//uncomment if you need an FM oscillator
#define FM_OSCILLATOR

#include <stdio.h>
#include <iostream>

/*
  members are:

  float phase;
  int TableSize;
  float sampleRate;

  float *table, dtable0, dtable1, dtable2, dtable3;

  ->these should be filled as folows... (remember to wrap around!!!)
  table[i] = the wave-shape
  dtable0[i] = table[i+1] - table[i];
  dtable1[i] = (3.f*(table[i]-table[i+1])-table[i-1]+table[i+2])/2.f
  dtable2[i] = 2.f*table[i+1]+table[i-1]-(5.f*table[i]+table[i+2])/2.f
  dtable3[i] = (table[i+1]-table[i-1])/2.f
*/
#include "Oscillator.h"
#include <math.h>

#define PI 3.141592f
#define FM_OSCILLATOR

Oscillator::Oscillator(int tableSize) :
	phase(0),
	sampleRate(44100),
	TableSize(tableSize)
{
	initTable();
}

void Oscillator::initTable()
{
	int i = 0;
	
	int tableSize = this->TableSize;

	table   = new float[TableSize];
	dtable0 = new float[TableSize];
	dtable1 = new float[TableSize];
	dtable2 = new float[TableSize];
	dtable3 = new float[TableSize];
	
	printf("%d\n", TableSize);

	// Make sin table
	for(i = 0; i < TableSize; i++) {
		table[i] = (float) sin(i/(float)TableSize*PI*2);
	}
	
	// i = 0
	dtable0[i] = table[1] - table[0];
	dtable1[i] = (3.f*(table[0]-table[1])-table[tableSize-1]+table[2])/2.f;
	dtable2[i] = 2.f*table[1]+table[tableSize-1]-(5.f*table[0]+table[2])/2.f;
	dtable3[i] = (table[1]-table[tableSize-1])/2.f;

	for(i = 1; i < tableSize-2; i++) {
		dtable0[i] = table[i+1] - table[i];
		dtable1[i] = (3.f*(table[i]-table[i+1])-table[i-1]+table[i+2])/2.f;
		dtable2[i] = 2.f*table[i+1]+table[i-1]-(5.f*table[i]+table[i+2])/2.f;
		dtable3[i] = (table[i+1]-table[i-1])/2.f;
#if 0
		printf("%f\n", dtable0[i]);
		printf("%f\n", dtable1[i]);
		printf("%f\n", dtable2[i]);
		printf("%f\n", dtable3[i]);
#endif
	}

	// i = tableSize-2
	i = tableSize - 2;
	dtable0[i] = table[i+1] - table[i];
	dtable1[i] = (3.f*(table[i]-table[i+1])-table[i-1]+table[0])/2.f;
	dtable2[i] = 2.f*table[i+1]+table[i-1]-(5.f*table[i]+table[0])/2.f;
	dtable3[i] = (table[i+1]-table[i-1])/2.f;
	
	// i = tableSize-1
	i = tableSize - 1;
	dtable0[i] = table[0] - table[tableSize-1];
	dtable1[i] = (3.f*(table[tableSize-1]-table[0])-table[i-1]+table[1])/2.f;
	dtable2[i] = 2.f*table[0]+table[i-1]-(5.f*table[i]+table[1])/2.f;
	dtable3[i] = (table[0]-table[i-1])/2.f;
}

float Oscillator::UpdateWithoutInterpolation(float frequency)
{
	int i = (int) phase;
  
	phase += (sampleRate/(float)TableSize/frequency);
	    
	if(phase >= (float)TableSize)
		phase -= (float)TableSize;

#ifdef FM_OSCILLATOR
	if(phase < 0.f)
		phase += (float)TableSize;
#endif
	    
	return table[i] ;
}

float Oscillator::UpdateWithLinearInterpolation(float frequency)
{
	int i = (int) phase;
	float alpha = phase - (float) i;
  
	phase += (sampleRate/(float)TableSize)/frequency;
	
	if(phase >= (float)TableSize)
		phase -= (float)TableSize;

#ifdef FM_OSCILLATOR
	if(phase < 0.f)
		phase += (float)TableSize;
#endif

	/*
	  dtable0[i] = table[i+1] - table[i]; //remember to wrap around!!!
	*/
	
	return table[i] + dtable0[i]*alpha;
}

float Oscillator::UpdateWithCubicInterpolation( float frequency )
{
	int i = (int) phase;
	float alpha = phase - (float) i;

	phase += (sampleRate/(float)TableSize)/frequency;

	if(phase >= (float)TableSize)
		phase -= (float)TableSize;

#ifdef FM_OSCILLATOR
	if(phase < 0.f)
		phase += (float)TableSize;
#endif

	/* //remember to wrap around!!!
	   dtable1[i] = (3.f*(table[i]-table[i+1])-table[i-1]+table[i+2])/2.f
	   dtable2[i] = 2.f*table[i+1]+table[i-1]-(5.f*table[i]+table[i+2])/2.f
	   dtable3[i] = (table[i+1]-table[i-1])/2.f
	*/

	return ((dtable1[i]*alpha + dtable2[i])*alpha + dtable3[i])*alpha+table[i];
}


