/*
    SuperCollider real time audio synthesis system
    Copyright (c) 2002 James McCartney. All rights reserved.
    http://www.audiosynth.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <TargetConditionals.h>

#if defined(SC_IPHONE) && !TARGET_IPHONE_SIMULATOR

#    import <UIKit/UIKit.h>

#    include "SC_PlugIn.h"

/*
#if TARGET_IPHONE_SIMULATOR
const double pi = 3.14f;
#endif
*/

static InterfaceTable* ft;

@interface AccelerometerDelegate : NSObject <UIAccelerometerDelegate> {
    UIAccelerationValue accel_x, accel_y, accel_z;
}
- (float)accel_x;
- (float)accel_y;
- (float)accel_z;
@end

static AccelerometerDelegate* delegate = 0;


struct AccelerometerUGen : public Unit {
    float m_y1, m_b1, m_lag;
};

//////////////////////////////////////////////////////////////////////////////////////////////////

extern "C" {
void load(InterfaceTable* inTable);

void AccelerometerX_next(AccelerometerUGen* unit, int inNumSamples);
void AccelerometerY_next(AccelerometerUGen* unit, int inNumSamples);
void AccelerometerZ_next(AccelerometerUGen* unit, int inNumSamples);

void AccelerometerX_Ctor(AccelerometerUGen* unit);
void AccelerometerY_Ctor(AccelerometerUGen* unit);
void AccelerometerZ_Ctor(AccelerometerUGen* unit);
};

//////////////////////////////////////////////////////////////////////////////////////////////////

void AccelerometerX_next(AccelerometerUGen* unit, int inNumSamples) {
    // minval, maxval, warp, lag

    float minval = ZIN0(0);
    float maxval = ZIN0(1);
    float warp = ZIN0(2);
    float lag = ZIN0(3);

    float y1 = unit->m_y1;
    float b1 = unit->m_b1;

    if (lag != unit->m_lag) {
        unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate));
        unit->m_lag = lag;
    }
    float y0 = ([delegate accel_x] + 1.0f) * 0.5f;
    if (warp == 0.0) {
        y0 = (maxval - minval) * y0 + minval;
    } else {
        y0 = pow(maxval / minval, y0) * minval;
    }
    ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
    unit->m_y1 = zapgremlins(y1);
}

void AccelerometerX_Ctor(AccelerometerUGen* unit) {
    SETCALC(AccelerometerX_next);
    unit->m_b1 = 0.f;
    unit->m_lag = 0.f;
    AccelerometerX_next(unit, 1);
}


void AccelerometerY_next(AccelerometerUGen* unit, int inNumSamples) {
    // minval, maxval, warp, lag

    float minval = ZIN0(0);
    float maxval = ZIN0(1);
    float warp = ZIN0(2);
    float lag = ZIN0(3);

    float y1 = unit->m_y1;
    float b1 = unit->m_b1;

    if (lag != unit->m_lag) {
        unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate));
        unit->m_lag = lag;
    }
    float y0 = ([delegate accel_y] + 1.0f) * 0.5f;
    if (warp == 0.0) {
        y0 = (maxval - minval) * y0 + minval;
    } else {
        y0 = pow(maxval / minval, y0) * minval;
    }
    ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
    unit->m_y1 = zapgremlins(y1);
}

void AccelerometerY_Ctor(AccelerometerUGen* unit) {
    SETCALC(AccelerometerY_next);
    unit->m_b1 = 0.f;
    unit->m_lag = 0.f;
    AccelerometerY_next(unit, 1);
}

void AccelerometerZ_next(AccelerometerUGen* unit, int inNumSamples) {
    // minval, maxval, warp, lag

    float minval = ZIN0(0);
    float maxval = ZIN0(1);
    float warp = ZIN0(2);
    float lag = ZIN0(3);

    float y1 = unit->m_y1;
    float b1 = unit->m_b1;

    if (lag != unit->m_lag) {
        unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate));
        unit->m_lag = lag;
    }
    float y0 = ([delegate accel_z] + 1.0f) * 0.5f;
    if (warp == 0.0) {
        y0 = (maxval - minval) * y0 + minval;
    } else {
        y0 = pow(maxval / minval, y0) * minval;
    }
    ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
    unit->m_y1 = zapgremlins(y1);
}

void AccelerometerZ_Ctor(AccelerometerUGen* unit) {
    SETCALC(AccelerometerZ_next);
    unit->m_b1 = 0.f;
    unit->m_lag = 0.f;
    AccelerometerZ_next(unit, 1);
}

@implementation AccelerometerDelegate

- (id)init {
    if (self = [super init]) {}
    return self;
}

- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration {
    accel_x = acceleration.x;
    accel_y = acceleration.y;
    accel_z = acceleration.z;

    /*
        accel_x += ([acceleration x] - accel_x)*0.8f;
        accel_y += ([acceleration y] - accel_y)*0.8f;
        accel_z += ([acceleration z] - accel_z)*0.8f;
    */
}

- (float)accel_x {
    return (float)accel_x;
}

- (float)accel_y {
    return (float)accel_y;
}

- (float)accel_z {
    return (float)accel_z;
}

@end

PluginLoad(iPhone) {
    ft = inTable;

    delegate = [[AccelerometerDelegate alloc] init];
    UIAccelerometer* accel = [UIAccelerometer sharedAccelerometer];
    [accel setUpdateInterval:0.01f];
    [accel setDelegate:delegate];
    DefineUnit("AccelerometerX", sizeof(AccelerometerUGen), (UnitCtorFunc)&AccelerometerX_Ctor, 0, 0);
    DefineUnit("AccelerometerY", sizeof(AccelerometerUGen), (UnitCtorFunc)&AccelerometerY_Ctor, 0, 0);
    DefineUnit("AccelerometerZ", sizeof(AccelerometerUGen), (UnitCtorFunc)&AccelerometerZ_Ctor, 0, 0);
}

#endif
