/*

This software module was originally developed by 

Luke Dahl, Brian Link, Rob Sussman, Alan Peevers (E-mu Systems)


in the course of development of the MPEG-4 Audio (ISO/IEC 14496-3) standard. 
This software module is an implementation of a part of one or more 
MPEG-4 Audio (ISO/IEC 14496-3) tools as specified by the MPEG-4 Audio 
(ISO/IEC 14496-3). ISO/IEC gives users of the MPEG-4 Audio (ISO/IEC 14496-3) 
free license to this software module or modifications thereof for use 
in hardware or software products claiming conformance to the MPEG-4 Audio 
(ISO/IEC 14496-3). Those intending to use this software module in hardware 
or software products are advised that its use may infringe existing patents. 
The original developer of this software module and his/her company, the 
subsequent editors and their companies, and ISO/IEC have no liability for 
use of this software module or modifications thereof in an implementation. 
Copyright is not released for non MPEG-4 Audio (ISO/IEC 14496-3) conforming 
products. E-mu Systems retains full right to use the code for his/her own 
purpose, assign or donate the code to a third party and to inhibit third 
parties from using the code for non MPEG-4 Audio (ISO/IEC 14496-3) 
conforming products. This copyright notice must be included in all copies 
or derivative works. 

Copyright (C) 1997 E-mu Systems, Inc.

*//*****************************************************************************
;
;	sf_synth.c
;
;	Audio processing for SF Synth.
;
;****************************************************************************/


#define PREINTERPOLATE /* needed to do preinterpolation -- this must come before including sf_wave_equ.h  */
#include "sf_wave_equ.h"
#include "sf_wave_def.h"
#include "sf_param_trans.h"
#include "sfe_enab.h"
#include "saol.h"

extern struct cmdinfo cmd;		/* to get SF bank name form cmd line */

#include <math.h>	/* so far used only in testing functions */

#define MAXSFBANKNAMECHARS 30	/* max number of characters in a sf bank name */
#define MAXEXPECTEDSFVOICES	4	/* maximum number of sf wavetable voices expected
									to be playing at once.  Used for normalizing mixer.*/
#define DEFAULT_PB_SENS	200	/* default pitchbend sensitivity in cents. */
#define PB_CONT_NUM		128	/* PitchBend is stored in midicc[][128] */

#define VOL7_CONT_NUM		7   /* Midi volume controller 7 -- this one isn't reset by reset all controllers */
#define VOL11_CONT_NUM		11  /* Midi volume controller 11 -- this one is reset by reset all controllers */

/* defines to control interpolation type */
#define LINEAR          0
#define FOURPT          1
#define INTERPOLATION   FOURPT 


void sf_bank_load(sa_decoder *sa, char *bankname, int banknum)
{

	sa->sfbanks[banknum].id = sfReadSFBFile(bankname);
	
	if (sa->sfbanks[banknum].id == -1)
	{
		runtime("ERROR: SF Bank did not load correctly.");
	}
	else
	{
		printf("SF Bank %d loaded. Reading samples.\n", banknum);
		sa->sfbanks[banknum].samples = sfGetAllSampleData(sa->sfbanks[banknum].id, 
												&sa->sfbanks[banknum].sampleSizeInBytes);
		if (sa->sfbanks[banknum].samples==NULL)
		{
			runtime("ERROR: Not able to load SF Bank Samples.");
		}
		else
		{
			printf("SF Bank %d Samples now loaded into system memory. (%lu bytes)\n", banknum,
									sa->sfbanks[banknum].sampleSizeInBytes);
		}
	}
}

