/* WaveTableOscControl.c */
/*****************************************************************************/
/*                                                                           */
/*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
/*    Copyright (C) 1994  Thomas R. Lawrence                                 */
/*                                                                           */
/*    This program 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 2 of the License, or      */
/*    (at your option) any later version.                                    */
/*                                                                           */
/*    This program 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 this program; if not, write to the Free Software            */
/*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
/*                                                                           */
/*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
/*                                                                           */
/*****************************************************************************/

#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"

#include "WaveTableOscControl.h"
#include "FastFixedPoint.h"
#include "Memory.h"
#include "EnvelopeState.h"
#include "SampleConsts.h"
#include "LFOGenerator.h"
#include "Multisampler.h"
#include "OscillatorSpecifier.h"
#include "Envelope.h"
#include "LFOListSpecifier.h"
#include "64BitMath.h"
#include "ErrorDaemon.h"
#include "OscEffectGenerator.h"
#include "EffectSpecList.h"


/* prototypes for fast playback routines */
static void						Wave_Mono_8BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Stereo_8BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Mono_16BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Stereo_16BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);

static void						Wave_Mono_8BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Stereo_8BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Mono_16BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Stereo_16BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);

static void						Wave_Mono_8BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Stereo_8BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Mono_16BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Wave_Stereo_16BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);

static void						Wave_NoOutput(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);


/* wave table oscillator template information record */
struct WaveTableTemplateRec
	{
		/* source information for the wave table */
		MultiSampleRec*				WaveTableSourceSelector;

		/* sampling rate for final output */
		long									FinalOutputSamplingRate;
		/* number of envelope updates per second */
		float									EnvelopeTicksPerSecond;

		/* values for scaling the frequency of something.  if we were really serious about */
		/* this, we'd traverse all of the oscillators with integral multiples or harmonic */
		/* fractions of the pitch & set their differentials to the same precision as the */
		/* worst oscillator so that they would all stay in sync as time progressed. */
		float									FrequencyMultiplier;
		/* this is added after the frequency multiplier is applied */
		float									FrequencyAdder;

		/* stereo status */
		NumChannelsType				StereoPlayback;
		/* time interpolation flag */
		MyBoolean							InterpolateThroughTime;
		/* inter-wave interpolation flag */
		MyBoolean							InterpolateAcrossWaves;

		/* envelope templates */
		EnvelopeRec*					LoudnessEnvelopeTemplate;
		LFOListSpecRec*				LoudnessLFOTemplate;
		EnvelopeRec*					IndexEnvelopeTemplate;
		LFOListSpecRec*				IndexLFOTemplate;

		/* miscellaneous control parameters */
		float									StereoBias;
		float									TimeDisplacement;
		float									OverallOscillatorLoudness;

		/* error logging facility */
		ErrorDaemonRec*				ErrorDaemon;

		/* template for the pitch displacement LFO */
		LFOListSpecRec*				PitchLFOTemplate;

		/* effect specifier, may be NIL */
		EffectSpecListRec*		OscEffectTemplate;

		/* main window thing */
		struct MainWindowRec*	MainWindow;

		/* inverse volume */
		float									InverseVolume;

		/* link for list control */
		WaveTableTemplateRec*	Next;
	};


/* wave table oscillator state record */
struct WaveTableStateRec
	{
		/* current sample position into the wave table */
		LongLongRec						WaveTableSamplePosition; /* 32-bit fixed point */
		/* current increment value for the wave table sample position */
		LongLongRec						WaveTableSamplePositionDifferential; /* 32-bit fixed point */

		/* envelope tick countdown for pre-start time */
		long									PreStartCountdown;

		/* function for generating a bunch of samples from the wave table */
		void									(*WaveTableGenSamples)(WaveTableStateRec* State,
														long SampleCount, largefixedsigned* RawBuffer);

		/* number of frames per table */
		long									FramesPerTable;
		/* number of tables */
		long									NumberOfTables;
		/* raw wave table data array */
		void**								WaveTableMatrix;
		/* number of bits in the data for the table */
		NumBitsType						TableNumBits;

		/* current index into table of waves.  0 = lowest wave table, NumberOfTables = highest */
		FastFixedType					WaveTableIndex;
		/* envelope controlling wave table index */
		EvalEnvelopeRec*			WaveTableIndexEnvelope;
		/* LFO generators modifying the output of the index envelope generator */
		LFOGenRec*						IndexLFOGenerator;

		/* NOTE:  either OverallLoudness or Left/RightLoudness are used, but not both */
		/* current overall loudness for oscillator */
		FastFixedType					OverallLoudness; /* 15-bit fixed point, 0..1 */
		/* left channel loudness */
		FastFixedType					LeftLoudness; /* 15-bit fixed point, 0..1 */
		/* right channel loudness */
		FastFixedType					RightLoudness; /* 15-bit fixed point, 0..1 */
		/* panning position for splitting envelope generator into stereo channels */
		/* 0 = left channel, 0.5 = middle, 1 = right channel */
		FastFixedType					Panning; /* 15-bit fixed point, -1..1 */
		/* envelope that is generating the loudness information */
		EvalEnvelopeRec*			WaveTableLoudnessEnvelope;
		/* LFO generators modifying the output of the loudness envelope generator */
		LFOGenRec*						LoudnessLFOGenerator;

		/* this flag is True if the wave table data was defined at the specified pitch */
		/* (and the wave table array is thus valid) or False if there is no wave table */
		/* at this pitch (and the array is invalid) */
		MyBoolean							WaveTableWasDefined;

		/* this field contains the overall volume scaling for everything so that we */
		/* can treat the envelopes as always going between 0 and 1. */
		float									NoteLoudnessScaling;

		/* this calculates the differential values for periodic pitch displacements */
		LFOGenRec*						PitchLFO;
		/* pitch lfo startup counter; negative = expired */
		long									PitchLFOStartCountdown;

		/* postprocessing for this oscillator; may be NIL */
		OscEffectGenRec*			OscEffectGenerator;

		/* static information for the wave table */
		WaveTableTemplateRec	Template; /* a copy of the data */

		/* link for list control */
		WaveTableStateRec*		Next;
	};




