/* LFOGenerator.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 "LFOGenerator.h"
#include "Memory.h"
#include "EnvelopeState.h"
#include "LFOSpecifier.h"
#include "LFOListSpecifier.h"
#include "FloatingPoint.h"
#include "RandomNumbers.h"
#include "Frequency.h"
#include "Multisampler.h"
#include "64BitMath.h"
#include "SampleConsts.h"
#include "WaveIndexUtility.h"


#define TWOPI ((float)6.28318530717958648)


typedef struct LFOOneStateRec
	{
		/* pointer to the LFO generating function */
		float										(*GenFunction)(struct LFOOneStateRec* State, float Phase,
															float OriginalValue, float Amplitude,
															float OscillatorFrequency);

		/* phase index counter */
		FastFixedType						CurrentPhase;

		/* the envelope controlling the amplitude. */
		EvalEnvelopeRec*				LFOAmplitudeEnvelope;
		/* the envelope controlling the frequency.  the value from here is periods per second */
		EvalEnvelopeRec*				LFOFrequencyEnvelope;
		/* the lfo augmenting the amplitude */
		LFOGenRec*							LFOAmplitudeLFOGenerator;
		/* the lfo augmenting the frequency */
		LFOGenRec*							LFOFrequencyLFOGenerator;

		/* if this is True, then modulation is linear, otherwise modulation is */
		/* exponential */
		LFOArithSelect					ModulationMode;

		/* what kind of operator are we using */
		LFOOscTypes							Operator;

		/* source information for the wave table */
		MultiSampleRec*					WaveTableSourceSelector;

		/* this is true if the wave table was defined */
		MyBoolean								WaveTableWasDefined;
		/* number of frames per table */
		long										FramesPerTable;
		/* number of tables */
		long										NumberOfTables;
		/* raw wave table data array */
		void**									WaveTableMatrix;
		/* function for indexing the wave table */
		signed long							(*WaveIndexer)(float Phase, FastFixedType TableIndex,
															long NumTables, long Frames, void** Matrix);
		/* number of bits in the data for the table */
		NumBitsType							TableNumBits;
		/* envelope controlling wave table index */
		EvalEnvelopeRec*				WaveTableIndexEnvelope;
		/* lfo processing the wave table index */
		LFOGenRec*							WaveTableLFOGenerator;

		/* modulation method */
		LFOModulationTypes			ModulationMethod;

		/* special extra value */
		double									ExtraValue;
		/* envelope ticks per second */
		float										TicksPerSecond;
		/* previous noise value */
		float										LeftNoise;
		/* next noise value */
		float										RightNoise;
		/* random number generator seed */
		long										RandomSeed;

		/* link to the next one */
		struct LFOOneStateRec*	Next;
	} LFOOneStateRec;


struct LFOGenRec
	{
		/* list of single LFO entries, which we sum up. */
		LFOOneStateRec*					LFOList;

		/* number of envelope clock pulses per second */
		float										EnvelopeTicksPerSecond;

		/* link for caching records */
		LFOGenRec*							GarbageLink;
	};