double g05new4tap[G05NEW_TableLength] = {
  -3.4791101e-03,   -2.4414808e-03,   -3.3875546e-03, 
  -4.2115543e-03,   -5.3712577e-03,   -6.5614795e-03, 
  -7.9042940e-03,   -9.3386639e-03,   -1.0864589e-02, 
  -1.2390515e-02,   -1.3977477e-02,   -1.5503403e-02, 
  -1.6998810e-02,   -1.8341624e-02,   -1.9531846e-02, 
  -2.0447401e-02,   -2.1057772e-02,   -2.1271401e-02, 
  -2.0996735e-02,   -2.0203253e-02,   -1.8738365e-02, 
  -1.6541032e-02,   -1.3519700e-02,   -9.6438490e-03, 
  -4.7303690e-03,    1.2207404e-03,    8.3925901e-03, 
   1.6724143e-02,    2.6459548e-02,    3.7385174e-02, 
   5.0355541e-02,    6.3173315e-02,    8.3590197e-02, 
   9.8635823e-02,    1.1832026e-01,    1.3895077e-01, 
   1.6150395e-01,    1.8527787e-01,    2.1063875e-01, 
   2.3718986e-01,    2.6499222e-01,    2.9377117e-01, 
   3.2352672e-01,    3.5395367e-01,    3.8496048e-01, 
   4.1627247e-01,    4.4773705e-01,    4.7911008e-01, 
   5.1014740e-01,    5.4066591e-01,    5.7039094e-01, 
   5.9907834e-01,    6.2651448e-01,    6.5248573e-01, 
   6.7671743e-01,    6.9911802e-01,    7.1932127e-01, 
   7.3735771e-01,    7.5280007e-01,    7.6589251e-01, 
   7.7593310e-01,    7.8374584e-01,    7.8688925e-01, 
   7.9094821e-01,    7.8688925e-01,    7.8374584e-01, 
   7.7593310e-01,    7.6589251e-01,    7.5280007e-01, 
   7.3735771e-01,    7.1932127e-01,    6.9911802e-01, 
   6.7671743e-01,    6.5248573e-01,    6.2651448e-01, 
   5.9907834e-01,    5.7039094e-01,    5.4066591e-01, 
   5.1014740e-01,    4.7911008e-01,    4.4773705e-01, 
   4.1627247e-01,    3.8496048e-01,    3.5395367e-01, 
   3.2352672e-01,    2.9377117e-01,    2.6499222e-01, 
   2.3718986e-01,    2.1063875e-01,    1.8527787e-01, 
   1.6150395e-01,    1.3895077e-01,    1.1832026e-01, 
   9.8635823e-02,    8.3590197e-02,    6.3173315e-02, 
   5.0355541e-02,    3.7385174e-02,    2.6459548e-02, 
   1.6724143e-02,    8.3925901e-03,    1.2207404e-03, 
  -4.7303690e-03,   -9.6438490e-03,   -1.3519700e-02, 
  -1.6541032e-02,   -1.8738365e-02,   -2.0203253e-02, 
  -2.0996735e-02,   -2.1271401e-02,   -2.1057772e-02, 
  -2.0447401e-02,   -1.9531846e-02,   -1.8341624e-02, 
  -1.6998810e-02,   -1.5503403e-02,   -1.3977477e-02, 
  -1.2390515e-02,   -1.0864589e-02,   -9.3386639e-03, 
  -7.9042940e-03,   -6.5614795e-03,   -5.3712577e-03, 
  -4.2115543e-03,   -3.3875546e-03,   -2.4414808e-03, 
  -3.4791101e-03,    0.0000000e+00 };

#ifdef PREINTERPOLATE
void init_interp_table(void)
{
	int i, j, k, count=0;
	double fraction = PREINTER_Fraction;
	double *in = g05new4tap;
	double *out = PREINTERCoefTab;

	/*	printf("preinterpolating filter coefficients\n");  */

	for (i=0; i < G05NEW_FilterOrder; i++)
	{
		for (j=0; j < G05NEW_EntryPerTap; j++)
		{
			for (k=0; k < PREINTER_Ratio; k++)
			{
				if (i==0 && j==0)
				{
					*out = (1 - k*fraction)*0 + k*fraction*(*in);
					out++;
				}
				else
				{
					*out = (1 - k*fraction)*(*(in-1)) + k*fraction*(*in);
					out++;
				}
			} /* for k */
			in++;
		} /* for j */
	} /* for i */
}
#endif

