/**
 ** Supermodel
 ** A Sega Model 3 Arcade Emulator.
 ** Copyright 2011 Bart Trzynadlowski, Nik Henson
 **
 ** This file is part of Supermodel.
 **
 ** Supermodel 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 3 of the License, or (at your option)
 ** any later version.
 **
 ** Supermodel 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 Supermodel.  If not, see <http://www.gnu.org/licenses/>.
 **/
 
/*
 * SCSPLFO.cpp
 * 
 * SCSP low frequency oscillator emulation. Included directly into SCSP.cpp. Do
 * not compile this!
 */

#include <cmath>
#include <cstdlib>

#define LFO_SHIFT 	8

struct _LFO
{
	unsigned short phase;
	UINT32 phase_step;
	int *table;
	int *scale;
};

#define LFIX(v)	((unsigned int) ((float) (1<<LFO_SHIFT)*(v)))

//Convert DB to multiply amplitude
#define DB(v) 	LFIX(pow(10.0,v/20.0))

//Convert cents to step increment
#define CENTS(v) LFIX(pow(2.0,v/1200.0))

static int PLFO_TRI[256], PLFO_SQR[256], PLFO_SAW[256], PLFO_NOI[256];
static int ALFO_TRI[256], ALFO_SQR[256], ALFO_SAW[256], ALFO_NOI[256];
static float LFOFreq[32] = { 0.17f, 0.19f, 0.23f, 0.27f, 0.34f, 0.39f, 0.45f, 0.55f, 0.68f, 0.78f, 0.92f, 1.10f, 1.39f, 1.60f, 1.87f, 2.27f,
			  2.87f, 3.31f, 3.92f, 4.79f, 6.15f, 7.18f, 8.60f, 10.8f, 14.4f, 17.2f, 21.5f, 28.7f, 43.1f, 57.4f, 86.1f, 172.3f };
static float ASCALE[8] = { 0.0f, 0.4f, 0.8f, 1.5f, 3.0f, 6.0f, 12.0f, 24.0f };
static float PSCALE[8] = { 0.0f, 7.0f, 13.5f, 27.0f, 55.0f, 112.0f, 230.0f, 494.0f };
static int PSCALES[8][256];
static int ASCALES[8][256];

void LFO_Init(void)
{
	int i, s;
	for (i = 0; i < 256; ++i)
	{
		int a, p;
		//		float TL;
				//Saw
		a = 255 - i;
		if (i < 128)
			p = i;
		else
			p = i - 256;
		ALFO_SAW[i] = a;
		PLFO_SAW[i] = p;

		//Square
		if (i < 128)
		{
			a = 255;
			p = 127;
		}
		else
		{
			a = 0;
			p = -128;
		}
		ALFO_SQR[i] = a;
		PLFO_SQR[i] = p;

		//Tri
		if (i < 128)
			a = 255 - (i * 2);
		else
			a = (i * 2) - 256;
		if (i < 64)
			p = i * 2;
		else if (i < 128)
			p = 255 - i * 2;
		else if (i < 192)
			p = 256 - i * 2;
		else
			p = i * 2 - 511;
		ALFO_TRI[i] = a;
		PLFO_TRI[i] = p;

		//noise
		//a=lfo_noise[i];
		a = rand() & 0xff;
		p = 128 - a;
		ALFO_NOI[i] = a;
		PLFO_NOI[i] = p;
	}

	for (s = 0; s < 8; ++s)
	{
		float limit = PSCALE[s];
		for (i = -128; i < 128; ++i)
		{
			PSCALES[s][i + 128] = CENTS(((limit*(float)i) / 128.0));
		}
		limit = -ASCALE[s];
		for (i = 0; i < 256; ++i)
		{
			ASCALES[s][i] = DB(((limit*(float)i) / 256.0));
		}
	}
}

signed int inline PLFO_Step(struct _LFO *LFO)
{
	int p;
	LFO->phase += LFO->phase_step;
#if LFO_SHIFT!=8    
	LFO->phase &= (1 << (LFO_SHIFT + 8)) - 1;
#endif    
	p = LFO->table[LFO->phase >> LFO_SHIFT];
	p = LFO->scale[p + 128];
	return p << (SHIFT - LFO_SHIFT);
}

signed int inline ALFO_Step(struct _LFO *LFO)
{
	int p;
	LFO->phase += LFO->phase_step;
#if LFO_SHIFT!=8    
	LFO->phase &= (1 << (LFO_SHIFT + 8)) - 1;
#endif    
	p = LFO->table[LFO->phase >> LFO_SHIFT];
	p = LFO->scale[p];
	return p << (SHIFT - LFO_SHIFT);
}

void LFO_ComputeStep(struct _LFO *LFO, UINT32 LFOF, UINT32 LFOWS, UINT32 LFOS, int ALFO)
{
	float step = (float)LFOFreq[LFOF] * 256.0f / (float)44100.0f;
	LFO->phase_step = (unsigned int)((float)(1 << LFO_SHIFT)*step);
	if (ALFO)
	{
		switch (LFOWS)
		{
		case 0: LFO->table = ALFO_SAW; break;
		case 1: LFO->table = ALFO_SQR; break;
		case 2: LFO->table = ALFO_TRI; break;
		case 3: LFO->table = ALFO_NOI; break;
		}
		LFO->scale = ASCALES[LFOS];
	}
	else
	{
		switch (LFOWS)
		{
		case 0: LFO->table = PLFO_SAW; break;
		case 1: LFO->table = PLFO_SQR; break;
		case 2: LFO->table = PLFO_TRI; break;
		case 3: LFO->table = PLFO_NOI; break;
		}
		LFO->scale = PSCALES[LFOS];
	}
}