/* prototypes */
static float						AddConst(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddSignSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddPosSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddSignTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddPosTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddSignSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddPosSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddSignRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddPosRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddSignFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddPosFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddSignFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddPosFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						AddWaveTable(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultConst(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultSignSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultPosSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultSignTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultPosTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultSignSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultPosSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultSignRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultPosRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultSignFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultPosFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultSignFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultPosFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						MultWaveTable(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultConst(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultSignSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultPosSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultSignTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultPosTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultSignSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultPosSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultSignRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultPosRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultSignFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultPosFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultSignFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultPosFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);
static float						InvMultWaveTable(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency);


static LFOGenRec*					LFOGenFreeList = NIL;
static LFOOneStateRec*		LFOOneStateFreeList = NIL;


/* flush cached LFO generator records */
void								FlushLFOGeneratorRecords(void)
	{
		while (LFOGenFreeList != NIL)
			{
				LFOGenRec*				Temp;

				Temp = LFOGenFreeList;
				LFOGenFreeList = LFOGenFreeList->GarbageLink;
				ReleasePtr((char*)Temp);
			}

		while (LFOOneStateFreeList != NIL)
			{
				LFOOneStateRec*		Temp;

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


#if DEBUG
static void					ValidateLFOGen(LFOGenRec* LFOGen)
	{
		LFOGenRec*				Scan;

		Scan = LFOGenFreeList;
		while (Scan != NIL)
			{
				if (Scan == LFOGen)
					{
						PRERR(ForceAbort,"ValidateLFOGen:  it's on the free list");
					}
				Scan = Scan->GarbageLink;
			}
	}
#else
#define ValidateLFOGen(x) ((void)0)
#endif


#if DEBUG
static void					ValidateLFOOneState(LFOOneStateRec* OneState)
	{
		LFOOneStateRec*		Scan;

		Scan = LFOOneStateFreeList;
		while (Scan != NIL)
			{
				if (Scan == OneState)
					{
						PRERR(ForceAbort,"ValidateLFOOneState:  it's on the free list");
					}
				Scan = Scan->Next;
			}
	}
#else
#define ValidateLFOOneState(x) ((void)0)
#endif


/* create a new LFO generator based on a list of specifications */
/* it returns the largest pre-origin time for all of the envelopes it contains */
/* AmplitudeScaling and FrequencyScaling are provided primarily for frequency */
/* LFO control; other LFOs are controlled through the accent parameters, and */
/* should supply 1 (no scaling) for these parameters. */
LFOGenRec*					NewLFOGenerator(struct LFOListSpecRec* LFOListSpec,
											long* MaxPreOriginTime, AccentParam* Accents, float FrequencyHertz,
											float HurryUp, float TicksPerSecond, float AmplitudeScaling,
											float FrequencyScaling, float FreqForMultisampling)
	{
		LFOGenRec*				LFOGen;
		long							ListLimit;
		long							ListScan;
		LFOOneStateRec*		ListTail;
		long							MaxPreOrigin;

		CheckPtrExistence(LFOListSpec);
		if (LFOGenFreeList != NIL)
			{
				LFOGen = LFOGenFreeList;
				LFOGenFreeList = LFOGenFreeList->GarbageLink;
			}
		 else
			{
				LFOGen = (LFOGenRec*)AllocPtrCanFail(sizeof(LFOGenRec),"LFOGenRec");
				if (LFOGen == NIL)
					{
						return NIL;
					}
			}

		/* remember the envelope rate */
		LFOGen->EnvelopeTicksPerSecond = TicksPerSecond;

		/* build the list of thingers */
		LFOGen->LFOList = NIL;
		ListTail = NIL;
		ListLimit = LFOListSpecGetNumElements(LFOListSpec);
		MaxPreOrigin = 0;
		for (ListScan = 0; ListScan < ListLimit; ListScan += 1)
			{
				LFOSpecRec*				OneLFOSpec;
				LFOOneStateRec*		ListNode;
				long							PreOriginTime;

				/* allocate an entry */
				if (LFOOneStateFreeList != NIL)
					{
						ListNode = LFOOneStateFreeList;
						LFOOneStateFreeList = LFOOneStateFreeList->Next;
					}
				 else
					{
						ListNode = (LFOOneStateRec*)AllocPtrCanFail(sizeof(LFOOneStateRec),
							"LFOOneStateRec");
						if (ListNode == NIL)
							{
							 FailurePoint1:
								while (LFOGen->LFOList != NIL)
									{
										ListNode = LFOGen->LFOList;
										LFOGen->LFOList = LFOGen->LFOList->Next;
										DisposeEnvelopeStateRecord(ListNode->LFOAmplitudeEnvelope);
										DisposeEnvelopeStateRecord(ListNode->LFOFrequencyEnvelope);
										DisposeLFOGenerator(ListNode->LFOAmplitudeLFOGenerator);
										DisposeLFOGenerator(ListNode->LFOFrequencyLFOGenerator);
										if (ListNode->Operator == eLFOWaveTable)
											{
												DisposeMultisample(ListNode->WaveTableSourceSelector);
												DisposeEnvelopeStateRecord(ListNode->WaveTableIndexEnvelope);
												DisposeLFOGenerator(ListNode->WaveTableLFOGenerator);
											}
										ListNode->Next = LFOOneStateFreeList;
										LFOOneStateFreeList = ListNode;
									}
								LFOGen->GarbageLink = LFOGenFreeList;
								LFOGenFreeList = LFOGen;
								return NIL;
							}
					}
				/* initialize phase index */
				ListNode->CurrentPhase = 0;
				/* get the data to put in it */
				OneLFOSpec = LFOListSpecGetLFOSpec(LFOListSpec,ListScan);
				/* Add frequency envelope generator */
				ListNode->LFOFrequencyEnvelope = NewEnvelopeStateRecord(
					GetLFOSpecFrequencyEnvelope(OneLFOSpec),Accents,
					FrequencyHertz,FrequencyScaling,HurryUp,TicksPerSecond,&PreOriginTime);
				if (ListNode->LFOFrequencyEnvelope == NIL)
					{
					 FailurePoint2:
						ListNode->Next = LFOOneStateFreeList;
						LFOOneStateFreeList = ListNode;
						goto FailurePoint1;
					}
				if (PreOriginTime > MaxPreOrigin)
					{
						MaxPreOrigin = PreOriginTime;
					}
				/* determine what mode to use and calculate amplitude */
				switch (LFOSpecGetAddingMode(OneLFOSpec))
					{
						default:
							EXECUTE(PRERR(ForceAbort,
								"NewLFOGenerator:  bad value from LFOSpecGetAddingMode"));
							break;
						case eLFOArithmetic:
							ListNode->ModulationMode = eLFOArithAdditive;
							break;
						case eLFOGeometric:
							ListNode->ModulationMode = eLFOArithGeometric;
							break;
						case eLFOHalfSteps:
							ListNode->ModulationMode = eLFOArithHalfSteps;
							break;
					}
				/* add the amplitude envelope generator */
				ListNode->LFOAmplitudeEnvelope = NewEnvelopeStateRecord(
					GetLFOSpecAmplitudeEnvelope(OneLFOSpec),Accents,
					FrequencyHertz,AmplitudeScaling,HurryUp,TicksPerSecond,&PreOriginTime);
				if (ListNode->LFOAmplitudeEnvelope == NIL)
					{
					 FailurePoint3:
						DisposeEnvelopeStateRecord(ListNode->LFOFrequencyEnvelope);
						goto FailurePoint2;
					}
				if (PreOriginTime > MaxPreOrigin)
					{
						MaxPreOrigin = PreOriginTime;
					}
				/* add the frequency lfo modulator */
				ListNode->LFOFrequencyLFOGenerator = NewLFOGenerator(GetLFOSpecFrequencyLFOList(
					OneLFOSpec),&PreOriginTime,Accents,FrequencyHertz,
					HurryUp,TicksPerSecond,1,1/*no recursive amplitude or frequency scaling*/,
					FreqForMultisampling);
				if (ListNode->LFOFrequencyLFOGenerator == NIL)
					{
					 FailurePoint3a:
						DisposeEnvelopeStateRecord(ListNode->LFOAmplitudeEnvelope);
						goto FailurePoint3;
					}
				if (PreOriginTime > MaxPreOrigin)
					{
						MaxPreOrigin = PreOriginTime;
					}
				/* add the amplitude lfo modulator */
				ListNode->LFOAmplitudeLFOGenerator = NewLFOGenerator(GetLFOSpecAmplitudeLFOList(
					OneLFOSpec),&PreOriginTime,Accents,FrequencyHertz,
					HurryUp,TicksPerSecond,1,1/*no recursive amplitude or frequency scaling*/,
					FreqForMultisampling);
				if (ListNode->LFOAmplitudeLFOGenerator == NIL)
					{
					 FailurePoint3b:
						DisposeLFOGenerator(ListNode->LFOFrequencyLFOGenerator);
						goto FailurePoint3a;
					}
				if (PreOriginTime > MaxPreOrigin)
					{
						MaxPreOrigin = PreOriginTime;
					}
				/* determine what function to use */
				ListNode->Operator = LFOSpecGetOscillatorType(OneLFOSpec);
				ListNode->ModulationMethod = LFOSpecGetModulationMode(OneLFOSpec);
				switch (ListNode->Operator)
					{
						default:
							EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad oscillator type"));
							break;
						case eLFOConstant1:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddConst;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultConst;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultConst;
										break;
								}
							break;
						case eLFOSignedSine:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddSignSine;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultSignSine;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultSignSine;
										break;
								}
							break;
						case eLFOPositiveSine:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddPosSine;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultPosSine;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultPosSine;
										break;
								}
							break;
						case eLFOSignedTriangle:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddSignTriangle;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultSignTriangle;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultSignTriangle;
										break;
								}
							break;
						case eLFOPositiveTriangle:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddPosTriangle;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultPosTriangle;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultPosTriangle;
										break;
								}
							break;
						case eLFOSignedSquare:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddSignSquare;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultSignSquare;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultSignSquare;
										break;
								}
							break;
						case eLFOPositiveSquare:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddPosSquare;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultPosSquare;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultPosSquare;
										break;
								}
							break;
						case eLFOSignedRamp:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddSignRamp;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultSignRamp;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultSignRamp;
										break;
								}
							break;
						case eLFOPositiveRamp:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddPosRamp;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultPosRamp;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultPosRamp;
										break;
								}
							break;
						case eLFOSignedLinearFuzzTriangle:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddSignFuzzTriangle;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultSignFuzzTriangle;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultSignFuzzTriangle;
										break;
								}
							break;
						case eLFOSignedLinearFuzzSquare:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddSignFuzzSquare;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultSignFuzzSquare;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultSignFuzzSquare;
										break;
								}
							break;
						case eLFOPositiveLinearFuzzTriangle:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddPosFuzzTriangle;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultPosFuzzTriangle;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultPosFuzzTriangle;
										break;
								}
							break;
						case eLFOPositiveLinearFuzzSquare:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddPosFuzzSquare;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultPosFuzzSquare;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultPosFuzzSquare;
										break;
								}
							break;
						case eLFOWaveTable:
							switch (ListNode->ModulationMethod)
								{
									default:
										EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad modulation type"));
										break;
									case eLFOAdditive:
										ListNode->GenFunction = &AddWaveTable;
										break;
									case eLFOMultiplicative:
										ListNode->GenFunction = &MultWaveTable;
										break;
									case eLFOInverseMultiplicative:
										ListNode->GenFunction = &InvMultWaveTable;
										break;
								}
							ListNode->WaveTableSourceSelector = NewMultisampleWaveTable(
								GetLFOSpecSampleSelector(OneLFOSpec));
							if (ListNode->WaveTableSourceSelector == NIL)
								{
								 FailurePoint4:
									DisposeLFOGenerator(ListNode->LFOAmplitudeLFOGenerator);
									goto FailurePoint3b;
								}
							ListNode->WaveTableWasDefined = GetMultisampleReferenceWaveTable(
								ListNode->WaveTableSourceSelector,FreqForMultisampling,
								&(ListNode->WaveTableMatrix),&(ListNode->FramesPerTable),
								&(ListNode->NumberOfTables),&(ListNode->TableNumBits));
							if (ListNode->WaveTableWasDefined)
								{
									switch (ListNode->TableNumBits)
										{
											default:
												EXECUTE(PRERR(ForceAbort,"NewLFOGenerator:  bad num bits"));
												break;
											case eSample8bit:
												ListNode->WaveIndexer = (signed long (*)(float,
													FastFixedType,long,long,void**))&WaveTable8Bit;
												break;
											case eSample16bit:
												ListNode->WaveIndexer = (signed long (*)(float,
													FastFixedType,long,long,void**))&WaveTable16Bit;
												break;
										}
								}
							ListNode->WaveTableIndexEnvelope = NewEnvelopeStateRecord(
								GetLFOSpecWaveTableIndexEnvelope(OneLFOSpec),Accents,
								FrequencyHertz,1,HurryUp,TicksPerSecond,&PreOriginTime);
							if (ListNode->WaveTableIndexEnvelope == NIL)
								{
								 FailurePoint5:
									DisposeMultisample(ListNode->WaveTableSourceSelector);
									goto FailurePoint4;
								}
							if (PreOriginTime > MaxPreOrigin)
								{
									MaxPreOrigin = PreOriginTime;
								}
							/* add the index lfo modulator */
							ListNode->WaveTableLFOGenerator = NewLFOGenerator(
								GetLFOSpecWaveTableIndexLFOList(OneLFOSpec),&PreOriginTime,Accents,
								FrequencyHertz,HurryUp,TicksPerSecond,
								1,1/*no recursive amplitude or frequency scaling*/,FreqForMultisampling);
							if (ListNode->WaveTableLFOGenerator == NIL)
								{
								 FailurePoint6:
									DisposeEnvelopeStateRecord(ListNode->WaveTableIndexEnvelope);
									goto FailurePoint5;
								}
							if (PreOriginTime > MaxPreOrigin)
								{
									MaxPreOrigin = PreOriginTime;
								}
							break;
					}
				/* set up special values */
				ListNode->ExtraValue = GetLFOSpecExtraValue(OneLFOSpec);
				ListNode->TicksPerSecond = TicksPerSecond;
				if ((ListNode->Operator == eLFOSignedLinearFuzzTriangle)
					|| (ListNode->Operator == eLFOPositiveLinearFuzzTriangle)
					|| (ListNode->Operator == eLFOSignedLinearFuzzSquare)
					|| (ListNode->Operator == eLFOPositiveLinearFuzzSquare))
					{
						long									OldSeed;
						long									StartingSeed;

						StartingSeed = GetLFOSpecExtraValue(OneLFOSpec);
						if (StartingSeed < PARKANDMILLERMINIMUM)
							{
								StartingSeed = PARKANDMILLERMINIMUM;
							}
						if (StartingSeed > PARKANDMILLERMAXIMUM)
							{
								StartingSeed = PARKANDMILLERMAXIMUM;
							}
						OldSeed = SetParkAndMillerRandomSeed(StartingSeed);
						ListNode->LeftNoise = ((float)ParkAndMillerRandom() - PARKANDMILLERMINIMUM)
							/ (PARKANDMILLERMAXIMUM - PARKANDMILLERMINIMUM - 1);
						ListNode->RightNoise = ((float)ParkAndMillerRandom() - PARKANDMILLERMINIMUM)
							/ (PARKANDMILLERMAXIMUM - PARKANDMILLERMINIMUM - 1);
						ListNode->RandomSeed = SetParkAndMillerRandomSeed(OldSeed);
					}
				/* link it in */
				ListNode->Next = NIL;
				if (ListTail != NIL)
					{
						ListTail->Next = ListNode;
					}
				 else
					{
						LFOGen->LFOList = ListNode;
					}
				ListTail = ListNode;
			}

		*MaxPreOriginTime = MaxPreOrigin;
		return LFOGen;
	}