void sf_synth_top(context *cx, double *Left, double *Right, double *Rev, double *Chor,
	long rate, double sfbanknum, double chan, double midibank, double midipreset,
	double midinote, double keyvel)
{
	static int SFPARAMINIT = FALSE;
	double	samp, pan, panR, panL;	
	sfData* arraysynthparams;
	sfData* currsynthparams; 
	WORD voicecnt;
	int framesz, i, j, vctostart, srate, krate, extendnote, sfbank;

	sfbank = (int)sfbanknum;
	srate = cx->sa->all->g->srate;
	krate = cx->sa->all->g->krate;

#ifdef PREINTERPOLATE
	if (!SFPARAMINIT)
	{
		SFPARAMINIT = TRUE;
		init_interp_table();
	}
#endif

	/* if this is a new note */
	if (rate == IVAR)
	{
		/* get sf params */
		arraysynthparams = sfNav(cx->sa->sfbanks[sfbank].id,(WORD)midibank,(WORD)midipreset,(WORD)midinote,(WORD)keyvel,&voicecnt);

		/* Allocate synthparam storage */	
		if(!(cx->sfstorage = (struct SynthParams *)calloc(voicecnt, sizeof(struct SynthParams))))
			interror("Couldn't allocate SynthParam space in sf_synth!!");
		cx->sfVoiceCnt = voicecnt;
		
		/* find voices and fill up cx->sfstorage */
		for (i = 0; i < (int)voicecnt; i++)
		{
			sf_init_sp(&(cx->sfstorage[i]));
			
			currsynthparams = &arraysynthparams[i];
			sf_xlat(currsynthparams, &cx->sa->sfbanks[sfbank], &(cx->sfstorage[i]), srate, krate);
			cx->sfstorage[i].Chan = chan;
			cx->sfstorage[i].Note = midinote;

			/* some parameter inits from StartVoice. Keep These. */
			cx->sfstorage[i].EnvMessage = ENV_START;
			cx->sfstorage[i].Lfo1.value = .5;
			cx->sfstorage[i].Lfo2.value = .5;
			cx->sfstorage[i].Lfo1.count = cx->sfstorage[i].Lfo1.delay;
			cx->sfstorage[i].Lfo2.count = cx->sfstorage[i].Lfo2.delay;
			cx->sfstorage[i].curSamp = cx->sfstorage[i].Start;
			cx->sfstorage[i].curFract = 0;
			if (cx->sfstorage[i].InstantAttack == TRUE)
				cx->sfstorage[i].Vol = pow(10., -cx->sfstorage[i].Attenuation/200.0);
		}
	}

	if (rate == KSIG)
	{	
		framesz = srate/krate;
		extendnote = 0;
		
		/* update synth params */
		for (i = 0;i < cx->sfVoiceCnt; i++)
		{
			if(cx->instr->turnoff_notified)
			{
				/* if any voices are still on */
				if(cx->sfstorage[i].VolEnv.state != OFF)
				{
					/* and not yet in release */
					if(cx->sfstorage[i].VolEnv.state != RELEASE)
					{
						cx->sfstorage[i].EnvMessage = ENV_STOP;
						extendnote = 1;		/* set flag to extend note */
					}
					else
					{
						extendnote = 1;
					}
				}
				
			}
			/* update envelopes and other synthparams */
			env_gen(cx, i, framesz);
		}
		if(extendnote)
		{
			instr_extend(cx,(double)2/krate);
		}
	}
	
	if (rate == ASIG)
	{		
		*Left = 0;
		*Right = 0;
		*Rev = 0;
		*Chor = 0;

		for (i = 0;i < cx->sfVoiceCnt; i++)
		{	
			if (cx->sfstorage[i].VolEnv.state != OFF)
			{
				sf_osc(cx->sfstorage, i, &samp); 	
				sf_lpf(cx->sfstorage, i, &samp); 

				/* increment Fc and Vol*/
				cx->sfstorage[i].FilterFc += cx->sfstorage[i].FilterFcInc;
				cx->sfstorage[i].Vol += cx->sfstorage[i].VolInc;

				/* Mix into four output samples */
				pan = cx->sa->midicc[cx->sfstorage[i].Chan][10];
				pan = (pan - 56)/56;
				panR = cx->sfstorage[i].RSend + pan;
				panR = (panR > 1)?1:panR;
				panR = (panR < 0)?0:panR;
				panL = cx->sfstorage[i].LSend - pan;
				panL = (panL > 1)?1:panL;
				panL = (panL < 0)?0:panL;
				*Left += panL * samp;
				*Right += panR * samp;
				*Rev += cx->sfstorage[i].RvbSend * samp;
				*Chor += cx->sfstorage[i].ChsSend * samp;
			}
		}
		/* Normalize to prevent overflow */
		*Left /= MAXEXPECTEDSFVOICES;
		*Right /= MAXEXPECTEDSFVOICES;
		*Rev /= MAXEXPECTEDSFVOICES;
		*Chor /= MAXEXPECTEDSFVOICES;
	}
}

