/*-----------------------------------------------------------------------------

� 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved

-----------------------------------------------------------------------------*/

#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include "iir.h"
#include "filter.hpp"
#include "paramutils.h"

#define NUM_PARMS	7
#define MAX_ORDER	10
#define MAX_TYPES	4
#define MAX_Q		10.0f
#define ALPHA		0.2f
#define BETA		(1.0f-ALPHA)

const char * const pFTypeString[8] =
{
	"Unknown",
	"Lowpass",
	"Highpass",
    "Bandpass",
	"Bandstop",
	"Peaking",
	"Low-Shelving",
	"High-Shelving"
};

enum {ORDER, TYPE, FMIN, FMAX, FG, Q, TESTPARAM};
char *pParmStr[NUM_PARMS] = {"Order","Filter-Type","Freq min","Freq max","Frequency","Resonance","Test-Param"};

AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
{
	return new Filter (audioMaster);
}

//-----------------------------------------------------------------------------
Filter::Filter(audioMasterCallback audioMaster)
	: AudioEffectX(audioMaster, 1, NUM_PARMS)	// 1 program, 1 parameter only
{
	sampleRate = 48000;
	fg = 1000/sampleRate;	// default to 1000 Hz
	order = 4;
	q = 1.0f/MAX_Q;
	type = IIR_FILTERTYPE_LOWPASS;
	setNumInputs(2);		// stereo in
	setNumOutputs(2);		// stereo out
	setUniqueID('Filt');	// identify
//	canMono();				// makes sense to feed both inputs with the same signal
	canProcessReplacing();	// supports both accumulating and replacing output
	strcpy(programName, "Default");	// default program name
	IIRInit(filterCoeff_L, order);
	IIRInit(filterCoeff_R, order);
	sm_fg = fg;
	sm_q = q;
	testParam=0;

	IIRCalcFilterCoeff(filterCoeff_L, sampleRate, sm_fg*sampleRate, sm_q, order, type);
	IIRCalcFilterCoeff(filterCoeff_R, sampleRate, sm_fg*sampleRate, sm_q, order, type);
	forder = (0.5f/MAX_ORDER)*(float)(order -1);
	ftype = (1.0f/MAX_TYPES)*(float)(type -1);
	f_fmin = 0;
	f_fmax = 17300.f/sampleRate;
}

//-----------------------------------------------------------------------------------------
Filter::~Filter()
{
	// nothing to do here
}

//-----------------------------------------------------------------------------------------
void Filter::setProgramName(char *name)
{
	strcpy(programName, name);
}

//-----------------------------------------------------------------------------------------
void Filter::getProgramName(char *name)
{
	strcpy(name, programName);
}

//-----------------------------------------------------------------------------------------
void Filter::setParameter(VstInt32 index, float value)
{
	fg = f_fmin + value*(f_fmax-f_fmin);


	switch(index)
	{
	case TYPE:

		ftype = ParamQuantize(value,1.0f/(MAX_TYPES-1));
		
		type = 1 + (VstInt32)(ftype*(MAX_TYPES-1));
		IIRCalcFilterCoeff(filterCoeff_L, sampleRate, 0.5f*fg*sampleRate, q*MAX_Q, order, type);
		IIRCalcFilterCoeff(filterCoeff_R, sampleRate, 0.5f*fg*sampleRate, q*MAX_Q, order, type);
		break;

	case ORDER:
		forder = ParamQuantize(value,1.0f/(MAX_ORDER/2-1));
		order = 2*(VstInt32)(1+forder*MAX_ORDER/2);
		sprintf(dbgStr, "value = %f, forder = %f, order = %d",value,forder,order);
//		OutputDebugString(dbgStr);
		IIRCalcFilterCoeff(filterCoeff_L, sampleRate, 0.5f*fg*sampleRate, q*MAX_Q, order, type);
		IIRCalcFilterCoeff(filterCoeff_R, sampleRate, 0.5f*fg*sampleRate, q*MAX_Q, order, type);
		break;

	case FMIN:
		f_fmin = value;
		break;

	case FMAX:
		f_fmax = value;
		break;

	case FG:
		f_fg_param = value;
		break;

	case Q:
		q = value;
		break;

	case TESTPARAM:
		testParam=ParamQuantize(value,1.0f/3);
		sprintf(dbgStr, "Set Param: %f",value);
//		OutputDebugString(dbgStr);
		break;
	}

}