/* fix up the origin time so that envelopes start at the proper times */
void								LFOGeneratorFixEnvelopeOrigins(LFOGenRec* LFOGen,
											long ActualPreOriginTime)
	{
		LFOOneStateRec*		Scan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);

		Scan = LFOGen->LFOList;
		while (Scan != NIL)
			{
				ValidateLFOOneState(Scan);
				EnvelopeStateFixUpInitialDelay(Scan->LFOAmplitudeEnvelope,ActualPreOriginTime);
				EnvelopeStateFixUpInitialDelay(Scan->LFOFrequencyEnvelope,ActualPreOriginTime);
				LFOGeneratorFixEnvelopeOrigins(Scan->LFOAmplitudeLFOGenerator,
					ActualPreOriginTime);
				LFOGeneratorFixEnvelopeOrigins(Scan->LFOFrequencyLFOGenerator,
					ActualPreOriginTime);
				if (Scan->Operator == eLFOWaveTable)
					{
						EnvelopeStateFixUpInitialDelay(Scan->WaveTableIndexEnvelope,
							ActualPreOriginTime);
						LFOGeneratorFixEnvelopeOrigins(Scan->WaveTableLFOGenerator,
							ActualPreOriginTime);
					}
				Scan = Scan->Next;
			}
	}


/* this function computes one LFO cycle and returns the value from the LFO generator. */
/* it should be called on the envelope clock. */
FastFixedType				LFOGenUpdateCycle(LFOGenRec* LFOGen, FastFixedType OriginalValue,
											float OscillatorFrequency)
	{
		LFOOneStateRec*		Scan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);

		Scan = LFOGen->LFOList;
		if (Scan != NIL)
			{
				float							Iterator;

				Iterator = FastFixed2Float(OriginalValue);
				while (Scan != NIL)
					{
						float							VariantAmplitude;
						float							VariantPhase;

						/* compute amplitude envelope/lfo thing */
						VariantAmplitude = FastFixed2Float(LFOGenUpdateCycle(
							Scan->LFOAmplitudeLFOGenerator,
							EnvelopeUpdate(Scan->LFOAmplitudeEnvelope,OscillatorFrequency),
							OscillatorFrequency));
						VariantPhase = FastFixed2Float(Scan->CurrentPhase);
						/* perform the calculations */
						switch (Scan->ModulationMode)
							{
								default:
									EXECUTE(PRERR(AllowResume,
										"LFOGenUpdateCycle:  bad value for ModulationMode"));
									break;
								case eLFOArithAdditive:
									Iterator = (*Scan->GenFunction)(Scan,VariantPhase,
										Iterator,VariantAmplitude,OscillatorFrequency);
									break;
								case eLFOArithGeometric:
									{
										MyBoolean					Sign;

										Sign = (Iterator < 0);
										if (Sign)
											{
												Iterator = - Iterator;
											}
										if (Iterator != 0)
											{
												/* the LOG2 is to normalize the values, so that 1/12 will */
												/* be 1 halfstep */
												Iterator = (float)FEXP((*Scan->GenFunction)(Scan,
													VariantPhase,(float)FLN(Iterator),
													VariantAmplitude * (float)LOG2,OscillatorFrequency));
											}
										if (Sign)
											{
												Iterator = - Iterator;
											}
									}
									break;
								case eLFOArithHalfSteps:
									{
										MyBoolean					Sign;

										Sign = (Iterator < 0);
										if (Sign)
											{
												Iterator = - Iterator;
											}
										if (Iterator != 0)
											{
												/* the LOG2 is to normalize the values, so that 1/12 will */
												/* be 1 halfstep */
												Iterator = (float)FEXP((*Scan->GenFunction)(Scan,
													VariantPhase,(float)FLN(Iterator),
													VariantAmplitude * (float)LOG2 / 12,OscillatorFrequency));
											}
										if (Sign)
											{
												Iterator = - Iterator;
											}
									}
									break;
							}
						Scan->CurrentPhase = Scan->CurrentPhase  + (float)LFOGenUpdateCycle(
							Scan->LFOFrequencyLFOGenerator,EnvelopeUpdate(
							Scan->LFOFrequencyEnvelope,OscillatorFrequency),OscillatorFrequency)
							/ LFOGen->EnvelopeTicksPerSecond;
						if ((Scan->Operator == eLFOSignedLinearFuzzTriangle)
							|| (Scan->Operator == eLFOPositiveLinearFuzzTriangle)
							|| (Scan->Operator == eLFOSignedLinearFuzzSquare)
							|| (Scan->Operator == eLFOPositiveLinearFuzzSquare))
							{
								long							Counter;
								long							OldSeed;

								OldSeed = SetParkAndMillerRandomSeed(Scan->RandomSeed);
								for (Counter = Scan->CurrentPhase >> FASTFIXEDPRECISION;
									Counter >= 1; Counter -= 1)
									{
										Scan->LeftNoise = Scan->RightNoise;
										Scan->RightNoise = ((float)ParkAndMillerRandom()
											- PARKANDMILLERMINIMUM) / (PARKANDMILLERMAXIMUM
											- PARKANDMILLERMINIMUM - 1);
									}
								Scan->RandomSeed = SetParkAndMillerRandomSeed(OldSeed);
							}
						Scan->CurrentPhase = Scan->CurrentPhase & ((1L << FASTFIXEDPRECISION) - 1);
						/* go to next one */
						Scan = Scan->Next;
					}
				return Double2FastFixed(Iterator);
			}
		 else
			{
				return OriginalValue;
			}
	}