/* Oscillator that does sample interpolation from sample table */
void sf_osc(struct SynthParams *sp, int voice, double *buf)
{
	int	intpart;
	double	samp1, samp2;
#if INTERPOLATION==FOURPT
	int	coeff_index, i;
	double  coeff[G05NEW_FilterOrder], *coeffptr, *sampleptr;
#endif

	if (sp[voice].VolEnv.state != OFF)
	{
		/*	Check for end of data */
		if (sp[voice].curSamp >= sp[voice].End)
		{
			sp[voice].VolEnv.state = OFF;
			sp[voice].VolEnv.value = 0;
			sp[voice].VolEnv.count = 0;
			sp[voice].Vol = 0;
		}

#if INTERPOLATION==LINEAR
		/*	Linear interpolation */
		samp1 = *(sp[voice].curSamp);
		samp2 = *(sp[voice].curSamp + 1);
		*buf = samp1 * (1 - sp[voice].curFract) + samp2 * sp[voice].curFract;
#elif INTERPOLATION==FOURPT

		coeffptr = coeff;

#ifdef PREINTERPOLATE
		coeff_index = (int)(sp[voice].curFract * PREINTER_EntryPerTap);
		coeff_index = PREINTER_EntryPerTap - coeff_index - 1;
		i = G05NEW_FilterOrder;
		while (i--)
		{
			*coeffptr++ = PREINTERCoefTab[coeff_index];
			coeff_index += PREINTER_EntryPerTap;
		}
#else /* !PREINTERPOLATE */
		coeff_index = (int)(sp[voice].curFract * G05NEW_EntryPerTap);
		coeff_index = G05NEW_EntryPerTap - coeff_index -1;	
		i = G05NEW_FilterOrder;
		while (i--)
		{
			*coeffptr++ = g05new4tap[coeff_index];
			coeff_index += G05NEW_EntryPerTap;
		}
#endif  /* !PREINTERPOLATE */

		coeffptr = coeff;
		sampleptr = sp[voice].curSamp;
		*buf = 0;
		i = G05NEW_FilterOrder;
		while (i--)
		{
			*buf += *coeffptr++ * *sampleptr++;
		}
#endif /* INTERPOLATION==FOURPT */
		
		/*	Apply volume */
		*buf *= sp[voice].Vol;
		
		/*	Pointer update */
		sp[voice].curFract += sp[voice].PhaseInc;
		intpart = (int) sp[voice].curFract;
		sp[voice].curSamp += intpart;
		sp[voice].curFract -= intpart;

		/* Check for end of loop if looping is enabled */
		if (sp[voice].SampleMode != LOOP_NONE) {
			/* Don't check for end of loop if key is up and mode is LOOP_HOLD */	
			if (!(sp[voice].SampleMode == LOOP_HOLD && sp[voice].VolEnv.state == RELEASE))
			if (sp[voice].curSamp >= sp[voice].Endloop)
			{
				sp[voice].curSamp -= (sp[voice].Endloop - sp[voice].Startloop);
			}
		}

		if (sp[voice].VolEnv.state != DELAY && sp[voice].VolEnv.state != ATTACK && 
			sp[voice].VolEnv.value < 1./65536)
		{							/* this ensures that decay does not last forever */
			sp[voice].VolEnv.state = OFF;	
			sp[voice].VolEnv.value = 0;
			sp[voice].VolEnv.count = 0;
			sp[voice].Vol = 0;
		}
	} /* (sp[voice].VolEnv.state != OFF) */
}