static WaveTableTemplateRec*		WaveTableTemplateFreeList = NIL;
static WaveTableStateRec*				WaveTableStateFreeList = NIL;


/* get rid of all cached memory for state or template records */
void									FlushWaveTableOscControl(void)
	{
		while (WaveTableTemplateFreeList != NIL)
			{
				WaveTableTemplateRec*		Temp;

				Temp = WaveTableTemplateFreeList;
				WaveTableTemplateFreeList = WaveTableTemplateFreeList->Next;
				ReleasePtr((char*)Temp);
			}

		while (WaveTableStateFreeList != NIL)
			{
				WaveTableStateRec*		Temp;

				Temp = WaveTableStateFreeList;
				WaveTableStateFreeList = WaveTableStateFreeList->Next;
				ReleasePtr((char*)Temp);
			}
	}


#if DEBUG
static void						CheckValidWaveTableTemplate(WaveTableTemplateRec* Object)
	{
		WaveTableTemplateRec*	Scan;

		Scan = WaveTableTemplateFreeList;
		while (Scan != NIL)
			{
				if (Scan == Object)
					{
						PRERR(ForceAbort,"CheckValidWaveTableTemplate:  template is on free list");
					}
				Scan = Scan->Next;
			}
	}
#else
#define CheckValidWaveTableTemplate(x) ((void)0)
#endif


#if DEBUG
static void						CheckValidWaveTableState(WaveTableStateRec* Object)
	{
		WaveTableStateRec*		Scan;

		Scan = WaveTableStateFreeList;
		while (Scan != NIL)
			{
				if (Scan == Object)
					{
						PRERR(ForceAbort,"CheckValidWaveTableState:  state is on free list");
					}
				Scan = Scan->Next;
			}
	}
#else
#define CheckValidWaveTableState(x) ((void)0)
#endif


/* perform one envelope update cycle, and set a new frequency for a wave table */
/* state object.  used for portamento and modulation of frequency (vibrato) */
void									UpdateWaveTableEnvelopes(WaveTableStateRec* State,
												float NewFrequencyHertz)
	{
		FastFixedType				Temp;
		double							Differential;

		CheckPtrExistence(State);
		CheckValidWaveTableState(State);

		if (State->PitchLFOStartCountdown > 0)
			{
				State->PitchLFOStartCountdown -= 1;
			}
		 else
			{
				/* do some pitch stuff */
				NewFrequencyHertz = FastFixed2Float(LFOGenUpdateCycle(State->PitchLFO,
					Double2FastFixed(NewFrequencyHertz),NewFrequencyHertz));
			}
		NewFrequencyHertz = NewFrequencyHertz * State->Template.FrequencyMultiplier
			+ State->Template.FrequencyAdder;
		Differential = NewFrequencyHertz / State->Template.FinalOutputSamplingRate
			* State->FramesPerTable;
		Double2LongLong(Differential,&(State->WaveTableSamplePositionDifferential));

		/* this is for the benefit of resampling only -- envelope generators do their */
		/* own pre-origin sequencing */
		if (State->PreStartCountdown > 0)
			{
				State->PreStartCountdown -= 1;
			}

		Temp = (State->NumberOfTables - 1) * LFOGenUpdateCycle(State->IndexLFOGenerator,
			EnvelopeUpdate(State->WaveTableIndexEnvelope,NewFrequencyHertz),NewFrequencyHertz);
		if (Temp < 0)
			{
				Temp = 0;
			}
		else if (Temp > Int2FastFixed(State->NumberOfTables - 1))
			{
				Temp = Int2FastFixed(State->NumberOfTables - 1);
			}
		State->WaveTableIndex = Temp;

		Temp = State->NoteLoudnessScaling * LFOGenUpdateCycle(State->LoudnessLFOGenerator,
			EnvelopeUpdate(State->WaveTableLoudnessEnvelope,NewFrequencyHertz),NewFrequencyHertz);
		/* fast fixed has a very narrow range, so overflow can't be permitted: */
		/* 15x15->30 bits, with 2 extra bits; we use one for sign and the other */
		/* to permit the representation of 1 and -1. */
		if (State->Template.StereoPlayback == eSampleMono)
			{
				if (Temp < - Int2FastFixed(1))
					{
						ErrorDaemonReportClamping(State->Template.ErrorDaemon,
							- FastFixed2Float(Temp));
						Temp = - Int2FastFixed(1);
					}
				else if (Temp > Int2FastFixed(1))
					{
						ErrorDaemonReportClamping(State->Template.ErrorDaemon,
							FastFixed2Float(Temp));
						Temp = Int2FastFixed(1);
					}
				State->OverallLoudness = Temp;
			}
		 else
			{
				FastFixedType				LeftVolumeScaling;
				FastFixedType				RightVolumeScaling;
				FastFixedType				MaxVolScaling;
				FastFixedType				MaxTemp;

				LeftVolumeScaling = FastFixedTimesFastFixedToFastFixed(Double2FastFixed(0.5),
					Int2FastFixed(1) - State->Panning);
				RightVolumeScaling = FastFixedTimesFastFixedToFastFixed(Double2FastFixed(0.5),
					Int2FastFixed(1) + State->Panning);

				if (((LeftVolumeScaling >= 0) ? LeftVolumeScaling : (- LeftVolumeScaling))
					> ((RightVolumeScaling >= 0) ? RightVolumeScaling : (- RightVolumeScaling)))
					{
						MaxVolScaling = ((LeftVolumeScaling >= 0)
							? LeftVolumeScaling : (- LeftVolumeScaling));
					}
				 else
					{
						MaxVolScaling = ((RightVolumeScaling >= 0)
							? RightVolumeScaling : (- RightVolumeScaling));
					}
				MaxTemp = Double2FastFixed((float)1 / FastFixed2Float(MaxVolScaling));
				if (Temp < - MaxTemp)
					{
						ErrorDaemonReportClamping(State->Template.ErrorDaemon,
							- FastFixed2Float(Temp) / FastFixed2Float(MaxTemp));
						Temp = - MaxTemp;
					}
				else if (Temp > MaxTemp)
					{
						ErrorDaemonReportClamping(State->Template.ErrorDaemon,
							FastFixed2Float(Temp) / FastFixed2Float(MaxTemp));
						Temp = MaxTemp;
					}

				State->LeftLoudness = FastFixedTimesFastFixedToFastFixed(
					LeftVolumeScaling,Temp);
				State->RightLoudness = FastFixedTimesFastFixedToFastFixed(
					RightVolumeScaling,Temp);
			}

		if (State->OscEffectGenerator != NIL)
			{
				OscEffectGeneratorUpdateEnvelopes(State->OscEffectGenerator,NewFrequencyHertz);
			}
	}