/* pass the key-up impulse on to the envelopes contained inside */
void								LFOGeneratorKeyUpSustain1(LFOGenRec* LFOGen)
	{
		LFOOneStateRec*		Scan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);

		Scan = LFOGen->LFOList;
		while (Scan != NIL)
			{
				EnvelopeKeyUpSustain1(Scan->LFOAmplitudeEnvelope);
				EnvelopeKeyUpSustain1(Scan->LFOFrequencyEnvelope);
				LFOGeneratorKeyUpSustain1(Scan->LFOAmplitudeLFOGenerator);
				LFOGeneratorKeyUpSustain1(Scan->LFOFrequencyLFOGenerator);
				if (Scan->Operator == eLFOWaveTable)
					{
						EnvelopeKeyUpSustain1(Scan->WaveTableIndexEnvelope);
						LFOGeneratorKeyUpSustain1(Scan->WaveTableLFOGenerator);
					}
				Scan = Scan->Next;
			}
	}


/* pass the key-up impulse on to the envelopes contained inside */
void								LFOGeneratorKeyUpSustain2(LFOGenRec* LFOGen)
	{
		LFOOneStateRec*		Scan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);

		Scan = LFOGen->LFOList;
		while (Scan != NIL)
			{
				EnvelopeKeyUpSustain2(Scan->LFOAmplitudeEnvelope);
				EnvelopeKeyUpSustain2(Scan->LFOFrequencyEnvelope);
				LFOGeneratorKeyUpSustain2(Scan->LFOAmplitudeLFOGenerator);
				LFOGeneratorKeyUpSustain2(Scan->LFOFrequencyLFOGenerator);
				if (Scan->Operator == eLFOWaveTable)
					{
						EnvelopeKeyUpSustain2(Scan->WaveTableIndexEnvelope);
						LFOGeneratorKeyUpSustain2(Scan->WaveTableLFOGenerator);
					}
				Scan = Scan->Next;
			}
	}