void sf_lpf(struct SynthParams *sp, int voice, double *samp)
{
	double Fc;
	double FilterQ;
	double Z1, Z2;
	int coef;
	int fc;
	int inscale;
	int b1, b2;
	double b1f, b2f;

	Fc = sp[voice].FilterFc;
	FilterQ = sp[voice].FilterQ;
	Z1 = sp[voice].FilterZ1;
	Z2 = sp[voice].FilterZ2;

	coef = FilterQ/12;		/* FilterQ is between 0 and 180 */
	fc = 65535*(Fc - 4622)/(11848-4622);
	/*fc   = Fc - 4622 + 65535*(Fc - 4622)/7226; /* Alan's new mapping */
	fc= (fc > 65535)?65535:fc;
	fc= (fc < 0)?0:fc;
			 
	b1=decodeB1(fc);	    /* computes b1d */
	b2=decodeB2(coef, fc);
	b1=b1-b2;				/* b1 = b1d-b2  */
    
	b1f = -(float)(1+ (0x3ffff-(b1 & 0x3ffff)))/65536.0f;   /* range: [0 -2] */
	b2f = (float)b2/65536.0f;				/* range: [0 1]  */
    
	inscale = ( 9 + (7-(coef&7)) ) << (coef<8);  /* filter input scale factor */
	
	b1f = -2 -b1f;			/* these are the 'normal' biquad parms */
	b2f = 1-b2f;
    	
        *samp=*samp * inscale * (1+b1f+b2f) - b1f*Z1 - b2f*Z2;
	Z2=Z1;					/* update the state */
	Z1=*samp;
#if 1
	*samp /= 32;			/* renormalize so flat filters have unity DC gain */
#endif
	
	sp[voice].FilterZ1=Z1;
	sp[voice].FilterZ2=Z2;
}

int decodeB2(int coef, int fc){
long b2e, b2dcd;
int b17, b16, b15, b14, b13, b12, b11;
int d14, d13, s13, s14;
    
    fc = fc+1;
    
    b2e=((fc & 0x1f800)+0x400)+(0x8000 + 0x800*(15-coef) + 0x400);
    
    b17=(b2e & 0x20000)>>1;
    b16=(b2e & 0x10000)>>16;
    b15=(b2e & 0x8000)>>15;
    b14=(b2e & 0x4000)>>14;
    b13=(b2e & 0x2000)>>13;
    b12=(b2e & 0x1000)>>12;
    b11=(b2e & 0x800)>>11;
    
    d14 = b16 & b15 & b14;
    d13 = b13 | !(b17 | (b16&b15&b14));
    s13 = b13 | (b16&b15&b14);
    s14 = b14 & !(b16&b15);
    
    b2dcd=((d14<<14) + (d13<<13) + (b12<<12) + (b11<<11) + (fc&0x7ff))*8;
    
    if (!b16)
	b2dcd = (b2dcd & 0x3ff00)>>8;
    if (!b15)
	b2dcd = (b2dcd & 0x3fff0)>>4;
    if (!s14)
	b2dcd = (b2dcd & 0x3fffc)>>2;
    if (!s13)
	b2dcd = (b2dcd & 0x3fffe)>>1;
	
    return(b17 + (b2dcd & 0xffff));
}

int decodeB1(int fc){
long b1e, b1d;
int r17, r16, r15, r14;
    
    b1e = 3*fc+2;

    b1d = 32*(0x3fff-(b1e & 0x3fff));

    r17=(b1e & 0x20000)>>17;
    r16=(b1e & 0x10000)>>16;
    r15=(b1e & 0x8000)>>15;
    r14=(b1e & 0x4000)>>14;
    
    if (!r17)
	b1d = (0xFE<<11) + ((b1d & 0x7ff00)>>8);
	
    if (!r16)
	b1d = (0x7<<16) + ((!r17)<<15) + ((b1d & 0x7fff0)>>4);
	
    if (!r15)
	b1d = (0x3<<17) + ((b1d & 0x7fffc)>>2);
	
    if (!r14)
	b1d = (0x1<<18) + ((b1d & 0x7fffe)>>1);
	
    return(0x30000+(b1d & 0xffff));
}