//-----------------------------------------------------------------------------------------
float Filter::getParameter(VstInt32 index)
{
	float value = 0;
	
	switch(index)
	{
	case TYPE:
		value = (float)ftype;
		break;

	case ORDER:
		value = (float)forder;
		break;

	case FMIN:
		value = f_fmin;
		break;

	case FMAX:
		value = f_fmin;
		break;

	case FG:
		value = f_fg_param;
		break;

	case Q:
		value = q;
		break;

	case TESTPARAM:
		value = testParam;
		sprintf(dbgStr, "Get Param: %f",value);
//		OutputDebugString(dbgStr);
		break;
	}
	return value;
}

//-----------------------------------------------------------------------------------------
void Filter::getParameterName(VstInt32 index, char *label)
{
	strcpy(label,pParmStr[index]);
}

//-----------------------------------------------------------------------------------------
void Filter::getParameterDisplay(VstInt32 index, char *text)
{

	switch(index)
	{
	case TYPE:
		strcpy(text, pFTypeString[type]);
		break;
	case ORDER:
		snprintf(text, kVstMaxParamStrLen, "%d", order);
		break;
	case FMIN:
		float2string(0.5f*f_fmin*sampleRate,text, kVstMaxParamStrLen);
		break;
	case FMAX:
		float2string(0.5f*f_fmax*sampleRate,text, kVstMaxParamStrLen);
		break;
	case FG:
		float2string(0.5f*fg*sampleRate,text, kVstMaxParamStrLen);
		break;
	case Q:
		float2string(q*MAX_Q,text, kVstMaxParamStrLen);
		break;
	case TESTPARAM:
		float2string(testParam,text, kVstMaxParamStrLen);
		break;

	}
}

//-----------------------------------------------------------------------------------------
void Filter::getParameterLabel(VstInt32 index, char *label)
{
	switch(index)
	{
	case TYPE:
		strcpy(label, "           ");
		break;
	case ORDER:
		strcpy(label, "           ");
		break;
	case FMIN:
		strcpy(label, "     Hz    ");
		break;
	case FMAX:
		strcpy(label, "     Hz    ");
		break;
	case FG:
		strcpy(label, "     Hz    ");
		break;
	case Q:
		strcpy(label, "           ");
		break;
	case TESTPARAM:
		strcpy(label, "    Test   ");
		break;
	}
}

//-----------------------------------------------------------------------------------------
void Filter::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames)
{
    float *in1  =  inputs[0];
    float *in2  =  inputs[1];
    float *out1 = outputs[0];
    float *out2 = outputs[1];

	sm_fg = BETA*sm_fg+ALPHA*fg;
	sm_q = BETA*sm_q+ALPHA*q*MAX_Q;

	IIRCalcFilterCoeff(filterCoeff_L, sampleRate, 0.5f*sm_fg*sampleRate, sm_q, order, type);
	IIRCalcFilterCoeff(filterCoeff_R, sampleRate, 0.5f*sm_fg*sampleRate, sm_q, order, type);

	IIR(filterCoeff_L, in1, out1, order, sampleFrames);
	IIR(filterCoeff_R, in2, out2, order, sampleFrames);
}

//-----------------------------------------------------------------------------------------
void Filter::setSampleRate(float sampleRate)
{
	this->sampleRate = sampleRate;
	sprintf(dbgStr, "Sample Rate = %f",sampleRate);
//	OutputDebugString(dbgStr);
}

//-----------------------------------------------------------------------------------------
void Filter::setBlockSize(VstInt32 blockSize)
{
	this->blockSize = blockSize;
	sprintf(dbgStr, "Block Size = %d",blockSize);
//	OutputDebugString(dbgStr);
}