/* pass the key-up impulse on to the envelopes contained inside */
void								LFOGeneratorKeyUpSustain3(LFOGenRec* LFOGen)
	{
		LFOOneStateRec*		Scan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);

		Scan = LFOGen->LFOList;
		while (Scan != NIL)
			{
				EnvelopeKeyUpSustain3(Scan->LFOAmplitudeEnvelope);
				EnvelopeKeyUpSustain3(Scan->LFOFrequencyEnvelope);
				LFOGeneratorKeyUpSustain3(Scan->LFOAmplitudeLFOGenerator);
				LFOGeneratorKeyUpSustain3(Scan->LFOFrequencyLFOGenerator);
				if (Scan->Operator == eLFOWaveTable)
					{
						EnvelopeKeyUpSustain3(Scan->WaveTableIndexEnvelope);
						LFOGeneratorKeyUpSustain3(Scan->WaveTableLFOGenerator);
					}
				Scan = Scan->Next;
			}
	}


/* retrigger envelopes from the origin point */
void								LFOGeneratorRetriggerFromOrigin(LFOGenRec* LFOGen,
											AccentParam* Accents, float FrequencyHertz,
											float HurryUp, float AmplitudeScaling, float FrequencyScaling,
											MyBoolean ActuallyRetrigger)
	{
		LFOOneStateRec*		Scan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);

		Scan = LFOGen->LFOList;
		while (Scan != NIL)
			{
				EnvelopeRetriggerFromOrigin(Scan->LFOAmplitudeEnvelope,Accents,
					FrequencyHertz,AmplitudeScaling,HurryUp,
					LFOGen->EnvelopeTicksPerSecond,ActuallyRetrigger);
				EnvelopeRetriggerFromOrigin(Scan->LFOFrequencyEnvelope,Accents,
					FrequencyHertz,FrequencyScaling,HurryUp,
					LFOGen->EnvelopeTicksPerSecond,ActuallyRetrigger);
				LFOGeneratorRetriggerFromOrigin(Scan->LFOAmplitudeLFOGenerator,Accents,
					FrequencyHertz,HurryUp,1,1/*no recursive scaling*/,
					ActuallyRetrigger);
				LFOGeneratorRetriggerFromOrigin(Scan->LFOFrequencyLFOGenerator,Accents,
					FrequencyHertz,HurryUp,1,1/*no recursive scaling*/,
					ActuallyRetrigger);
				if (Scan->Operator == eLFOWaveTable)
					{
						EnvelopeRetriggerFromOrigin(Scan->WaveTableIndexEnvelope,Accents,
							FrequencyHertz,FrequencyScaling,HurryUp,
							LFOGen->EnvelopeTicksPerSecond,ActuallyRetrigger);
						LFOGeneratorRetriggerFromOrigin(Scan->WaveTableLFOGenerator,Accents,
							FrequencyHertz,HurryUp,1,1/*no recursive scaling*/,
							ActuallyRetrigger);
					}
				Scan = Scan->Next;
			}
	}