/* function updates envelopes and other synthparameters */
void env_gen(context *cx, int voice, int framesz)
{
	double VolTarget,  Gain, Atten, tempLfo1, tempLfo2;
	double PitchMod, FcMod, PitchBend;
	int ccVol7, ccVol11;	

	env_val(&(cx->sfstorage[voice].VolEnv), cx->sfstorage[voice].EnvMessage);

#ifdef DEBUG_BDL
if ((voice == 0) && (cx->sfstorage[voice].VolEnv.state != OFF))
printf("%g\n", cx->sfstorage[voice].VolEnv.value);
#endif

	if (cx->sfstorage[voice].VolEnv.state != OFF)
	{
		env_val(&(cx->sfstorage[voice].PitchEnv), cx->sfstorage[voice].EnvMessage);
		cx->sfstorage[voice].EnvMessage = ENV_NONE;
		lfo_val(&(cx->sfstorage[voice].Lfo1));
		lfo_val(&(cx->sfstorage[voice].Lfo2));

/*	Apply Tremolo */

		if (cx->sfstorage[voice].Lfo1.value < 0)   /* turn sawtooth into triangle */
			tempLfo1 = -cx->sfstorage[voice].Lfo1.value;
		else
			tempLfo1 = cx->sfstorage[voice].Lfo1.value;
		tempLfo1 = 2. * (tempLfo1 - .5);
/*	Compute Target Volume */

		ccVol7 = cx->sa->midicc[cx->sfstorage[voice].Chan][VOL7_CONT_NUM];
		ccVol11 = cx->sa->midicc[cx->sfstorage[voice].Chan][VOL11_CONT_NUM];

		if (ccVol7 == 0 || ccVol11 == 0) 
		{
			Gain = 0;
		}
		else {
			Atten = cx->sfstorage[voice].Attenuation - cx->sfstorage[voice].Tremolo * tempLfo1 - 
				400.0 * log10(ccVol7 / 127.0) - 400.0 * log10(ccVol11 / 127.0) ;

			if (Atten < 0)
				Atten = 0;
		
			Gain = pow(10.0, -Atten/200.0);
		}

		VolTarget = Gain * cx->sfstorage[voice].VolEnv.value;

		if (VolTarget > 1.0)
			VolTarget = 1.0;		
		cx->sfstorage[voice].VolInc = (VolTarget - cx->sfstorage[voice].Vol) / framesz;

/*	Compute Phase Increment */

		if (cx->sfstorage[voice].Lfo2.value < 0)   /* turn sawtooth into triangle */
			tempLfo2 = -cx->sfstorage[voice].Lfo2.value;
		else
			tempLfo2 = cx->sfstorage[voice].Lfo2.value;
		tempLfo2 = 2. * (tempLfo2 - .5);

		PitchBend = cx->sa->midicc[cx->sfstorage[voice].Chan][PB_CONT_NUM];
		PitchBend = (PitchBend - 8192)/8192;

		PitchMod = cx->sfstorage[voice].PitchEnvToPitch * cx->sfstorage[voice].PitchEnv.value + 
					cx->sfstorage[voice].Lfo1ToPitch * tempLfo1 + 
					cx->sfstorage[voice].Lfo2ToPitch * tempLfo2 +
					PitchBend * DEFAULT_PB_SENS;
#if 0
		printf("PitchMod\n");
		printf("\tPitchBend: %f\n", PitchBend);
#endif

		cx->sfstorage[voice].PhaseInc = CalcPhaseInc(cx->sfstorage[voice].InitPitch + PitchMod);

/*  Compute Fc Increment */

		FcMod = cx->sfstorage[voice].PitchEnvToFilterFc * cx->sfstorage[voice].PitchEnv.value +
				cx->sfstorage[voice].Lfo1ToFilterFc * tempLfo1;
		cx->sfstorage[voice].FilterFcInc = (cx->sfstorage[voice].InitFilterFc + FcMod - cx->sfstorage[voice].FilterFc)/framesz;

	} /* !(cx->sfstorage[voice].VolEnv.state != OFF) */
	else
	{
		cx->sfstorage[voice].VolInc = 0;
	}
}

void lfo_val(struct Lfo *l)
{
/* 2/freq gives the duration of one period since this sawtooth gets converted */
/* to triangle waveform. */
	if (l->count > 0)
	{
		l->count--;
	}
	else
	{
		l->value += l->freq;
		if (l->value >=1.0)
			l->value -= 2.0;
	}
}