/* dispose of the wave table state record */
void									DisposeWaveTableState(WaveTableStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);

		if (State->OscEffectGenerator != NIL)
			{
				DisposeOscEffectGenerator(State->OscEffectGenerator);
			}
		DisposeEnvelopeStateRecord(State->WaveTableIndexEnvelope);
		DisposeLFOGenerator(State->IndexLFOGenerator);
		DisposeEnvelopeStateRecord(State->WaveTableLoudnessEnvelope);
		DisposeLFOGenerator(State->LoudnessLFOGenerator);
		DisposeLFOGenerator(State->PitchLFO);

		State->Next = WaveTableStateFreeList;
		WaveTableStateFreeList = State;
	}


/* dispose of the wave table information template */
void									DisposeWaveTableTemplate(WaveTableTemplateRec* Template)
	{
		CheckPtrExistence(Template);
		CheckValidWaveTableTemplate(Template);

		DisposeMultisample(Template->WaveTableSourceSelector);

		Template->Next = WaveTableTemplateFreeList;
		WaveTableTemplateFreeList = Template;
	}


/* create a new wave table template */
WaveTableTemplateRec*	NewWaveTableTemplate(struct OscillatorRec* Oscillator,
												float EnvelopeTicksPerSecond, long SamplingRate,
												MyBoolean Stereo, MyBoolean TimeInterp, MyBoolean WaveInterp,
												struct ErrorDaemonRec* ErrorDaemon,
												struct MainWindowRec* MainWindow, float InverseVolume)
	{
		WaveTableTemplateRec*	Template;

		CheckPtrExistence(ErrorDaemon);
		CheckPtrExistence(Oscillator);
		ERROR(OscillatorGetWhatKindItIs(Oscillator) != eOscillatorWaveTable,PRERR(ForceAbort,
			"NewWaveTableTemplate:  oscillator is not a wave table"));

		if (WaveTableTemplateFreeList != NIL)
			{
				Template = WaveTableTemplateFreeList;
				WaveTableTemplateFreeList = WaveTableTemplateFreeList->Next;
			}
		 else
			{
				Template = (WaveTableTemplateRec*)AllocPtrCanFail(sizeof(WaveTableTemplateRec),
					"WaveTableTemplateRec");
				if (Template == NIL)
					{
						return NIL;
					}
			}
		EXECUTE(Template->Next = (WaveTableTemplateRec*)0x81818181;)

		Template->WaveTableSourceSelector = NewMultisampleWaveTable(
			OscillatorGetSampleIntervalList(Oscillator));
		if (Template->WaveTableSourceSelector == NIL)
			{
			 FailurePoint1:
				Template->Next = WaveTableTemplateFreeList;
				WaveTableTemplateFreeList = Template;
				return NIL;
			}

		Template->FinalOutputSamplingRate = SamplingRate;
		Template->EnvelopeTicksPerSecond = EnvelopeTicksPerSecond;
		Template->InverseVolume = InverseVolume;
		Template->OverallOscillatorLoudness = OscillatorGetOutputLoudness(Oscillator);

		/* it might be better to handle divisor and multiplier separately -- we would */
		/* want to do that if we were trying to guarantee that all harmonic */
		/* oscillators ran in lock-step */
		Template->FrequencyMultiplier = OscillatorGetFrequencyMultiplier(Oscillator)
			/ OscillatorGetFrequencyDivisor(Oscillator);
		Template->FrequencyAdder = OscillatorGetFrequencyAdder(Oscillator);

		Template->StereoBias = OscillatorGetStereoBias(Oscillator);
		Template->TimeDisplacement = OscillatorGetTimeDisplacement(Oscillator);

		if (Stereo)
			{
				Template->StereoPlayback = eSampleStereo;
			}
		 else
			{
				Template->StereoPlayback = eSampleMono;
			}
		Template->InterpolateThroughTime = TimeInterp;
		Template->InterpolateAcrossWaves = WaveInterp;

		/* these are just references */
		Template->LoudnessEnvelopeTemplate = OscillatorGetLoudnessEnvelope(Oscillator);
		Template->LoudnessLFOTemplate = OscillatorGetLoudnessLFOList(Oscillator);
		Template->IndexEnvelopeTemplate = OscillatorGetExcitationEnvelope(Oscillator);
		Template->IndexLFOTemplate = OscillatorGetExcitationLFOList(Oscillator);

		/* more references */
		Template->ErrorDaemon = ErrorDaemon;
		Template->PitchLFOTemplate = GetOscillatorFrequencyLFOList(Oscillator);
		Template->OscEffectTemplate = GetOscillatorEffectList(Oscillator);
		if (GetEffectSpecListLength(Template->OscEffectTemplate) == 0)
			{
				Template->OscEffectTemplate = NIL;
			}
		Template->MainWindow = MainWindow;

		return Template;
	}