/* dispose the LFO generator */
void								DisposeLFOGenerator(LFOGenRec* LFOGen)
	{
		LFOOneStateRec*		StateScan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);

		StateScan = LFOGen->LFOList;

		/* dispose of the master record */
		LFOGen->GarbageLink = LFOGenFreeList;
		LFOGenFreeList = LFOGen;

		/* dispose of each element */
		while (StateScan != NIL)
			{
				LFOOneStateRec*		Temp;

				ValidateLFOOneState(StateScan);
				if (StateScan->Operator == eLFOWaveTable)
					{
						DisposeMultisample(StateScan->WaveTableSourceSelector);
						DisposeEnvelopeStateRecord(StateScan->WaveTableIndexEnvelope);
						DisposeLFOGenerator(StateScan->WaveTableLFOGenerator);
					}
				DisposeEnvelopeStateRecord(StateScan->LFOAmplitudeEnvelope);
				DisposeEnvelopeStateRecord(StateScan->LFOFrequencyEnvelope);
				DisposeLFOGenerator(StateScan->LFOAmplitudeLFOGenerator);
				DisposeLFOGenerator(StateScan->LFOFrequencyLFOGenerator);
				Temp = StateScan;
				StateScan = StateScan->Next;
				Temp->Next = LFOOneStateFreeList;
				LFOOneStateFreeList = Temp;
			}
	}


/* find out if LFO generator has started yet */
MyBoolean						HasLFOGeneratorStarted(LFOGenRec* LFOGen)
	{
		LFOOneStateRec*		StateScan;

		CheckPtrExistence(LFOGen);
		ValidateLFOGen(LFOGen);
		StateScan = LFOGen->LFOList;
		while (StateScan != NIL)
			{
				ValidateLFOOneState(StateScan);
				if (StateScan->Operator == eLFOWaveTable)
					{
						if (HasEnvelopeStartedYet(StateScan->WaveTableIndexEnvelope))
							{
								return True;
							}
						if (HasLFOGeneratorStarted(StateScan->WaveTableLFOGenerator))
							{
								return True;
							}
					}
				if (HasEnvelopeStartedYet(StateScan->LFOAmplitudeEnvelope))
					{
						return True;
					}
				if (HasEnvelopeStartedYet(StateScan->LFOFrequencyEnvelope))
					{
						return True;
					}
				if (HasLFOGeneratorStarted(StateScan->LFOAmplitudeLFOGenerator))
					{
						return True;
					}
				if (HasLFOGeneratorStarted(StateScan->LFOFrequencyLFOGenerator))
					{
						return True;
					}
				StateScan = StateScan->Next;
			}
		return False;
	}


static float						AddConst(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue + Amplitude;
	}


static float						AddSignSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue + Amplitude * FSIN(Phase * TWOPI);
	}


static float						AddPosSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue + Amplitude * 0.5 * (1 + FSIN(Phase * TWOPI));
	}


static float						AddSignTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < 0.25)
			{
			}
		else if (Phase < 0.75)
			{
				Phase = 0.5 - Phase;
			}
		else
			{
				Phase = Phase - 1;
			}
		return OriginalValue + Phase * 4 * Amplitude;
	}


static float						AddPosTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < 0.25)
			{
			}
		else if (Phase < 0.75)
			{
				Phase = 0.5 - Phase;
			}
		else
			{
				Phase = Phase - 1;
			}
		return OriginalValue + (Phase + .25) * 2 * Amplitude;
	}


static float						AddSignSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									Peak1;
		float									Peak2;
		float									Trough1;
		float									Trough2;

		Peak1 = State->ExtraValue / 4;
		if (Phase < Peak1)
			{
				return OriginalValue + Amplitude * (Phase / Peak1);
			}
		Peak2 = Peak1 + (.5 - State->ExtraValue / 2);
		if (Phase < Peak2)
			{
				return OriginalValue + Amplitude;
			}
		Trough1 = Peak2 + State->ExtraValue / 2;
		if (Phase < Trough1)
			{
				return OriginalValue + Amplitude * ((Trough1 - Phase) / Peak1 - 1);
			}
		Trough2 = 1 - State->ExtraValue / 4;
		if (Phase < Trough2)
			{
				return OriginalValue - Amplitude;
			}
		return OriginalValue + Amplitude * ((Phase - Trough2) / (State->ExtraValue / 4) - 1);
	}


static float						AddPosSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									Peak1;
		float									Peak2;
		float									Trough1;
		float									Trough2;

		Peak1 = State->ExtraValue / 4;
		if (Phase < Peak1)
			{
				return OriginalValue + Amplitude * .5 * (1 + (Phase / Peak1));
			}
		Peak2 = Peak1 + (.5 - State->ExtraValue / 2);
		if (Phase < Peak2)
			{
				return OriginalValue + Amplitude;
			}
		Trough1 = Peak2 + State->ExtraValue / 2;
		if (Phase < Trough1)
			{
				return OriginalValue + Amplitude * .5 * (1 + ((Trough1 - Phase) / Peak1 - 1));
			}
		Trough2 = 1 - State->ExtraValue / 4;
		if (Phase < Trough2)
			{
				return OriginalValue;
			}
		return OriginalValue + Amplitude * .5 * (1 + ((Phase - Trough2)
			/ (State->ExtraValue / 4) - 1));
	}


