/* SampleOscControl.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 "SampleOscControl.h"
#include "64BitMath.h"
#include "Multisampler.h"
#include "EnvelopeState.h"
#include "Envelope.h"
#include "LFOGenerator.h"
#include "LFOListSpecifier.h"
#include "SampleConsts.h"
#include "Memory.h"
#include "OscillatorSpecifier.h"
#include "ErrorDaemon.h"
#include "OscEffectGenerator.h"
#include "EffectSpecList.h"


#if !MEMDEBUG && DEBUG
	#undef PRNGCHK
	#define PRNGCHK(x,y,z) ((void)0)
#endif


/* prototypes for fast playback routines */
static void						Sample_MonoOut_MonoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_MonoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_MonoOut_StereoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_StereoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);

static void						Sample_MonoOut_MonoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_MonoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_MonoOut_StereoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_StereoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);

static void						Sample_MonoOut_MonoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_MonoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_MonoOut_StereoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_StereoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);

static void						Sample_MonoOut_MonoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_MonoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_MonoOut_StereoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);
static void						Sample_StereoOut_StereoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);

static void						Sample_NoOutput(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer);


/* this is used for loop control */
typedef enum
	{
		eRepeatingLoop1 EXECUTE(= -18734),
		eRepeatingLoop2,
		eRepeatingLoop3,
		eNoLoop,
		eSampleFinished
	} LoopType;


/* sample oscillator template information record */
struct SampleTemplateRec
	{
		/* source information for the sample */
		MultiSampleRec*				SampleSourceSelector;

		/* 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; /* not used now -- for future use */

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

		/* 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 */
		SampleTemplateRec*		Next;
	};