/* create a new wave table state object. */
WaveTableStateRec*		NewWaveTableState(WaveTableTemplateRec* Template,
												float FreqForMultisampling, AccentParam* Accents,
												float Loudness, float HurryUp,
												long* PreOriginTimeOut, float StereoPosition,
												float InitialFrequency, float PitchDisplacementDepthLimit,
												float PitchDisplacementRateLimit,
												long PitchDisplacementStartPoint)
	{
		WaveTableStateRec*	State;
		long								MaxPreOrigin;
		long								OnePreOrigin;

		CheckPtrExistence(Template);
		CheckValidWaveTableTemplate(Template);

		if (WaveTableStateFreeList != NIL)
			{
				State = WaveTableStateFreeList;
				WaveTableStateFreeList = WaveTableStateFreeList->Next;
			}
		 else
			{
				State = (WaveTableStateRec*)AllocPtrCanFail(sizeof(WaveTableStateRec),
					"WaveTableStateRec");
				if (State == NIL)
					{
					 FailurePoint1:
						return NIL;
					}
			}
		EXECUTE(State->Next = (WaveTableStateRec*)0x81818181;)

		State->Template = *Template;

		MaxPreOrigin = 0;

		Double2LongLong(0,&(State->WaveTableSamplePosition));
		/* State->WaveTableSamplePositionDifferential specified in separate call */

		State->NoteLoudnessScaling = Loudness * Template->OverallOscillatorLoudness;

		State->WaveTableWasDefined = GetMultisampleReferenceWaveTable(
			Template->WaveTableSourceSelector,FreqForMultisampling,&(State->WaveTableMatrix),
			&(State->FramesPerTable),&(State->NumberOfTables),&(State->TableNumBits));

		/* State->WaveTableWasDefined: */
		/*   if there is no wave table defined for the current pitch, then we don't */
		/*   bother generating any data */
		/* State->FramesPerTable > 0: */
		/*   if the wave table is empty, then we don't do any work (and we must not, */
		/*   since array accesses would cause a crash) */
		if (State->WaveTableWasDefined && (State->FramesPerTable > 0))
			{
				if (Template->StereoPlayback == eSampleStereo)
					{
						if (State->TableNumBits == eSample16bit)
							{
								if (Template->InterpolateAcrossWaves)
									{
										State->WaveTableGenSamples = &Wave_Stereo_16BitIn_YesTime_YesWave;
									}
								else if (Template->InterpolateThroughTime)
									{
										State->WaveTableGenSamples = &Wave_Stereo_16BitIn_YesTime_NoWave;
									}
								else
									{
										State->WaveTableGenSamples = &Wave_Stereo_16BitIn_NoTime_NoWave;
									}
							}
						 else
							{
								if (Template->InterpolateAcrossWaves)
									{
										State->WaveTableGenSamples = &Wave_Stereo_8BitIn_YesTime_YesWave;
									}
								else if (Template->InterpolateThroughTime)
									{
										State->WaveTableGenSamples = &Wave_Stereo_8BitIn_YesTime_NoWave;
									}
								else
									{
										State->WaveTableGenSamples = &Wave_Stereo_8BitIn_NoTime_NoWave;
									}
							}
					}
				 else
					{
						if (State->TableNumBits == eSample16bit)
							{
								if (Template->InterpolateAcrossWaves)
									{
										State->WaveTableGenSamples = &Wave_Mono_16BitIn_YesTime_YesWave;
									}
								else if (Template->InterpolateThroughTime)
									{
										State->WaveTableGenSamples = &Wave_Mono_16BitIn_YesTime_NoWave;
									}
								else
									{
										State->WaveTableGenSamples = &Wave_Mono_16BitIn_NoTime_NoWave;
									}
							}
						 else
							{
								if (Template->InterpolateAcrossWaves)
									{
										State->WaveTableGenSamples = &Wave_Mono_8BitIn_YesTime_YesWave;
									}
								else if (Template->InterpolateThroughTime)
									{
										State->WaveTableGenSamples = &Wave_Mono_8BitIn_YesTime_NoWave;
									}
								else
									{
										State->WaveTableGenSamples = &Wave_Mono_8BitIn_NoTime_NoWave;
									}
							}
					}
			}
		 else
			{
				State->WaveTableGenSamples = &Wave_NoOutput;
			}

		State->PreStartCountdown = Template->TimeDisplacement
			* Template->EnvelopeTicksPerSecond + 0.5;
		if (- State->PreStartCountdown > MaxPreOrigin)
			{
				MaxPreOrigin = - State->PreStartCountdown;
			}

		/* State->WaveTableIndex determined by envelope update */
		State->WaveTableIndexEnvelope = NewEnvelopeStateRecord(
			Template->IndexEnvelopeTemplate,Accents,InitialFrequency,
			1,HurryUp,Template->EnvelopeTicksPerSecond,&OnePreOrigin);
		if (State->WaveTableIndexEnvelope == NIL)
			{
			 FailurePoint2:
				State->Next = WaveTableStateFreeList;
				WaveTableStateFreeList = State;
				goto FailurePoint1;
			}
		if (OnePreOrigin > MaxPreOrigin)
			{
				MaxPreOrigin = OnePreOrigin;
			}
		State->IndexLFOGenerator = NewLFOGenerator(Template->IndexLFOTemplate,
			&OnePreOrigin,Accents,InitialFrequency,HurryUp,
			Template->EnvelopeTicksPerSecond,1,1,FreqForMultisampling);
		if (State->IndexLFOGenerator == NIL)
			{
			 FailurePoint3:
				DisposeEnvelopeStateRecord(State->WaveTableIndexEnvelope);
				goto FailurePoint2;
			}
		if (OnePreOrigin > MaxPreOrigin)
			{
				MaxPreOrigin = OnePreOrigin;
			}

		/* State->OverallLoudness, State->LeftLoudness, State->RightLoudness */
		/* are determined by the envelope update */
		StereoPosition += Template->StereoBias;
		if (StereoPosition < -1)
			{
				StereoPosition = -1;
			}
		else if (StereoPosition > 1)
			{
				StereoPosition = 1;
			}
		State->Panning = Double2FastFixed(StereoPosition);
		State->WaveTableLoudnessEnvelope = NewEnvelopeStateRecord(
			Template->LoudnessEnvelopeTemplate,Accents,
			InitialFrequency,1,HurryUp,Template->EnvelopeTicksPerSecond,&OnePreOrigin);
		if (State->WaveTableLoudnessEnvelope == NIL)
			{
			 FailurePoint4:
				DisposeLFOGenerator(State->IndexLFOGenerator);
				goto FailurePoint3;
			}
		if (OnePreOrigin > MaxPreOrigin)
			{
				MaxPreOrigin = OnePreOrigin;
			}
		State->LoudnessLFOGenerator = NewLFOGenerator(Template->LoudnessLFOTemplate,
			&OnePreOrigin,Accents,InitialFrequency,HurryUp,
			Template->EnvelopeTicksPerSecond,1,1,FreqForMultisampling);
		if (State->LoudnessLFOGenerator == NIL)
			{
			 FailurePoint5:
				DisposeEnvelopeStateRecord(State->WaveTableLoudnessEnvelope);
				goto FailurePoint4;
			}
		if (OnePreOrigin > MaxPreOrigin)
			{
				MaxPreOrigin = OnePreOrigin;
			}
		State->PitchLFO = NewLFOGenerator(Template->PitchLFOTemplate,
			&OnePreOrigin,Accents,InitialFrequency,HurryUp,
			Template->EnvelopeTicksPerSecond,PitchDisplacementDepthLimit,
			PitchDisplacementRateLimit,FreqForMultisampling);
		if (State->PitchLFO == NIL)
			{
			 FailurePoint6:
				DisposeLFOGenerator(State->LoudnessLFOGenerator);
				goto FailurePoint5;
			}
		if (OnePreOrigin > MaxPreOrigin)
			{
				MaxPreOrigin = OnePreOrigin;
			}
		State->PitchLFOStartCountdown = PitchDisplacementStartPoint;
		if (Template->OscEffectTemplate == NIL)
			{
				State->OscEffectGenerator = NIL;
			}
		 else
			{
				State->OscEffectGenerator = NewOscEffectGenerator(Template->OscEffectTemplate,
					Template->EnvelopeTicksPerSecond,Template->FinalOutputSamplingRate,
					(Template->StereoPlayback == eSampleStereo),Template->InverseVolume,
					Template->MainWindow,Accents,HurryUp,
					InitialFrequency,FreqForMultisampling,&OnePreOrigin);
				if (State->OscEffectGenerator == NIL)
					{
					 FailurePoint7:
						DisposeLFOGenerator(State->PitchLFO);
						goto FailurePoint6;
					}
				if (OnePreOrigin > MaxPreOrigin)
					{
						MaxPreOrigin = OnePreOrigin;
					}
			}

		*PreOriginTimeOut = MaxPreOrigin;
		return State;
	}