static float						AddSignRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < State->ExtraValue)
			{
				return OriginalValue + Amplitude * (1 - 2 * (Phase / State->ExtraValue));
			}
		 else
			{
				return OriginalValue + Amplitude * (2 * ((Phase - State->ExtraValue)
					/ (1 - State->ExtraValue)) - 1);
			}
	}


static float						AddPosRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < State->ExtraValue)
			{
				return OriginalValue + Amplitude * (1 - Phase / State->ExtraValue);
			}
		 else
			{
				return OriginalValue + Amplitude * ((Phase - State->ExtraValue)
					/ (1 - State->ExtraValue));
			}
	}


static float						AddSignFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise * (1 - Phase) + State->RightNoise * Phase;
		return OriginalValue + (2 * ReturnValue - 1) * Amplitude;
	}


static float						AddSignFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise;
		return OriginalValue + (2 * ReturnValue - 1) * Amplitude;
	}


static float						AddPosFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise * (1 - Phase) + State->RightNoise * Phase;
		return OriginalValue + ReturnValue * Amplitude;
	}


static float						AddPosFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise;
		return OriginalValue + ReturnValue * Amplitude;
	}


static float						MultConst(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue * Amplitude;
	}


static float						MultSignSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue * Amplitude * FSIN(Phase * TWOPI);
	}


static float						MultPosSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue * Amplitude * 0.5 * (1 + FSIN(Phase * TWOPI));
	}


static float						MultSignTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < 0.25)
			{
			}
		else if (Phase < 0.75)
			{
				Phase = 0.5 - Phase;
			}
		else
			{
				Phase = Phase - 1;
			}
		return OriginalValue * Phase * 4 * Amplitude;
	}


static float						MultPosTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < 0.25)
			{
			}
		else if (Phase < 0.75)
			{
				Phase = 0.5 - Phase;
			}
		else
			{
				Phase = Phase - 1;
			}
		return OriginalValue * (Phase + .25) * 2 * Amplitude;
	}


static float						MultSignSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									Peak1;
		float									Peak2;
		float									Trough1;
		float									Trough2;

		Peak1 = State->ExtraValue / 4;
		if (Phase < Peak1)
			{
				return OriginalValue * Amplitude * (Phase / Peak1);
			}
		Peak2 = Peak1 + (.5 - State->ExtraValue / 2);
		if (Phase < Peak2)
			{
				return OriginalValue * Amplitude;
			}
		Trough1 = Peak2 + State->ExtraValue / 2;
		if (Phase < Trough1)
			{
				return OriginalValue * Amplitude * ((Trough1 - Phase) / Peak1 - 1);
			}
		Trough2 = 1 - State->ExtraValue / 4;
		if (Phase < Trough2)
			{
				return OriginalValue * - Amplitude;
			}
		return OriginalValue * Amplitude * ((Phase - Trough2) / (State->ExtraValue / 4) - 1);
	}


static float						MultPosSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									Peak1;
		float									Peak2;
		float									Trough1;
		float									Trough2;

		Peak1 = State->ExtraValue / 4;
		if (Phase < Peak1)
			{
				return OriginalValue * Amplitude * .5 * (1 + (Phase / Peak1));
			}
		Peak2 = Peak1 + (.5 - State->ExtraValue / 2);
		if (Phase < Peak2)
			{
				return OriginalValue * Amplitude;
			}
		Trough1 = Peak2 + State->ExtraValue / 2;
		if (Phase < Trough1)
			{
				return OriginalValue * Amplitude * .5 * (1 + ((Trough1 - Phase) / Peak1 - 1));
			}
		Trough2 = 1 - State->ExtraValue / 4;
		if (Phase < Trough2)
			{
				return 0;
			}
		return OriginalValue * Amplitude * .5 * (1 + ((Phase - Trough2)
			/ (State->ExtraValue / 4) - 1));
	}


static float						MultSignRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < State->ExtraValue)
			{
				return OriginalValue * Amplitude * (1 - 2 * (Phase / State->ExtraValue));
			}
		 else
			{
				return OriginalValue * Amplitude * (2 * ((Phase - State->ExtraValue)
					/ (1 - State->ExtraValue)) - 1);
			}
	}


static float						MultPosRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < State->ExtraValue)
			{
				return OriginalValue * Amplitude * (1 - Phase / State->ExtraValue);
			}
		 else
			{
				return OriginalValue * Amplitude * ((Phase - State->ExtraValue)
					/ (1 - State->ExtraValue));
			}
	}


static float						MultSignFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise * (1 - Phase) + State->RightNoise * Phase;
		return OriginalValue * (2 * ReturnValue - 1) * Amplitude;
	}


static float						MultSignFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise;
		return OriginalValue * (2 * ReturnValue - 1) * Amplitude;
	}


static float						MultPosFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise * (1 - Phase) + State->RightNoise * Phase;
		return OriginalValue * ReturnValue * Amplitude;
	}


static float						MultPosFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise;
		return OriginalValue * ReturnValue * Amplitude;
	}


static float						InvMultConst(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue * (1 - Amplitude);
	}


static float						InvMultSignSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue * (1 - Amplitude * FSIN(Phase * TWOPI));
	}


static float						InvMultPosSine(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		return OriginalValue * (1 - Amplitude * 0.5 * (1 + FSIN(Phase * TWOPI)));
	}