void env_val(struct Env *e, EnvMessageType msg)
{

/*	Act on message */

	switch(msg)
	{
		case ENV_NONE:
			break;
			
		case ENV_START:			/* assumes start will not be sent for channel */
			e->state = DELAY;	/* that is still on */
			e->count = e->delay;
			break;
			
		case ENV_STOP:			/* note-off */
			e->state = RELEASE;
			e->count = 0;
			break;
		
		case ENV_ABORT:			/* rip-off */
			e->state = RELEASE;
			e->value = 0;
			e->count = 0;
			return;
			
		default:
			printf("ERROR: env_val: illegal envelope message %d\n", msg);
			exit(1);
			break;
	}
	
/*	Determine which state to use */

	switch(e->state)
	{
		case OFF:
			break;

		case DELAY:
			if (e->count == 0)
			{
				e->state = ATTACK;
			}
			else
				break;

		case ATTACK:
			if (e->attack + e->value >= 1.0)
			{
				e->state = HOLD;
				e->value = 1.0;
				e->count = e->hold;
			}
			else
				break;

		case HOLD:
			if (e->count == 0)
			{
				e->state = DECAY;
			}
			else
				break;

		case DECAY:
			if (e->decay * e->value <= e->sustain)
			{
				e->state = SUSTAIN;
				e->value = e->sustain;
			}
			else
				break;

		case SUSTAIN:
			if (msg == ENV_STOP)
			{
				e->state = RELEASE;
			}
			else
				break;

		case RELEASE:
			break;

		default:
			printf("ERROR: env_val: illegal envelope state\n");
			exit(1);
			break;
	}

/*	Act on current state */

	switch(e->state)
	{
		case OFF:				/* value and count zeroed already */
			break;

		case DELAY:				/* value already zero */
			e->count--;
			break;

		case ATTACK:
			e->value += e->attack;	/* linear attack */
			break;

		case HOLD:				/* value remains 1.0 */
			e->count--;
			break;

		case DECAY:
			e->value *= e->decay;	/* exponential decay */
			break;

		case SUSTAIN:				/* value remains constant */
			break;

		case RELEASE:
			e->value *= e->release;	/* exponential release */
			break;

		default:
			printf("ERROR: env_val: illegal envelope state\n");
			exit(1);
			break;
	}
}


void sf_init_sp(struct SynthParams *p)
{
	p->Start = NULL;
	p->End = NULL;
	p->Startloop = NULL;
	p->Endloop = NULL;

	p->curSamp = NULL;
	p->curFract = 0;
	p->InitPitch = 0;
	p->PhaseInc = 0;
	p->PitchEnvToPitch = 0;
	p->Lfo1ToPitch = 0;
	p->Lfo2ToPitch = 0;
	p->SFLfo1ToPitchVal = 0;
	p->SFLfo2ToPitchVal = 0;

	sf_init_env(&(p->PitchEnv));
	sf_init_env(&(p->VolEnv));
	sf_init_lfo(&(p->Lfo1));
	sf_init_lfo(&(p->Lfo2));

	p->EnvMessage = ENV_NONE;
	p->SFVolValue = 0;
	p->InstantAttack = 0;
	p->Vol = 0;
	p->VolInc = 0;
	p->Tremolo = 0;
	p->Attenuation = 0;

	p->InitFilterFc = 0;
	p->FilterFc = 0;
	p->FilterFcInc = 0;
	p->FilterQ = 0;
	p->Lfo1ToFilterFc = 0;
	p->PitchEnvToFilterFc = 0;
	p->FilterZ1 = 0;
	p->FilterZ2 = 0;

	p->SFPanValue = 0;
	p->LSend = 0;
	p->RSend = 0;
	p->RvbSend = 0;
	p->ChsSend = 0;
	
	p->Chan = -1;
	p->Note = -1;
	p->InSustain = 0;
	p->Pending = 0;
}

void sf_init_env(struct Env *e)
{
	e->state = OFF;
	e->value = 0;
	e->count = 0;
	e->delay = 0;
	e->attack = 0;
	e->hold = 0;
	e->decay = 0;
	e->sustain = 0;
	e->release = 0;
}

void sf_init_lfo(struct Lfo *l)
{
	l->value = 0.5;		/* -1 to 1 saw is mapped into 0 to 1 tri so .5 -> 0 */
	l->count = 0;
	l->freq = 0;
	l->delay = 0;
}