/* sample oscillator state record */
struct SampleStateRec
	{
		/* current sample position into the array */
		LongLongRec						SamplePosition; /* 32-bit fixed point */
		/* current increment value for the sample position */
		LongLongRec						SamplePositionDifferential; /* 32-bit fixed point */
		/* envelope tick countdown for pre-start time */
		long									PreStartCountdown;

		/* function for generating a bunch of sample points */
		void									(*SampleGenSamples)(SampleStateRec* State,
														long SampleCount, largefixedsigned* RawBuffer);

		/* number of frames in the sample */
		long									NumFrames;
		/* sample data pointer.  for mono, it is just an array.  for stereo, the */
		/* samples are interleaved, left channel first */
		void*									Data;
		/* number of bits in the data for the sample */
		NumBitsType						NumBits;
		/* stereo or mono sample */
		NumChannelsType				NumChannels;

		/* control parameters for the sample */
		float									NaturalFrequency;
		long									SamplingRate;
		long									OriginPoint;
		long									Loop1Start;
		long									Loop2Start;
		long									Loop3Start;
		long									Loop1End;
		long									Loop2End;
		long									Loop3End;
		/* state information for the current position */
		LoopType							LoopState; /* which loop is running */
		long									CurrentLoopLength; /* current loop length (end - start) */
		long									CurrentLoopEnd; /* current loop/total end point */

		/* 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, 0..1 */
		/* envelope that is generating the loudness information */
		EvalEnvelopeRec*			SampleLoudnessEnvelope;
		/* LFO generators modifying the output of the loudness envelope generator */
		LFOGenRec*						LoudnessLFOGenerator;

		/* this flag is True if the sample data was defined at the specified pitch */
		/* (and the sample vectors are thus valid) or False if there is no sample */
		/* at this pitch (and the arrays are invalid) */
		MyBoolean							SampleWasDefined;

		/* 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 sample */
		SampleTemplateRec			Template; /* a copy of the data */

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




static SampleTemplateRec*				SampleTemplateFreeList = NIL;
static SampleStateRec*					SampleStateFreeList = NIL;


/* get rid of all cached memory for state or template records */
void									FlushSampleOscControl(void)
	{
		while (SampleTemplateFreeList != NIL)
			{
				SampleTemplateRec*	Temp;

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

		while (SampleStateFreeList != NIL)
			{
				SampleStateRec*			Temp;

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


#if DEBUG
static void						CheckValidSampleTemplate(SampleTemplateRec* Object)
	{
		SampleTemplateRec*	Scan;

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


#if DEBUG
static void						CheckValidSampleState(SampleStateRec* Object)
	{
		SampleStateRec*			Scan;

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


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

		CheckPtrExistence(State);
		CheckValidSampleState(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->NaturalFrequency)
			/ State->Template.FinalOutputSamplingRate
			* State->SamplingRate;
		if (Differential < 0)
			{
				Differential = 0;
			}
		Double2LongLong(Differential,&(State->SamplePositionDifferential));

		/* 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->NoteLoudnessScaling * LFOGenUpdateCycle(State->LoudnessLFOGenerator,
			EnvelopeUpdate(State->SampleLoudnessEnvelope,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 sample state record */
void									DisposeSampleState(SampleStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(State);

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

		State->Next = SampleStateFreeList;
		SampleStateFreeList = State;
	}


/* dispose of the sample information template */
void									DisposeSampleTemplate(SampleTemplateRec* Template)
	{
		CheckPtrExistence(Template);
		CheckValidSampleTemplate(Template);

		DisposeMultisample(Template->SampleSourceSelector);

		Template->Next = SampleTemplateFreeList;
		SampleTemplateFreeList = Template;
	}


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

		CheckPtrExistence(ErrorDaemon);
		CheckPtrExistence(Oscillator);
		ERROR(OscillatorGetWhatKindItIs(Oscillator) != eOscillatorSampled,PRERR(ForceAbort,
			"NewSampleTemplate:  oscillator is not a sample"));

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

		Template->SampleSourceSelector = NewMultisampleSample(
			OscillatorGetSampleIntervalList(Oscillator));
		if (Template->SampleSourceSelector == NIL)
			{
			 FailurePoint1:
				Template->Next = SampleTemplateFreeList;
				SampleTemplateFreeList = Template;
				return NIL;
			}

		Template->FinalOutputSamplingRate = SamplingRate;
		Template->EnvelopeTicksPerSecond = EnvelopeTicksPerSecond;
		Template->InverseVolume = InverseVolume;

		/* 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);
		Template->OverallOscillatorLoudness = OscillatorGetOutputLoudness(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);

		/* 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 sample state object. */
SampleStateRec*				NewSampleState(SampleTemplateRec* Template,
												float FreqForMultisampling, AccentParam* Accents, float Loudness,
												float HurryUp, long* PreOriginTimeOut, float StereoPosition,
												float InitialFrequency, float PitchDisplacementDepthLimit,
												float PitchDisplacementRateLimit,
												long PitchDisplacementStartPoint)
	{
		SampleStateRec*			State;
		long								MaxPreOrigin;
		long								OnePreOrigin;
		double							NaturalFreqTemp;

		CheckPtrExistence(Template);
		CheckValidSampleTemplate(Template);

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

		State->Template = *Template;

		MaxPreOrigin = 0;

		Double2LongLong(0,&(State->SamplePosition));
		/* State->SamplePositionDifferential is specified in a separate call */

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

		State->SampleWasDefined = GetMultisampleReferenceSample(
			Template->SampleSourceSelector,FreqForMultisampling,&(State->Data),
			&(State->NumFrames),&(State->NumBits),&(State->NumChannels),&(State->Loop1Start),
			&(State->Loop1End),&(State->Loop2Start),&(State->Loop2End),&(State->Loop3Start),
			&(State->Loop3End),&(State->OriginPoint),&NaturalFreqTemp,&(State->SamplingRate));

		if (State->SampleWasDefined && (State->NumFrames > 0))
			{
				/* copy value over */
				State->NaturalFrequency = NaturalFreqTemp;

				/* bounds checking */
				if (State->Loop1Start < 0)
					{
						State->Loop1Start = 0;
					}
				if (State->Loop1End > State->NumFrames - 1)
					{
						State->Loop1End = State->NumFrames - 1;
					}
				if (State->Loop1End < State->Loop1Start)
					{
						State->Loop1End = State->Loop1Start;
					}
				if (State->Loop2Start < 0)
					{
						State->Loop2Start = 0;
					}
				if (State->Loop2End > State->NumFrames - 1)
					{
						State->Loop2End = State->NumFrames - 1;
					}
				if (State->Loop2End < State->Loop2Start)
					{
						State->Loop2End = State->Loop2Start;
					}
				if (State->Loop3Start < 0)
					{
						State->Loop3Start = 0;
					}
				if (State->Loop3End > State->NumFrames - 1)
					{
						State->Loop3End = State->NumFrames - 1;
					}
				if (State->Loop3End < State->Loop3Start)
					{
						State->Loop3End = State->Loop3Start;
					}

				/* set the initial state */
				if (State->Loop1Start != State->Loop1End)
					{
						State->LoopState = eRepeatingLoop1;
						State->CurrentLoopEnd = State->Loop1End;
						State->CurrentLoopLength = State->Loop1End - State->Loop1Start;
					}
				else if (State->Loop2Start != State->Loop2End)
					{
						State->LoopState = eRepeatingLoop2;
						State->CurrentLoopEnd = State->Loop2End;
						State->CurrentLoopLength = State->Loop2End - State->Loop2Start;
					}
				else if (State->Loop3Start != State->Loop3End)
					{
						State->LoopState = eRepeatingLoop3;
						State->CurrentLoopEnd = State->Loop3End;
						State->CurrentLoopLength = State->Loop3End - State->Loop3Start;
					}
				else
					{
						State->LoopState = eNoLoop;
						State->CurrentLoopEnd = State->NumFrames;
						State->CurrentLoopLength = 0;
					}

				/* compute how much time to wait before starting sample playback.  this */
				/* is INDEPENDENT of the envelope starting points; the envelope generator setup */
				/* handles origin alignment on its own. */
				/* this number will assume the origin starts NOW.  the fixup routine will */
				/* add some number to this so that the origin is properly determined. */
				/* if the countdown is still negative, then the sample will sound like it */
				/* is starting late.  the user can fix this by increasing the scanning gap. */
				State->PreStartCountdown = - (
					((((float)State->OriginPoint / ((InitialFrequency
						* Template->FrequencyMultiplier + Template->FrequencyAdder)
						/ State->NaturalFrequency)) / State->SamplingRate)
						- Template->TimeDisplacement)
					* Template->EnvelopeTicksPerSecond + 0.5);
				if (- State->PreStartCountdown > MaxPreOrigin)
					{
						MaxPreOrigin = - State->PreStartCountdown;
					}
			}
		 else
			{
				/* no playback */
				State->LoopState = eSampleFinished;
			}

		/* State->SampleWasDefined: */
		/*   if there is no sample defined for the current pitch, then we don't */
		/*   bother generating any data */
		/* State->NumFrames > 0: */
		/*   if there is no data in the sample, then don't access the array */
		if (State->SampleWasDefined && (State->NumFrames > 0))
			{
				if (Template->StereoPlayback == eSampleStereo) /* this is output stereo */
					{
						if (State->NumBits == eSample16bit)
							{
								if (State->NumChannels == eSampleStereo) /* this is sample data stereo */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_StereoOut_StereoSamp_16BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_StereoOut_StereoSamp_16BitIn_NoTime;
											}
									}
								 else /* sample data mono */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_StereoOut_MonoSamp_16BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_StereoOut_MonoSamp_16BitIn_NoTime;
											}
									}
							}
						 else /* output 8-bit */
							{
								if (State->NumChannels == eSampleStereo) /* this is sample data stereo */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_StereoOut_StereoSamp_8BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_StereoOut_StereoSamp_8BitIn_NoTime;
											}
									}
								 else /* mono sample data */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_StereoOut_MonoSamp_8BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_StereoOut_MonoSamp_8BitIn_NoTime;
											}
									}
							}
					}
				 else /* output mono */
					{
						if (State->NumBits == eSample16bit)
							{
								if (State->NumChannels == eSampleStereo) /* this is sample data stereo */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_MonoOut_StereoSamp_16BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_MonoOut_StereoSamp_16BitIn_NoTime;
											}
									}
								 else /* sample data mono */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_MonoOut_MonoSamp_16BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_MonoOut_MonoSamp_16BitIn_NoTime;
											}
									}
							}
						 else /* 8-bit */
							{
								if (State->NumChannels == eSampleStereo) /* this is sample data stereo */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_MonoOut_StereoSamp_8BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_MonoOut_StereoSamp_8BitIn_NoTime;
											}
									}
								 else /* sample data mono */
									{
										if (Template->InterpolateThroughTime)
											{
												State->SampleGenSamples = Sample_MonoOut_MonoSamp_8BitIn_YesTime;
											}
										 else
											{
												State->SampleGenSamples = Sample_MonoOut_MonoSamp_8BitIn_NoTime;
											}
									}
							}
					}
			}
		 else
			{
				State->SampleGenSamples = Sample_NoOutput;
			}

		/* 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->SampleLoudnessEnvelope = NewEnvelopeStateRecord(
			Template->LoudnessEnvelopeTemplate,Accents,
			InitialFrequency,1,HurryUp,Template->EnvelopeTicksPerSecond,&OnePreOrigin);
		if (State->SampleLoudnessEnvelope == NIL)
			{
			 FailurePoint2:
				State->Next = SampleStateFreeList;
				SampleStateFreeList = State;
				goto FailurePoint1;
			}
		if (OnePreOrigin > MaxPreOrigin)
			{
				MaxPreOrigin = OnePreOrigin;
			}
		State->LoudnessLFOGenerator = NewLFOGenerator(Template->LoudnessLFOTemplate,
			&OnePreOrigin,Accents,InitialFrequency,HurryUp,
			Template->EnvelopeTicksPerSecond,1,1,FreqForMultisampling);
		if (State->LoudnessLFOGenerator == NIL)
			{
			 FailurePoint3:
				DisposeEnvelopeStateRecord(State->SampleLoudnessEnvelope);
				goto FailurePoint2;
			}
		if (OnePreOrigin > MaxPreOrigin)
			{
				MaxPreOrigin = OnePreOrigin;
			}
		State->PitchLFO = NewLFOGenerator(Template->PitchLFOTemplate,
			&OnePreOrigin,Accents,InitialFrequency,HurryUp,
			Template->EnvelopeTicksPerSecond,PitchDisplacementDepthLimit,
			PitchDisplacementRateLimit,FreqForMultisampling);
		if (State->PitchLFO == NIL)
			{
			 FailurePoint4:
				DisposeLFOGenerator(State->LoudnessLFOGenerator);
				goto FailurePoint3;
			}
		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)
					{
					 FailurePoint5:
						DisposeLFOGenerator(State->PitchLFO);
						goto FailurePoint4;
					}
				if (OnePreOrigin > MaxPreOrigin)
					{
						MaxPreOrigin = OnePreOrigin;
					}
			}

		*PreOriginTimeOut = MaxPreOrigin;
		return State;
	}


/* fix up pre-origin time for the sample state object */
void									FixUpSampleStatePreOrigin(SampleStateRec* State,
												long ActualPreOrigin)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(State);

		EnvelopeStateFixUpInitialDelay(State->SampleLoudnessEnvelope,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									SampleKeyUpSustain1(SampleStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(State);

		LFOGeneratorKeyUpSustain1(State->LoudnessLFOGenerator);
		EnvelopeKeyUpSustain1(State->SampleLoudnessEnvelope);
		LFOGeneratorKeyUpSustain1(State->PitchLFO);
		if (State->OscEffectGenerator != NIL)
			{
				OscEffectKeyUpSustain1(State->OscEffectGenerator);
			}

		if (State->LoopState == eRepeatingLoop1)
			{
				if (State->Loop2Start != State->Loop2End)
					{
						State->LoopState = eRepeatingLoop2;
						State->CurrentLoopEnd = State->Loop2End;
						State->CurrentLoopLength = State->Loop2End - State->Loop2Start;
					}
				else if (State->Loop3Start != State->Loop3End)
					{
						State->LoopState = eRepeatingLoop3;
						State->CurrentLoopEnd = State->Loop3End;
						State->CurrentLoopLength = State->Loop3End - State->Loop3Start;
					}
				else
					{
						State->LoopState = eNoLoop;
						State->CurrentLoopEnd = State->NumFrames;
						State->CurrentLoopLength = 0;
					}
			}
	}


/* send a key-up signal to one of the oscillators */
void									SampleKeyUpSustain2(SampleStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(State);

		LFOGeneratorKeyUpSustain2(State->LoudnessLFOGenerator);
		EnvelopeKeyUpSustain2(State->SampleLoudnessEnvelope);
		LFOGeneratorKeyUpSustain2(State->PitchLFO);
		if (State->OscEffectGenerator != NIL)
			{
				OscEffectKeyUpSustain2(State->OscEffectGenerator);
			}

		if (/*(State->LoopState == eRepeatingLoop1)*/
			/*||*/ (State->LoopState == eRepeatingLoop2))
			{
				if (State->Loop3Start != State->Loop3End)
					{
						State->LoopState = eRepeatingLoop3;
						State->CurrentLoopEnd = State->Loop3End;
						State->CurrentLoopLength = State->Loop3End - State->Loop3Start;
					}
				else
					{
						State->LoopState = eNoLoop;
						State->CurrentLoopEnd = State->NumFrames;
						State->CurrentLoopLength = 0;
					}
			}
	}


/* send a key-up signal to one of the oscillators */
void									SampleKeyUpSustain3(SampleStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(State);

		LFOGeneratorKeyUpSustain3(State->LoudnessLFOGenerator);
		EnvelopeKeyUpSustain3(State->SampleLoudnessEnvelope);
		LFOGeneratorKeyUpSustain3(State->PitchLFO);
		if (State->OscEffectGenerator != NIL)
			{
				OscEffectKeyUpSustain3(State->OscEffectGenerator);
			}

		if (/*(State->LoopState == eRepeatingLoop1)*/
			/*|| (State->LoopState == eRepeatingLoop2)*/
			/*||*/ (State->LoopState == eRepeatingLoop3))
			{
				State->LoopState = eNoLoop;
				State->CurrentLoopEnd = State->NumFrames;
				State->CurrentLoopLength = 0;
			}
	}


/* restart a sample oscillator.  this is used for tie continuations */
void									RestartSampleState(SampleStateRec* State,
												float NewFreqMultisampling, AccentParam* NewAccents,
												float NewLoudness, float NewHurryUp, MyBoolean RetriggerEnvelopes,
												float NewStereoPosition, float NewInitialFrequency,
												float PitchDisplacementDepthLimit,
												float PitchDisplacementRateLimit,
												long PitchDisplacementStartPoint)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(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->SampleLoudnessEnvelope,NewAccents,
			NewInitialFrequency,1,NewHurryUp,
			State->Template.EnvelopeTicksPerSecond,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 a sequence of samples (called for each envelope clock) */
void									SampleGenSamples(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer,
												largefixedsigned* PrivateWorkspace)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(State);

		if (State->PreStartCountdown <= 0)
			{
				if (State->OscEffectGenerator == NIL)
					{
						/* normal case */
						if (State->LoopState != eSampleFinished)
							{
								(*State->SampleGenSamples)(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 */
						if (State->LoopState != eSampleFinished)
							{
								(*State->SampleGenSamples)(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 sample oscillator has finished */
MyBoolean							SampleIsItFinished(SampleStateRec* State)
	{
		CheckPtrExistence(State);
		CheckValidSampleState(State);

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

		return False;
	}


static void						Sample_MonoOut_MonoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed char*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

		while (SampleCount > 0)
			{
				PRNGCHK(SampleData,&(SampleData[LongLongHighHalf(LocalSamplePosition)]),
					sizeof(SampleData[LongLongHighHalf(LocalSamplePosition)]));
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalOverallLoudness,
					SampleData[LongLongHighHalf(LocalSamplePosition)]);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_MonoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed char*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

		while (SampleCount > 0)
			{
				signed long					SamplePoint;

				PRNGCHK(SampleData,&(SampleData[LongLongHighHalf(LocalSamplePosition)]),
					sizeof(SampleData[LongLongHighHalf(LocalSamplePosition)]));
				SamplePoint = SampleData[LongLongHighHalf(LocalSamplePosition)];
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalLeftLoudness,SamplePoint);
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalRightLoudness,SamplePoint);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_MonoOut_StereoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed char*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

		while (SampleCount > 0)
			{
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]));
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]));
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalOverallLoudness,
					((signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]
					+ (signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]) >> 1);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_StereoSamp_8BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed char*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

		while (SampleCount > 0)
			{
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]));
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalLeftLoudness,
					(signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]);
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]));
				*(RawBuffer++) += FastFixedTimes8BitTo24Bit(LocalRightLoudness,
					(signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_MonoOut_MonoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed short*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

		while (SampleCount > 0)
			{
				PRNGCHK(SampleData,&(SampleData[LongLongHighHalf(LocalSamplePosition)]),
					sizeof(SampleData[LongLongHighHalf(LocalSamplePosition)]));
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,
					SampleData[LongLongHighHalf(LocalSamplePosition)]);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_MonoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed short*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

		while (SampleCount > 0)
			{
				signed long					SamplePoint;

				PRNGCHK(SampleData,&(SampleData[LongLongHighHalf(LocalSamplePosition)]),
					sizeof(SampleData[LongLongHighHalf(LocalSamplePosition)]));
				SamplePoint = SampleData[LongLongHighHalf(LocalSamplePosition)];
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,SamplePoint);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,SamplePoint);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_MonoOut_StereoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed short*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

		while (SampleCount > 0)
			{
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]));
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]));
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,
					((signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]
					+ (signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]) >> 1);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_StereoSamp_16BitIn_NoTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed short*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

		while (SampleCount > 0)
			{
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]));
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,
					(signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 0]);
				PRNGCHK(SampleData,&(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]),
					sizeof(SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]));
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,
					(signed long)SampleData[2 * LongLongHighHalf(LocalSamplePosition) + 1]);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_MonoOut_MonoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed char*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[ArraySubscript]),
					sizeof(SampleData[ArraySubscript]));
				LeftValue = ((signed long)SampleData[ArraySubscript]) << 8; /* convert to 16-bit */
				PRNGCHK(SampleData,&(SampleData[ArraySubscript + 1]),
					sizeof(SampleData[ArraySubscript + 1]));
				RightValue = ((signed long)SampleData[ArraySubscript + 1]) << 8; /* to 16-bit */
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_MonoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed char*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[ArraySubscript]),
					sizeof(SampleData[ArraySubscript]));
				LeftValue = ((signed long)SampleData[ArraySubscript]) << 8; /* convert to 16-bit */
				PRNGCHK(SampleData,&(SampleData[ArraySubscript + 1]),
					sizeof(SampleData[ArraySubscript + 1]));
				RightValue = ((signed long)SampleData[ArraySubscript + 1]) << 8; /* to 16-bit */
				CombinedValue = LeftValue + ((LeftWeight * (RightValue - LeftValue)) >> 15);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,CombinedValue);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,CombinedValue);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_MonoOut_StereoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed char*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[2 * ArraySubscript + 0]),
					sizeof(SampleData[2 * ArraySubscript + 0]));
				PRNGCHK(SampleData,&(SampleData[2 * ArraySubscript + 1]),
					sizeof(SampleData[2 * ArraySubscript + 1]));
				LeftValue = ((signed long)SampleData[2 * ArraySubscript + 0]
					+ (signed long)SampleData[2 * ArraySubscript + 1]) << 7; /* convert to 16-bit */
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1) + 0]),
					sizeof(SampleData[2 * (ArraySubscript + 1) + 0]));
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1) + 1]),
					sizeof(SampleData[2 * (ArraySubscript + 1) + 1]));
				RightValue = ((signed long)SampleData[2 * (ArraySubscript + 1) + 0]
					+ (signed long)SampleData[2 * (ArraySubscript + 1) + 1]) << 7; /* to 16-bit */
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_StereoSamp_8BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed char*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed char*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 0)]),
					sizeof(SampleData[2 * (ArraySubscript + 0)]));
				LeftValue = ((signed long)SampleData[2 * (ArraySubscript + 0)]) << 8; /* convert to 16-bit */
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1)]),
					sizeof(SampleData[2 * (ArraySubscript + 1)]));
				RightValue = ((signed long)SampleData[2 * (ArraySubscript + 1)]) << 8; /* to 16-bit */
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 0) + 1]),
					sizeof(SampleData[2 * (ArraySubscript + 0) + 1]));
				LeftValue = ((signed long)SampleData[2 * (ArraySubscript + 0) + 1]) << 8; /* convert to 16-bit */
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1) + 1]),
					sizeof(SampleData[2 * (ArraySubscript + 1) + 1]));
				RightValue = ((signed long)SampleData[2 * (ArraySubscript + 1) + 1]) << 8; /* to 16-bit */
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_MonoOut_MonoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed short*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[ArraySubscript]),
					sizeof(SampleData[ArraySubscript]));
				LeftValue = SampleData[ArraySubscript];
				PRNGCHK(SampleData,&(SampleData[ArraySubscript + 1]),
					sizeof(SampleData[ArraySubscript + 1]));
				RightValue = SampleData[ArraySubscript + 1];
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_MonoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed short*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[ArraySubscript]),
					sizeof(SampleData[ArraySubscript]));
				LeftValue = SampleData[ArraySubscript];
				PRNGCHK(SampleData,&(SampleData[ArraySubscript + 1]),
					sizeof(SampleData[ArraySubscript + 1]));
				RightValue = SampleData[ArraySubscript + 1];
				CombinedValue = LeftValue + ((LeftWeight * (RightValue - LeftValue)) >> 15);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,CombinedValue);
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,CombinedValue);
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_MonoOut_StereoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalOverallLoudness;
		signed short*				SampleData;

		LocalOverallLoudness = State->OverallLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[2 * ArraySubscript + 0]),
					sizeof(SampleData[2 * ArraySubscript + 0]));
				PRNGCHK(SampleData,&(SampleData[2 * ArraySubscript + 1]),
					sizeof(SampleData[2 * ArraySubscript + 1]));
				LeftValue = ((signed long)SampleData[2 * ArraySubscript + 0]
					+ (signed long)SampleData[2 * ArraySubscript + 1]) >> 1;
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1) + 0]),
					sizeof(SampleData[2 * (ArraySubscript + 1) + 0]));
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1) + 1]),
					sizeof(SampleData[2 * (ArraySubscript + 1) + 1]));
				RightValue = ((signed long)SampleData[2 * (ArraySubscript + 1) + 0]
					+ (signed long)SampleData[2 * (ArraySubscript + 1) + 1]) >> 1;
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalOverallLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_StereoOut_StereoSamp_16BitIn_YesTime(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
		LongLongRec					LocalSamplePosition;
		LongLongRec					LocalSamplePositionDifferential;
		long								LocalCurrentLoopEnd;
		FastFixedType				LocalLeftLoudness;
		FastFixedType				LocalRightLoudness;
		signed short*				SampleData;

		LocalLeftLoudness = State->LeftLoudness;
		LocalRightLoudness = State->RightLoudness;
		LocalSamplePosition = State->SamplePosition;
		LocalSamplePositionDifferential = State->SamplePositionDifferential;
		LocalCurrentLoopEnd = State->CurrentLoopEnd;
		SampleData = (signed short*)State->Data;

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

				/* L+F(R-L) */
				LeftWeight = LongLongLowHalf(LocalSamplePosition) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(LocalSamplePosition);
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 0)]),
					sizeof(SampleData[2 * (ArraySubscript + 0)]));
				LeftValue = SampleData[2 * (ArraySubscript + 0)];
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1)]),
					sizeof(SampleData[2 * (ArraySubscript + 1)]));
				RightValue = SampleData[2 * (ArraySubscript + 1)];
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalLeftLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 0) + 1]),
					sizeof(SampleData[2 * (ArraySubscript + 0) + 1]));
				LeftValue = SampleData[2 * (ArraySubscript + 0) + 1];
				PRNGCHK(SampleData,&(SampleData[2 * (ArraySubscript + 1) + 1]),
					sizeof(SampleData[2 * (ArraySubscript + 1) + 1]));
				RightValue = SampleData[2 * (ArraySubscript + 1) + 1];
				*(RawBuffer++) += FastFixedTimes16BitTo24Bit(LocalRightLoudness,LeftValue
					+ ((LeftWeight * (RightValue - LeftValue)) >> 15));
				LongLongAdd(&LocalSamplePosition,&LocalSamplePositionDifferential);
			 CheapDoLoop:
				if (LongLongHighHalf(LocalSamplePosition) >= LocalCurrentLoopEnd)
					{
						if (State->LoopState != eNoLoop)
							{
								/* handle loop */
								LongLongSetHighHalf(LocalSamplePosition,LongLongHighHalf(
									LocalSamplePosition) - State->CurrentLoopLength);
								goto CheapDoLoop;
							}
						 else
							{
								/* end of sample -- terminate */
								State->LoopState = eSampleFinished;
								goto BreakLoopPoint;
							}
					}
				SampleCount -= 1;
			}
	 BreakLoopPoint:
		;

		State->SamplePosition = LocalSamplePosition;
	}


static void						Sample_NoOutput(SampleStateRec* State,
												long SampleCount, largefixedsigned* RawBuffer)
	{
	}