/* fix up pre-origin time for the wave table state object */
void									FixUpWaveTableStatePreOrigin(WaveTableStateRec* State,
												long ActualPreOrigin)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);

		EnvelopeStateFixUpInitialDelay(State->WaveTableIndexEnvelope,ActualPreOrigin);
		EnvelopeStateFixUpInitialDelay(State->WaveTableLoudnessEnvelope,ActualPreOrigin);
		LFOGeneratorFixEnvelopeOrigins(State->IndexLFOGenerator,ActualPreOrigin);
		LFOGeneratorFixEnvelopeOrigins(State->LoudnessLFOGenerator,ActualPreOrigin);
		LFOGeneratorFixEnvelopeOrigins(State->PitchLFO,ActualPreOrigin);
		if (State->OscEffectGenerator != NIL)
			{
				FixUpOscEffectGeneratorPreOrigin(State->OscEffectGenerator,ActualPreOrigin);
			}

		State->PreStartCountdown += ActualPreOrigin;
	}


/* send a key-up signal to one of the oscillators */
void									WaveTableKeyUpSustain1(WaveTableStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);
		LFOGeneratorKeyUpSustain1(State->IndexLFOGenerator);
		LFOGeneratorKeyUpSustain1(State->LoudnessLFOGenerator);
		EnvelopeKeyUpSustain1(State->WaveTableIndexEnvelope);
		EnvelopeKeyUpSustain1(State->WaveTableLoudnessEnvelope);
		LFOGeneratorKeyUpSustain1(State->PitchLFO);
		if (State->OscEffectGenerator != NIL)
			{
				OscEffectKeyUpSustain1(State->OscEffectGenerator);
			}
	}


/* send a key-up signal to one of the oscillators */
void									WaveTableKeyUpSustain2(WaveTableStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);
		LFOGeneratorKeyUpSustain2(State->IndexLFOGenerator);
		LFOGeneratorKeyUpSustain2(State->LoudnessLFOGenerator);
		EnvelopeKeyUpSustain2(State->WaveTableIndexEnvelope);
		EnvelopeKeyUpSustain2(State->WaveTableLoudnessEnvelope);
		LFOGeneratorKeyUpSustain2(State->PitchLFO);
		if (State->OscEffectGenerator != NIL)
			{
				OscEffectKeyUpSustain2(State->OscEffectGenerator);
			}
	}