static float						InvMultSignTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < 0.25)
			{
			}
		else if (Phase < 0.75)
			{
				Phase = 0.5 - Phase;
			}
		else
			{
				Phase = Phase - 1;
			}
		return OriginalValue * (1 - Phase * 4 * Amplitude);
	}


static float						InvMultPosTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < 0.25)
			{
			}
		else if (Phase < 0.75)
			{
				Phase = 0.5 - Phase;
			}
		else
			{
				Phase = Phase - 1;
			}
		return OriginalValue * (1 - ((Phase + .25) * 2 * Amplitude));
	}


static float						InvMultSignSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									Peak1;
		float									Peak2;
		float									Trough1;
		float									Trough2;

		Peak1 = State->ExtraValue / 4;
		if (Phase < Peak1)
			{
				return OriginalValue * (1 - Amplitude * (Phase / Peak1));
			}
		Peak2 = Peak1 + (.5 - State->ExtraValue / 2);
		if (Phase < Peak2)
			{
				return OriginalValue * (1 - Amplitude);
			}
		Trough1 = Peak2 + State->ExtraValue / 2;
		if (Phase < Trough1)
			{
				return OriginalValue * (1 - Amplitude * ((Trough1 - Phase) / Peak1 - 1));
			}
		Trough2 = 1 - State->ExtraValue / 4;
		if (Phase < Trough2)
			{
				return OriginalValue * (1 - - Amplitude);
			}
		return OriginalValue * (1 - Amplitude * ((Phase - Trough2)
			/ (State->ExtraValue / 4) - 1));
	}


static float						InvMultPosSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									Peak1;
		float									Peak2;
		float									Trough1;
		float									Trough2;

		Peak1 = State->ExtraValue / 4;
		if (Phase < Peak1)
			{
				return OriginalValue * (1 - Amplitude * .5 * (1 + (Phase / Peak1)));
			}
		Peak2 = Peak1 + (.5 - State->ExtraValue / 2);
		if (Phase < Peak2)
			{
				return OriginalValue * (1 - Amplitude);
			}
		Trough1 = Peak2 + State->ExtraValue / 2;
		if (Phase < Trough1)
			{
				return OriginalValue * (1 - Amplitude * .5 * (1 + ((Trough1 - Phase)
					/ Peak1 - 1)));
			}
		Trough2 = 1 - State->ExtraValue / 4;
		if (Phase < Trough2)
			{
				return OriginalValue * (1 - 0);
			}
		return OriginalValue * (1 - Amplitude * .5 * (1 + ((Phase - Trough2)
			/ (State->ExtraValue / 4) - 1)));
	}


static float						InvMultSignRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < State->ExtraValue)
			{
				return OriginalValue * (1 - Amplitude * (1 - 2 * (Phase / State->ExtraValue)));
			}
		 else
			{
				return OriginalValue * (1 - Amplitude * (2 * ((Phase - State->ExtraValue)
					/ (1 - State->ExtraValue)) - 1));
			}
	}


static float						InvMultPosRamp(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (Phase < State->ExtraValue)
			{
				return OriginalValue * (1 - Amplitude * (1 - Phase / State->ExtraValue));
			}
		 else
			{
				return OriginalValue * (1 - Amplitude * ((Phase - State->ExtraValue)
					/ (1 - State->ExtraValue)));
			}
	}


static float						InvMultSignFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise * (1 - Phase) + State->RightNoise * Phase;
		return OriginalValue * (1 - (2 * ReturnValue - 1) * Amplitude);
	}


static float						InvMultSignFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise;
		return OriginalValue * (1 - (2 * ReturnValue - 1) * Amplitude);
	}


static float						InvMultPosFuzzTriangle(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise * (1 - Phase) + State->RightNoise * Phase;
		return OriginalValue * (1 - ReturnValue * Amplitude);
	}


static float						InvMultPosFuzzSquare(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		float									ReturnValue;

		ReturnValue = State->LeftNoise;
		return OriginalValue * (1 - ReturnValue * Amplitude);
	}


static float						AddWaveTable(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (State->WaveTableWasDefined)
			{
				return OriginalValue + Amplitude
					* ((float)(*State->WaveIndexer)(State->FramesPerTable * Phase,
						LFOGenUpdateCycle(State->WaveTableLFOGenerator,EnvelopeUpdate(
						State->WaveTableIndexEnvelope,OscillatorFrequency),OscillatorFrequency),
						State->NumberOfTables,State->FramesPerTable,State->WaveTableMatrix)
						/ MAX16BIT);
			}
		 else
			{
				return OriginalValue;
			}
	}


static float						MultWaveTable(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (State->WaveTableWasDefined)
			{
				return OriginalValue * Amplitude
					* ((float)(*State->WaveIndexer)(State->FramesPerTable * Phase,
						LFOGenUpdateCycle(State->WaveTableLFOGenerator,EnvelopeUpdate(
						State->WaveTableIndexEnvelope,OscillatorFrequency),OscillatorFrequency),
						State->NumberOfTables,State->FramesPerTable,State->WaveTableMatrix)
						/ MAX16BIT);
			}
		 else
			{
				return 0;
			}
	}


static float						InvMultWaveTable(LFOOneStateRec* State, float Phase,
													float OriginalValue, float Amplitude,
													float OscillatorFrequency)
	{
		if (State->WaveTableWasDefined)
			{
				return OriginalValue * (1 - Amplitude
					* ((float)(*State->WaveIndexer)(State->FramesPerTable * Phase,
						LFOGenUpdateCycle(State->WaveTableLFOGenerator,EnvelopeUpdate(
						State->WaveTableIndexEnvelope,OscillatorFrequency),OscillatorFrequency),
						State->NumberOfTables,State->FramesPerTable,State->WaveTableMatrix)
						/ MAX16BIT));
			}
		 else
			{
				return OriginalValue;
			}
	}
