// --------------------------------------------------------------
// --------------------------------------------------------------

#include <stdlib.h>
#include <math.h>

#include "synth_defs.h"
#include "sine.h"

// --------------------------------------------------------------
// internal funcs
// --------------------------------------------------------------

// --------------------------------------------------------------
// Exported functions
// --------------------------------------------------------------
void Sine_Init(sine_gen_t *pObj, synth_float_t fs)
{
	Sine_SetFS(pObj, fs);
	Sine_Prepare(pObj);
}	

void Sine_Free(sine_gen_t *pObj)
{
}

void Sine_SetFS(sine_gen_t *pObj, synth_float_t fs)
{
	pObj->fs = SINE_OVERSAMPLING*fs;
	pObj->pitch = -1;
}

void Sine_Reset(sine_gen_t *pObj, synth_float_t phase)
{
	pObj->y[0] = cos(2*jsy_pi*phase);
	pObj->y[1] = sin(2*jsy_pi*phase);
	pObj->fscale = 1;
}

void Sine_Start(sine_gen_t *pObj)
{
	pObj->pitch = -1;
	pObj->CV_fm = -1;
}

void Sine_Prepare(sine_gen_t *pObj)
{
	Sine_Reset(pObj, (synth_float_t)rand()/RAND_MAX);
}

void Sine_Update(sine_gen_t *pObj)
{
	synth_float_t freq;
	freq = pObj->fscale * pObj->pitch;
	pObj->b = 2.0 * sin(freq*jsy_pi / pObj->fs);
}

synth_float_t Sine_Process_Scalar(sine_gen_t *pObj, synth_float_t pitch, synth_float_t CV_fm)
{
	int i;

	synth_float_t a, phi;

	// ToDo: amplitude drift correction
	// y[0]^2 + y[1]^2 = a;

	if (pObj->CV_fm != CV_fm)
	{
		pObj->CV_fm = CV_fm;
		pObj->fscale = (synth_float_t)pow((synth_float_t)2, CV_fm);
		Sine_Update(pObj);
	}

	if (pObj->pitch != pitch)
	{
		pObj->pitch = pitch;
		Sine_Update(pObj);
	}

	for (i=0; i < SINE_OVERSAMPLING; i++)
	{
		pObj->y[0] = pObj->y[0] - pObj->b*pObj->y[1];
		pObj->y[1] = pObj->y[1] + pObj->b*pObj->y[0];
	}
	
	a = pObj->y[0]*pObj->y[0] + pObj->y[1]*pObj->y[1];
	if (fabs(a - 1) > 0.5)
	{
		phi = atan2(pObj->y[0], pObj->y[1]);
		pObj->y[0] = sin(phi);
		pObj->y[1] = cos(phi);
	}
	return -pObj->y[0];
}