/* send a key-up signal to one of the oscillators */
void									WaveTableKeyUpSustain3(WaveTableStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);
		LFOGeneratorKeyUpSustain3(State->IndexLFOGenerator);
		LFOGeneratorKeyUpSustain3(State->LoudnessLFOGenerator);
		EnvelopeKeyUpSustain3(State->WaveTableIndexEnvelope);
		EnvelopeKeyUpSustain3(State->WaveTableLoudnessEnvelope);
		LFOGeneratorKeyUpSustain3(State->PitchLFO);
		if (State->OscEffectGenerator != NIL)
			{
				OscEffectKeyUpSustain3(State->OscEffectGenerator);
			}
	}


/* restart a wave table oscillator.  this is used for tie continuations */
void									RestartWaveTableState(WaveTableStateRec* State,
												float NewFreqMultisampling, AccentParam* NewAccents,
												float NewLoudness, float NewHurryUp, MyBoolean RetriggerEnvelopes,
												float NewStereoPosition, float NewInitialFrequency,
												float PitchDisplacementDepthLimit,
												float PitchDisplacementRateLimit,
												long PitchDisplacementStartPoint)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);

		NewStereoPosition += State->Template.StereoBias;
		if (NewStereoPosition < -1)
			{
				NewStereoPosition = -1;
			}
		else if (NewStereoPosition > 1)
			{
				NewStereoPosition = 1;
			}
		State->Panning = Double2FastFixed(NewStereoPosition);

		State->NoteLoudnessScaling = NewLoudness * State->Template.OverallOscillatorLoudness;

		EnvelopeRetriggerFromOrigin(State->WaveTableIndexEnvelope,NewAccents,
			NewInitialFrequency,1,NewHurryUp,
			State->Template.EnvelopeTicksPerSecond,RetriggerEnvelopes);
		EnvelopeRetriggerFromOrigin(State->WaveTableLoudnessEnvelope,NewAccents,
			NewInitialFrequency,1,NewHurryUp,
			State->Template.EnvelopeTicksPerSecond,RetriggerEnvelopes);
		LFOGeneratorRetriggerFromOrigin(State->IndexLFOGenerator,NewAccents,
			NewInitialFrequency,NewHurryUp,1,1,RetriggerEnvelopes);
		LFOGeneratorRetriggerFromOrigin(State->LoudnessLFOGenerator,NewAccents,
			NewInitialFrequency,NewHurryUp,1,1,
			RetriggerEnvelopes);
		LFOGeneratorRetriggerFromOrigin(State->PitchLFO,NewAccents,
			NewInitialFrequency,NewHurryUp,
			PitchDisplacementDepthLimit,PitchDisplacementRateLimit,
			RetriggerEnvelopes);
		if (State->OscEffectGenerator != NIL)
			{
				OscEffectGeneratorRetriggerFromOrigin(State->OscEffectGenerator,
					NewAccents,NewInitialFrequency,NewHurryUp,RetriggerEnvelopes);
			}
		if (RetriggerEnvelopes)
			{
				State->PitchLFOStartCountdown = PitchDisplacementStartPoint;
			}
		 else
			{
				State->PitchLFOStartCountdown = -1;
			}
	}


/* generate one sequence of samples */
void									WaveTableGenSamples(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer,
												largefixedsigned* PrivateWorkspace)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);

		if (State->PreStartCountdown <= 0)
			{
				if (State->OscEffectGenerator == NIL)
					{
						/* normal case */
						(*State->WaveTableGenSamples)(State,SampleCount,RawBuffer);
					}
				 else
					{
						/* effect postprocessing case */
						/* initialize private storage */
						if (State->Template.StereoPlayback == eSampleMono)
							{
								long								Scan;

								for (Scan = 0; Scan < SampleCount; Scan += 1)
									{
										PrivateWorkspace[Scan] = 0;
									}
							}
						 else
							{
								long								Scan;

								for (Scan = 0; Scan < 2 * SampleCount; Scan += 1)
									{
										PrivateWorkspace[Scan] = 0;
									}
							}
						/* generate waveform */
						(*State->WaveTableGenSamples)(State,SampleCount,PrivateWorkspace);
						/* apply processor to it */
						ApplyOscEffectGenerator(State->OscEffectGenerator,PrivateWorkspace,
							SampleCount);
						/* copy out data */
						if (State->Template.StereoPlayback == eSampleMono)
							{
								long								Scan;

								for (Scan = 0; Scan < SampleCount; Scan += 1)
									{
										RawBuffer[Scan] += PrivateWorkspace[Scan];
									}
							}
						 else
							{
								long								Scan;

								for (Scan = 0; Scan < 2 * SampleCount; Scan += 1)
									{
										RawBuffer[Scan] += PrivateWorkspace[Scan];
									}
							}
					}
			}
	}


/* find out if the wave table oscillator has finished */
MyBoolean							WaveTableIsItFinished(WaveTableStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidWaveTableState(State);

		/* we are finished when one of the following conditions is met: */
		/*  - output volume is zero AND loudness envelope is finished */
		/*  - we are not generating any signal */
		if (!State->WaveTableWasDefined)
			{
				return True;
			}
		if (IsEnvelopeAtEnd(State->WaveTableLoudnessEnvelope))
			{
				if (State->Template.StereoPlayback == eSampleStereo)
					{
						if ((State->LeftLoudness == 0) && (State->RightLoudness == 0))
							{
								return True;
							}
					}
				 else
					{
						if (State->OverallLoudness == 0)
							{
								return True;
							}
					}
			}
		return IsEnvelopeAtEnd(State->WaveTableLoudnessEnvelope);
	}


static void						Wave_Mono_8BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed char*				WaveData;
		FastFixedType				LocalOverallLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Mono_8BitIn_NoTime_NoWave:  wave index out of range"));
		LocalOverallLoudness = State->OverallLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalOverallLoudness,
					WaveData[LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask]);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Stereo_8BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed char*				WaveData;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Stereo_8BitIn_NoTime_NoWave:  wave index out of range"));
		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				signed long					SamplePoint;

				SamplePoint = WaveData[LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask];
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalLeftLoudness,SamplePoint);
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalRightLoudness,SamplePoint);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Mono_16BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed short*				WaveData;
		FastFixedType				LocalOverallLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Mono_16BitIn_NoTime_NoWave:  wave index out of range"));
		LocalOverallLoudness = State->OverallLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,
					WaveData[LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask]);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Stereo_16BitIn_NoTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed short*				WaveData;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Stereo_16BitIn_NoTime_NoWave:  wave index out of range"));
		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				signed long					SamplePoint;

				SamplePoint = WaveData[LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask];
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,SamplePoint);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,SamplePoint);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Mono_8BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed char*				WaveData;
		FastFixedType				LocalOverallLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Mono_8BitIn_YesTime_NoWave:  wave index out of range"));
		LocalOverallLoudness = State->OverallLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					LeftValue;
				signed long					RightValue;

				/* naive anti-aliasing worked as follows: */
				/*  L = left sample, R = right sample, F = fractional portion of index */
				/*  S = L(1-F) + RF */
				/*  Craig Peeper suggested the following optimization: */
				/*  L(1-F)+RF ==> L-LF+RF ==> L+RF-LF ==> L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) */
				LeftValue = ((signed long)WaveData[ArraySubscript]) << 8; /* convert to 16-bit */
				RightValue = ((signed long)WaveData[ArraySubscript + 1]) << 8; /* to 16-bit */
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Stereo_8BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed char*				WaveData;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Stereo_8BitIn_YesTime_NoWave:  wave index out of range"));
		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					LeftValue;
				signed long					RightValue;
				signed long					CombinedValue;

				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) */
				LeftValue = ((signed long)WaveData[ArraySubscript]) << 8; /* convert to 16-bit */
				RightValue = ((signed long)WaveData[ArraySubscript + 1]) << 8; /* to 16-bit */
				CombinedValue = LeftValue + ((LeftWeight * (RightValue - LeftValue)) >> 15);
				/* Oh, Please Mr. Compiler, LeftValue and RightValue are dead now!!! */
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,CombinedValue);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,CombinedValue);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Mono_16BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed short*				WaveData;
		FastFixedType				LocalOverallLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Mono_16BitIn_YesTime_NoWave:  wave index out of range"));
		LocalOverallLoudness = State->OverallLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					LeftValue;
				signed long					RightValue;

				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) */
				LeftValue = WaveData[ArraySubscript];
				RightValue = WaveData[ArraySubscript + 1];
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Stereo_16BitIn_YesTime_NoWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed short*				WaveData;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Stereo_16BitIn_YesTime_NoWave:  wave index out of range"));
		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					LeftValue;
				signed long					RightValue;
				signed long					CombinedValue;

				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) */
				LeftValue = WaveData[ArraySubscript];
				RightValue = WaveData[ArraySubscript + 1];
				CombinedValue = LeftValue + ((LeftWeight * (RightValue - LeftValue)) >> 15);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,CombinedValue);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,CombinedValue);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Mono_8BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed char*				WaveData0;
		signed char*				WaveData1;
		FastFixedType				Wave0Weight;
		FastFixedType				LocalOverallLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Mono_8BitIn_YesTime_YesWave:  wave index out of range"));
		if (FastFixed2Int(State->WaveTableIndex) == State->NumberOfTables - 1)
			{
				/* this is done in case the wave table index is at the maximum, in which */
				/* case there is no table+1 to interpolate with. */
				Wave_Mono_8BitIn_YesTime_NoWave(State,SampleCount,RawBuffer);
				return;
			}
		LocalOverallLoudness = State->OverallLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData0 = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]));
		WaveData1 = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex) + 1]);
		Wave0Weight = State->WaveTableIndex & FASTFIXEDFRACTMASK;

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					Left0Value;
				signed long					Right0Value;
				signed long					Left1Value;
				signed long					Right1Value;
				FastFixedType				Wave0Temp;

				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) -- applied twice */
				Left0Value = ((signed long)WaveData0[ArraySubscript]) << 8; /* convert to 16-bit */
				Right0Value = ((signed long)WaveData0[ArraySubscript + 1]) << 8; /* to 16-bit */
				Left1Value = ((signed long)WaveData1[ArraySubscript]) << 8; /* convert to 16-bit */
				Right1Value = ((signed long)WaveData1[ArraySubscript + 1]) << 8; /* to 16-bit */
				Wave0Temp = Left0Value + ((LeftWeight * (Right0Value - Left0Value)) >> 15);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,
					Wave0Temp + ((Wave0Weight * (Left1Value + ((LeftWeight * (Right1Value
					- Left1Value)) >> 15) - Wave0Temp)) >> 15));
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Stereo_8BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed char*				WaveData0;
		signed char*				WaveData1;
		FastFixedType				Wave0Weight;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Stereo_8BitIn_YesTime_YesWave:  wave index out of range"));
		if (FastFixed2Int(State->WaveTableIndex) == State->NumberOfTables - 1)
			{
				/* this is done in case the wave table index is at the maximum, in which */
				/* case there is no table+1 to interpolate with. */
				Wave_Stereo_8BitIn_YesTime_NoWave(State,SampleCount,RawBuffer);
				return;
			}
		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData0 = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]));
		WaveData1 = (signed char*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex) + 1]);
		Wave0Weight = State->WaveTableIndex & FASTFIXEDFRACTMASK;

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					Left0Value;
				signed long					Right0Value;
				signed long					Left1Value;
				signed long					Right1Value;
				FastFixedType				Wave0Temp;

				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) -- applied twice */
				Left0Value = ((signed long)WaveData0[ArraySubscript]) << 8; /* convert to 16-bit */
				Right0Value = ((signed long)WaveData0[ArraySubscript + 1]) << 8; /* to 16-bit */
				Left1Value = ((signed long)WaveData1[ArraySubscript]) << 8; /* convert to 16-bit */
				Right1Value = ((signed long)WaveData1[ArraySubscript + 1]) << 8; /* to 16-bit */
				Wave0Temp = Left0Value + ((LeftWeight * (Right0Value - Left0Value)) >> 15);
				Wave0Temp = Wave0Temp + ((Wave0Weight * (Left1Value + ((LeftWeight * (Right1Value
					- Left1Value)) >> 15) - Wave0Temp)) >> 15);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,Wave0Temp);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,Wave0Temp);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Mono_16BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed short*				WaveData0;
		signed short*				WaveData1;
		FastFixedType				Wave0Weight;
		FastFixedType				LocalOverallLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Mono_16BitIn_YesTime_YesWave:  wave index out of range"));
		if (FastFixed2Int(State->WaveTableIndex) == State->NumberOfTables - 1)
			{
				/* this is done in case the wave table index is at the maximum, in which */
				/* case there is no table+1 to interpolate with. */
				Wave_Mono_16BitIn_YesTime_NoWave(State,SampleCount,RawBuffer);
				return;
			}
		LocalOverallLoudness = State->OverallLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData0 = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]));
		WaveData1 = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex) + 1]);
		Wave0Weight = State->WaveTableIndex & FASTFIXEDFRACTMASK;

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					Left0Value;
				signed long					Right0Value;
				signed long					Left1Value;
				signed long					Right1Value;
				FastFixedType				Wave0Temp;

				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) -- applied twice */
				Left0Value = WaveData0[ArraySubscript];
				Right0Value = WaveData0[ArraySubscript + 1];
				Left1Value = WaveData1[ArraySubscript];
				Right1Value = WaveData1[ArraySubscript + 1];
				Wave0Temp = Left0Value + ((LeftWeight * (Right0Value - Left0Value)) >> 15);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,
					Wave0Temp + ((Wave0Weight * (Left1Value + ((LeftWeight * (Right1Value
					- Left1Value)) >> 15) - Wave0Temp)) >> 15));
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_Stereo_16BitIn_YesTime_YesWave(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalWaveTableSamplePosition;
		LongLongRec					LocalWaveTableSamplePositionDifferential;
		unsigned long				LocalSamplePositionMask;
		signed short*				WaveData0;
		signed short*				WaveData1;
		FastFixedType				Wave0Weight;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;

		ERROR((State->WaveTableIndex < 0) || (State->WaveTableIndex
			> Int2FastFixed(State->NumberOfTables - 1)),PRERR(ForceAbort,
			"Wave_Stereo_16BitIn_YesTime_YesWave:  wave index out of range"));
		if (FastFixed2Int(State->WaveTableIndex) == State->NumberOfTables - 1)
			{
				/* this is done in case the wave table index is at the maximum, in which */
				/* case there is no table+1 to interpolate with. */
				Wave_Stereo_16BitIn_YesTime_NoWave(State,SampleCount,RawBuffer);
				return;
			}
		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalWaveTableSamplePosition = State->WaveTableSamplePosition;
		LocalWaveTableSamplePositionDifferential = State->WaveTableSamplePositionDifferential;
		LocalSamplePositionMask = State->FramesPerTable - 1;
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex)]));
		WaveData0 = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex)]);
		PRNGCHK(State->WaveTableMatrix,&(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]),sizeof(State->WaveTableMatrix[FastFixed2Int(
			State->WaveTableIndex) + 1]));
		WaveData1 = (signed short*)(State->WaveTableMatrix[
			FastFixed2Int(State->WaveTableIndex) + 1]);
		Wave0Weight = State->WaveTableIndex & FASTFIXEDFRACTMASK;

		while (SampleCount > 0)
			{
				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					Left0Value;
				signed long					Right0Value;
				signed long					Left1Value;
				signed long					Right1Value;
				FastFixedType				Wave0Temp;

				LeftWeight = LongLongLowHalf(LocalWaveTableSamplePosition)
					>> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalWaveTableSamplePosition)
					& LocalSamplePositionMask;
				/* L+F(R-L) -- applied twice */
				Left0Value = WaveData0[ArraySubscript];
				Right0Value = WaveData0[ArraySubscript + 1];
				Left1Value = WaveData1[ArraySubscript];
				Right1Value = WaveData1[ArraySubscript + 1];
				Wave0Temp = Left0Value + ((LeftWeight * (Right0Value - Left0Value)) >> 15);
				Wave0Temp = Wave0Temp + ((Wave0Weight * (Left1Value + ((LeftWeight
					* (Right1Value - Left1Value)) >> 15) - Wave0Temp)) >> 15);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,Wave0Temp);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,Wave0Temp);
				LongLongAdd(&LocalWaveTableSamplePosition,
					&LocalWaveTableSamplePositionDifferential);
				SampleCount -= 1;
			}

		State->WaveTableSamplePosition = LocalWaveTableSamplePosition;
	}


static void						Wave_NoOutput(WaveTableStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
	}
