/* BuildInstrument.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 "BuildInstrument.h"
#include "BuildInstrument2.h"
#include "CompilerScanner.h"
#include "TrashTracker.h"
#include "InstrumentStructure.h"
#include "Memory.h"
#include "EffectSpecList.h"




#define OPAREN "("
#define CPAREN ")"




/* load keywords into scanner */
static void									LoadScannerKeywords(ScannerRec* Scanner)
	{
		AddKeywordToScanner(Scanner,"instrument",eKeywordInstrument);
		AddKeywordToScanner(Scanner,"loudness",eKeywordLoudness);
		AddKeywordToScanner(Scanner,"frequencylfo",eKeywordFrequencylfo);
		AddKeywordToScanner(Scanner,"oscillator",eKeywordOscillator);
		AddKeywordToScanner(Scanner,"freqenvelope",eKeywordFreqenvelope);
		AddKeywordToScanner(Scanner,"modulation",eKeywordModulation);
		AddKeywordToScanner(Scanner,"constant",eKeywordConstant);
		AddKeywordToScanner(Scanner,"signsine",eKeywordSignsine);
		AddKeywordToScanner(Scanner,"plussine",eKeywordPlussine);
		AddKeywordToScanner(Scanner,"signtriangle",eKeywordSigntriangle);
		AddKeywordToScanner(Scanner,"plustriangle",eKeywordPlustriangle);
		AddKeywordToScanner(Scanner,"signsquare",eKeywordSignsquare);
		AddKeywordToScanner(Scanner,"plussquare",eKeywordPlussquare);
		AddKeywordToScanner(Scanner,"signramp",eKeywordSignramp);
		AddKeywordToScanner(Scanner,"plusramp",eKeywordPlusramp);
		AddKeywordToScanner(Scanner,"signlinfuzz",eKeywordSignlinfuzz);
		AddKeywordToScanner(Scanner,"pluslinfuzz",eKeywordPluslinfuzz);
		AddKeywordToScanner(Scanner,"additive",eKeywordAdditive);
		AddKeywordToScanner(Scanner,"multiplicative",eKeywordMultiplicative);
		AddKeywordToScanner(Scanner,"inversemult",eKeywordInversemult);
		AddKeywordToScanner(Scanner,"type",eKeywordType);
		AddKeywordToScanner(Scanner,"sampled",eKeywordSampled);
		AddKeywordToScanner(Scanner,"wavetable",eKeywordWavetable);
		AddKeywordToScanner(Scanner,"samplelist",eKeywordSamplelist);
		AddKeywordToScanner(Scanner,"freqmultiplier",eKeywordFreqmultiplier);
		AddKeywordToScanner(Scanner,"freqdivisor",eKeywordFreqdivisor);
		AddKeywordToScanner(Scanner,"freqadder",eKeywordFreqadder);
		AddKeywordToScanner(Scanner,"loudnessenvelope",eKeywordLoudnessenvelope);
		AddKeywordToScanner(Scanner,"totalscaling",eKeywordTotalscaling);
		AddKeywordToScanner(Scanner,"exponential",eKeywordExponential);
		AddKeywordToScanner(Scanner,"linear",eKeywordLinear);
		AddKeywordToScanner(Scanner,"level",eKeywordLevel);
		AddKeywordToScanner(Scanner,"delay",eKeywordDelay);
		AddKeywordToScanner(Scanner,"sustainpoint",eKeywordSustainpoint);
		AddKeywordToScanner(Scanner,"releasepoint",eKeywordReleasepoint);
		AddKeywordToScanner(Scanner,"sustainpointnoskip",eKeywordSustainpointnoskip);
		AddKeywordToScanner(Scanner,"releasepointnoskip",eKeywordReleasepointnoskip);
		AddKeywordToScanner(Scanner,"ampaccent1",eKeywordAmpaccent1);
		AddKeywordToScanner(Scanner,"ampaccent2",eKeywordAmpaccent2);
		AddKeywordToScanner(Scanner,"ampaccent3",eKeywordAmpaccent3);
		AddKeywordToScanner(Scanner,"ampaccent4",eKeywordAmpaccent4);
		AddKeywordToScanner(Scanner,"ampaccent5",eKeywordAmpaccent5);
		AddKeywordToScanner(Scanner,"ampaccent6",eKeywordAmpaccent6);
		AddKeywordToScanner(Scanner,"ampaccent7",eKeywordAmpaccent7);
		AddKeywordToScanner(Scanner,"ampaccent8",eKeywordAmpaccent8);
		AddKeywordToScanner(Scanner,"ampfreq",eKeywordAmpfreq);
		AddKeywordToScanner(Scanner,"rateaccent1",eKeywordRateaccent1);
		AddKeywordToScanner(Scanner,"rateaccent2",eKeywordRateaccent2);
		AddKeywordToScanner(Scanner,"rateaccent3",eKeywordRateaccent3);
		AddKeywordToScanner(Scanner,"rateaccent4",eKeywordRateaccent4);
		AddKeywordToScanner(Scanner,"rateaccent5",eKeywordRateaccent5);
		AddKeywordToScanner(Scanner,"rateaccent6",eKeywordRateaccent6);
		AddKeywordToScanner(Scanner,"rateaccent7",eKeywordRateaccent7);
		AddKeywordToScanner(Scanner,"rateaccent8",eKeywordRateaccent8);
		AddKeywordToScanner(Scanner,"ratefreq",eKeywordRatefreq);
		AddKeywordToScanner(Scanner,"scale",eKeywordScale);
		AddKeywordToScanner(Scanner,"ampenvelope",eKeywordAmpenvelope);
		AddKeywordToScanner(Scanner,"loudnesslfo",eKeywordLoudnesslfo);
		AddKeywordToScanner(Scanner,"indexenvelope",eKeywordIndexenvelope);
		AddKeywordToScanner(Scanner,"indexlfo",eKeywordIndexlfo);
		AddKeywordToScanner(Scanner,"points",eKeywordPoints);
		AddKeywordToScanner(Scanner,"stereobias",eKeywordStereobias);
		AddKeywordToScanner(Scanner,"displacement",eKeywordDisplacement);
		AddKeywordToScanner(Scanner,"surroundbias",eKeywordSurroundbias);
		AddKeywordToScanner(Scanner,"hertz",eKeywordHertz);
		AddKeywordToScanner(Scanner,"origin",eKeywordOrigin);
		AddKeywordToScanner(Scanner,"halfsteps",eKeywordHalfsteps);
		AddKeywordToScanner(Scanner,"square",eKeywordSquare);
		AddKeywordToScanner(Scanner,"triangle",eKeywordTriangle);
		AddKeywordToScanner(Scanner,"trackeffect",eKeywordTrackeffect);
		AddKeywordToScanner(Scanner,"tap",eKeywordTap);
		AddKeywordToScanner(Scanner,"to",eKeywordTo);
		AddKeywordToScanner(Scanner,"sourceaccent1",eKeywordSourceaccent1);
		AddKeywordToScanner(Scanner,"sourceaccent2",eKeywordSourceaccent2);
		AddKeywordToScanner(Scanner,"sourceaccent3",eKeywordSourceaccent3);
		AddKeywordToScanner(Scanner,"sourceaccent4",eKeywordSourceaccent4);
		AddKeywordToScanner(Scanner,"targetaccent1",eKeywordTargetaccent1);
		AddKeywordToScanner(Scanner,"targetaccent2",eKeywordTargetaccent2);
		AddKeywordToScanner(Scanner,"targetaccent3",eKeywordTargetaccent3);
		AddKeywordToScanner(Scanner,"targetaccent4",eKeywordTargetaccent4);
		AddKeywordToScanner(Scanner,"scaleaccent1",eKeywordScaleaccent1);
		AddKeywordToScanner(Scanner,"scaleaccent2",eKeywordScaleaccent2);
		AddKeywordToScanner(Scanner,"scaleaccent3",eKeywordScaleaccent3);
		AddKeywordToScanner(Scanner,"scaleaccent4",eKeywordScaleaccent4);
		AddKeywordToScanner(Scanner,"left",eKeywordLeft);
		AddKeywordToScanner(Scanner,"right",eKeywordRight);
		AddKeywordToScanner(Scanner,"mono",eKeywordMono);
		AddKeywordToScanner(Scanner,"delayline",eKeywordDelayline);
		AddKeywordToScanner(Scanner,"maxdelaytime",eKeywordMaxdelaytime);
		AddKeywordToScanner(Scanner,"slope",eKeywordSlope);
		AddKeywordToScanner(Scanner,"center",eKeywordCenter);
		AddKeywordToScanner(Scanner,"envelope",eKeywordEnvelope);
		AddKeywordToScanner(Scanner,"nlproc",eKeywordNlproc);
		AddKeywordToScanner(Scanner,"inputscaling",eKeywordInputscaling);
		AddKeywordToScanner(Scanner,"outputscaling",eKeywordOutputscaling);
		AddKeywordToScanner(Scanner,"inputaccent1",eKeywordInputaccent1);
		AddKeywordToScanner(Scanner,"inputaccent2",eKeywordInputaccent2);
		AddKeywordToScanner(Scanner,"inputaccent3",eKeywordInputaccent3);
		AddKeywordToScanner(Scanner,"inputaccent4",eKeywordInputaccent4);
		AddKeywordToScanner(Scanner,"outputaccent1",eKeywordOutputaccent1);
		AddKeywordToScanner(Scanner,"outputaccent2",eKeywordOutputaccent2);
		AddKeywordToScanner(Scanner,"outputaccent3",eKeywordOutputaccent3);
		AddKeywordToScanner(Scanner,"outputaccent4",eKeywordOutputaccent4);
		AddKeywordToScanner(Scanner,"wavetableindex",eKeywordWavetableindex);
		AddKeywordToScanner(Scanner,"indexaccent1",eKeywordIndexaccent1);
		AddKeywordToScanner(Scanner,"indexaccent2",eKeywordIndexaccent2);
		AddKeywordToScanner(Scanner,"indexaccent3",eKeywordIndexaccent3);
		AddKeywordToScanner(Scanner,"indexaccent4",eKeywordIndexaccent4);
		AddKeywordToScanner(Scanner,"filter",eKeywordFilter);
		AddKeywordToScanner(Scanner,"freq",eKeywordFreq);
		AddKeywordToScanner(Scanner,"bandwidth",eKeywordBandwidth);
		AddKeywordToScanner(Scanner,"defaultscaling",eKeywordDefaultscaling);
		AddKeywordToScanner(Scanner,"unitymidbandgain",eKeywordUnitymidbandgain);
		AddKeywordToScanner(Scanner,"unitynoisegain",eKeywordUnitynoisegain);
		AddKeywordToScanner(Scanner,"unityzerohertzgain",eKeywordUnityzerohertzgain);
		AddKeywordToScanner(Scanner,"lowpass",eKeywordLowpass);
		AddKeywordToScanner(Scanner,"highpass",eKeywordHighpass);
		AddKeywordToScanner(Scanner,"reson",eKeywordReson);
		AddKeywordToScanner(Scanner,"zero",eKeywordZero);
		AddKeywordToScanner(Scanner,"butterworthlowpass",eKeywordButterworthlowpass);
		AddKeywordToScanner(Scanner,"butterworthhighpass",eKeywordButterworthhighpass);
		AddKeywordToScanner(Scanner,"butterworthbandpass",eKeywordButterworthbandpass);
		AddKeywordToScanner(Scanner,"butterworthbandreject",eKeywordButterworthbandreject);
		AddKeywordToScanner(Scanner,"freqaccent1",eKeywordFreqaccent1);
		AddKeywordToScanner(Scanner,"freqaccent2",eKeywordFreqaccent2);
		AddKeywordToScanner(Scanner,"freqaccent3",eKeywordFreqaccent3);
		AddKeywordToScanner(Scanner,"freqaccent4",eKeywordFreqaccent4);
		AddKeywordToScanner(Scanner,"bandwidthaccent1",eKeywordBandwidthaccent1);
		AddKeywordToScanner(Scanner,"bandwidthaccent2",eKeywordBandwidthaccent2);
		AddKeywordToScanner(Scanner,"bandwidthaccent3",eKeywordBandwidthaccent3);
		AddKeywordToScanner(Scanner,"bandwidthaccent4",eKeywordBandwidthaccent4);
		AddKeywordToScanner(Scanner,"null",eKeywordNull);
		AddKeywordToScanner(Scanner,"analyzer",eKeywordAnalyzer);
		AddKeywordToScanner(Scanner,"scoreeffect",eKeywordScoreeffect);
		AddKeywordToScanner(Scanner,"effect",eKeywordEffect);
		AddKeywordToScanner(Scanner,"sourceenvelope",eKeywordSourceenvelope);
		AddKeywordToScanner(Scanner,"targetenvelope",eKeywordTargetenvelope);
		AddKeywordToScanner(Scanner,"scaleenvelope",eKeywordScaleenvelope);
		AddKeywordToScanner(Scanner,"sourcelfo",eKeywordSourcelfo);
		AddKeywordToScanner(Scanner,"targetlfo",eKeywordTargetlfo);
		AddKeywordToScanner(Scanner,"scalelfo",eKeywordScalelfo);
		AddKeywordToScanner(Scanner,"inputscalingenvelope",eKeywordInputscalingenvelope);
		AddKeywordToScanner(Scanner,"outputscalingenvelope",eKeywordOutputscalingenvelope);
		AddKeywordToScanner(Scanner,"inputscalinglfo",eKeywordInputscalinglfo);
		AddKeywordToScanner(Scanner,"outputscalinglfo",eKeywordOutputscalinglfo);
		AddKeywordToScanner(Scanner,"bandwidthenvelope",eKeywordBandwidthenvelope);
		AddKeywordToScanner(Scanner,"freqlfo",eKeywordFreqlfo);
		AddKeywordToScanner(Scanner,"bandwidthlfo",eKeywordBandwidthlfo);
		AddKeywordToScanner(Scanner,"amplfo",eKeywordAmplfo);
		AddKeywordToScanner(Scanner,"pitchcontrol",eKeywordPitchcontrol);
		AddKeywordToScanner(Scanner,"parameq",eKeywordParameq);
		AddKeywordToScanner(Scanner,"gain",eKeywordGain);
		AddKeywordToScanner(Scanner,"gainaccent1",eKeywordGainaccent1);
		AddKeywordToScanner(Scanner,"gainaccent2",eKeywordGainaccent2);
		AddKeywordToScanner(Scanner,"gainaccent3",eKeywordGainaccent3);
		AddKeywordToScanner(Scanner,"gainaccent4",eKeywordGainaccent4);
		AddKeywordToScanner(Scanner,"gainenvelope",eKeywordGainenvelope);
		AddKeywordToScanner(Scanner,"gainlfo",eKeywordGainlfo);
		AddKeywordToScanner(Scanner,"order",eKeywordOrder);
		AddKeywordToScanner(Scanner,"resonantlowpass",eKeywordResonantlowpass);
	}




/* take a block of text and parse it into an instrument definition.  it returns an */
/* error code.  if an error occurs, then *InstrOut is invalid, otherwise it will */
/* be valid.  the text file remains unaltered.  *ErrorLine is numbered from 1. */
BuildInstrErrors						BuildInstrumentFromText(char* TextFile, long* ErrorLine,
															struct InstrumentRec** InstrOut,
															struct SampleListRec* SampleList,
															struct AlgoSampListRec* AlgoSampList,
															struct WaveTableListRec* WaveTableList,
															struct AlgoWaveTableListRec* AlgoWaveTableList)
	{
		TrashTrackRec*						TrashTracker;
		ScannerRec*								Scanner;
		InstrumentRec*						Instrument;
		BuildInstrErrors					Error;
		TokenRec*									Token;

		CheckPtrExistence(TextFile);
		CheckPtrExistence(SampleList);
		CheckPtrExistence(AlgoSampList);
		CheckPtrExistence(WaveTableList);
		CheckPtrExistence(AlgoWaveTableList);
		EXECUTE(*InstrOut = (InstrumentRec*)0x81818181;)
		EXECUTE(*ErrorLine = 0x81818181;)

		TrashTracker = NewTrashTracker();
		if (TrashTracker == NIL)
			{
			 NoMemoryFailurePoint1:
				*ErrorLine = 1;
				return eBuildInstrOutOfMemory;
			}

		Scanner = NewScanner(TrashTracker,TextFile);
		if (Scanner == NIL)
			{
			 NoMemoryFailurePoint2:
				goto NoMemoryFailurePoint1;
			}

		Instrument = NewInstrumentSpecifier();
		if (Instrument == NIL)
			{
			 NoMemoryFailurePoint3:
				goto NoMemoryFailurePoint2;
			}

		LoadScannerKeywords(Scanner);

		Error = ParseInstrDefinition(Instrument,Scanner,ErrorLine,SampleList,AlgoSampList,
			WaveTableList,AlgoWaveTableList);
		if (Error != eBuildInstrNoError)
			{
				DisposeInstrumentSpecification(Instrument);
				DisposeTrashTracker(TrashTracker);
				return Error;
			}

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*ErrorLine = GetCurrentLineNumber(Scanner);
				DisposeInstrumentSpecification(Instrument);
				DisposeTrashTracker(TrashTracker);
				return eBuildInstrOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenEndOfInput)
			{
				*ErrorLine = GetCurrentLineNumber(Scanner);
				DisposeInstrumentSpecification(Instrument);
				DisposeTrashTracker(TrashTracker);
				return eBuildInstrUnexpectedInput;
			}

		DisposeTrashTracker(TrashTracker);

		*InstrOut = Instrument;
		return eBuildInstrNoError;
	}




/* build just a list of effects */
BuildInstrErrors						BuildEffectList(char* TextFile, long* ErrorLine,
															struct EffectSpecListRec** EffectOut,
															struct WaveTableListRec* WaveTableList,
															struct AlgoWaveTableListRec* AlgoWaveTableList)
	{
		TrashTrackRec*						TrashTracker;
		ScannerRec*								Scanner;
		EffectSpecListRec*				EffectSpec;
		BuildInstrErrors					Error;
		TokenRec*									Token;

		CheckPtrExistence(TextFile);
		CheckPtrExistence(WaveTableList);
		CheckPtrExistence(AlgoWaveTableList);
		EXECUTE(*EffectOut = (EffectSpecListRec*)0x81818181;)
		EXECUTE(*ErrorLine = 0x81818181;)

		TrashTracker = NewTrashTracker();
		if (TrashTracker == NIL)
			{
			 NoMemoryFailurePoint1:
				*ErrorLine = 1;
				return eBuildInstrOutOfMemory;
			}

		Scanner = NewScanner(TrashTracker,TextFile);
		if (Scanner == NIL)
			{
			 NoMemoryFailurePoint2:
				goto NoMemoryFailurePoint1;
			}

		EffectSpec = NewEffectSpecList();
		if (EffectSpec == NIL)
			{
			 NoMemoryFailurePoint3:
				goto NoMemoryFailurePoint2;
			}

		LoadScannerKeywords(Scanner);

		do
			{
				Token = GetNextToken(Scanner);
				if (Token == NIL)
					{
						*ErrorLine = GetCurrentLineNumber(Scanner);
						DisposeTrashTracker(TrashTracker);
						DisposeEffectSpecList(EffectSpec);
						return eBuildInstrOutOfMemory;
					}
				if (GetTokenType(Token) != eTokenEndOfInput)
					{
						if ((GetTokenType(Token) != eTokenKeyword)
							|| (GetTokenKeywordTag(Token) != eKeywordScoreeffect))
							{
								*ErrorLine = GetCurrentLineNumber(Scanner);
								DisposeTrashTracker(TrashTracker);
								DisposeEffectSpecList(EffectSpec);
								return eBuildInstrExpectedScoreEffect;
							}
						Error = ParseTrackEffect(EffectSpec,Scanner,ErrorLine,
							WaveTableList,AlgoWaveTableList);
						if (Error != eBuildInstrNoError)
							{
								DisposeTrashTracker(TrashTracker);
								DisposeEffectSpecList(EffectSpec);
								return Error;
							}
						Token = GetNextToken(Scanner);
						if (Token == NIL)
							{
								*ErrorLine = GetCurrentLineNumber(Scanner);
								DisposeTrashTracker(TrashTracker);
								DisposeEffectSpecList(EffectSpec);
								return eBuildInstrOutOfMemory;
							}
						if (GetTokenType(Token) != eTokenSemicolon)
							{
								*ErrorLine = GetCurrentLineNumber(Scanner);
								DisposeTrashTracker(TrashTracker);
								DisposeEffectSpecList(EffectSpec);
								return eBuildInstrExpectedSemicolon;
							}
					}
			} while (GetTokenType(Token) != eTokenEndOfInput);

		*EffectOut = EffectSpec;
		DisposeTrashTracker(TrashTracker);
		return eBuildInstrNoError;
	}




/* get a static null terminated string describing the error */
char*												BuildInstrGetErrorMessageText(BuildInstrErrors ErrorCode)
	{
		char*											S EXECUTE(= (char*)0x81818181);

		switch (ErrorCode)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"BuildInstrGetErrorMessageText:  bad error code"));
					break;
				case eBuildInstrOutOfMemory:
					S = "Out of memory";
					break;
				case eBuildInstrUnexpectedInput:
					S = "Unexpected end of text";
					break;
				case eBuildInstrExpectedInstrument:
					S = "Expected 'instrument'";
					break;
				case eBuildInstrExpectedOpenParen:
					S = "Expected '"OPAREN"'";
					break;
				case eBuildInstrExpectedCloseParen:
					S = "Expected '"CPAREN"'";
					break;
				case eBuildInstrSomeRequiredInstrParamsMissing:
					S = "Some required instrument parameters have not been specified";
					break;
				case eBuildInstrExpectedSemicolon:
					S = "Expected ';'";
					break;
				case eBuildInstrExpectedInstrumentMember:
					S = "Expected 'loudness', 'frequencylfo', 'oscillator', or 'trackeffect'";
					break;
				case eBuildInstrMultipleInstrLoudness:
					S = "Instrument parameter 'loudness' has already been specified";
					break;
				case eBuildInstrSomeRequiredLFOParamsMissing:
					S = "Some required LFO parameters have not been specified";
					break;
				case eBuildInstrSomeRequiredOscillatorParamsMissing:
					S = "Some required oscillator parameters have not been specified";
					break;
				case eBuildInstrExpectedNumber:
					S = "Expected a number";
					break;
				case eBuildInstrExpectedStringOrIdentifier:
					S = "Expected a string or identifier";
					break;
				case eBuildInstrExpectedLFOMember:
					S = "Expected 'freqenvelope', 'ampenvelope', 'oscillator', 'modulation', "
						"'linear', 'exponential', 'freqlfo', or 'amplfo'";
					break;
				case eBuildInstrMultipleLFOFreqEnvelope:
					S = "LFO parameter 'freqenvelope' has already been specified";
					break;
				case eBuildInstrSomeRequiredEnvelopeParamsMissing:
					S = "Some required envelope parameters have not been specified";
					break;
				case eBuildInstrMultipleLFOAmpEnvelope:
					S = "LFO parameter 'ampenvelope' has already been specified";
					break;
				case eBuildInstrMultipleLFOOscillatorType:
					S = "LFO parameter 'oscillator' has already been specified";
					break;
				case eBuildInstrExpectedLFOOscillatorType:
					S = "Expected 'constant', 'signsine', 'plussine', 'signtriangle', "
						"'plustriangle', 'signsquare', 'plussquare', 'signramp', 'plusramp', "
						"'signlinfuzz', 'pluslinfuzz', or 'wavetable'";
					break;
				case eBuildInstrMultipleLFOModulationType:
					S = "LFO parameter 'modulation' has already been specified";
					break;
				case eBuildInstrMultipleLFOAddingMode:
					S = "LFO adding mode ('linear' or 'exponential') has already been specified";
					break;
				case eBuildInstrExpectedLFOModulationType:
					S = "Expected 'additive', 'multiplicative', or 'inversemult'";
					break;
				case eBuildInstrExpectedOscillatorMember:
					S = "Expected 'type', 'samplelist', 'loudness', "
						"'freqmultiplier', 'freqdivisor', 'freqadder', "
						"'loudnessenvelope', 'loudnesslfo', 'indexenvelope', 'indexlfo', "
						"'stereobias', 'displacement', or 'frequencylfo'";
					break;
				case eBuildInstrMultipleOscType:
					S = "Oscillator parameter 'type' has already been specified";
					break;
				case eBuildInstrMultipleOscSampleList:
					S = "Oscillator parameter 'samplelist' has already been specified";
					break;
				case eBuildInstrMultipleOscLoudness:
					S = "Oscillator parameter 'loudness' has already been specified";
					break;
				case eBuildInstrMultipleOscFreqMultiplier:
					S = "Oscillator parameter 'freqmultiplier' has already been specified";
					break;
				case eBuildInstrMultipleOscFreqDivisor:
					S = "Oscillator parameter 'freqdivisor' has already been specified";
					break;
				case eBuildInstrMultipleOscLoudnessEnvelope:
					S = "Oscillator parameter 'loudnessenvelope' has already been specified";
					break;
				case eBuildInstrMultipleOscIndexEnvelope:
					S = "Oscillator parameter 'indexenvelope' has already been specified";
					break;
				case eBuildInstrExpectedOscType:
					S = "Expected 'sampled' or 'wavetable'";
					break;
				case eBuildInstrExpectedInteger:
					S = "Expected an integer";
					break;
				case eBuildInstrExpectedEnvelopeMember:
					S = "Expected 'totalscaling', 'points', or 'pitchcontrol'";
					break;
				case eBuildInstrMultipleEnvTotalScaling:
					S = "Envelope parameter 'totalscaling' has already been specified";
					break;
				case eBuildInstrMultipleEnvPoints:
					S = "Envelope parameter 'points' has already been specified";
					break;
				case eBuildInstrExpectedDelayOrOrigin:
					S = "Expected 'delay' or 'origin'";
					break;
				case eBuildInstrExpectedLevelOrScale:
					S = "Expected 'level' or 'scale'";
					break;
				case eBuildInstrExpectedEnvPointMember:
					S = "Expected 'sustainpoint', 'sustainpointnoskip', 'releasepoint', "
						"'releasepointnoskip', 'ampaccent[1-8]', 'ampfreq', 'rateaccent[1-8]', "
						"'ratefreq', 'exponential', or 'linear'";
					break;
				case eBuildInstrExpectedIntBetween1And3:
					S = "Expected an integer in the range [1..3]";
					break;
				case eBuildInstrEnvSustainPointAlreadyDefined:
					S = "That envelope sustain point has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent1:
					S = "Envelope parameter 'ampaccent1' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent2:
					S = "Envelope parameter 'ampaccent2' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent3:
					S = "Envelope parameter 'ampaccent3' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent4:
					S = "Envelope parameter 'ampaccent4' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent5:
					S = "Envelope parameter 'ampaccent5' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent6:
					S = "Envelope parameter 'ampaccent6' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent7:
					S = "Envelope parameter 'ampaccent7' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpAccent8:
					S = "Envelope parameter 'ampaccent8' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointAmpFreq:
					S = "Envelope parameter 'ampfreq' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent1:
					S = "Envelope parameter 'rateaccent1' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent2:
					S = "Envelope parameter 'rateaccent2' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent3:
					S = "Envelope parameter 'rateaccent3' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent4:
					S = "Envelope parameter 'rateaccent4' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent5:
					S = "Envelope parameter 'rateaccent5' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent6:
					S = "Envelope parameter 'rateaccent6' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent7:
					S = "Envelope parameter 'rateaccent7' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateAccent8:
					S = "Envelope parameter 'rateaccent8' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointRateFreq:
					S = "Envelope parameter 'ratefreq' has already been specified";
					break;
				case eBuildInstrMultipleEnvPointCurveSpec:
					S = "Envelope parameter 'exponential' or 'linear' has "
						"already been specified";
					break;
				case eBuildInstrSomeSamplesDontExist:
					S = "Some named samples or algorithmic samples do not exist";
					break;
				case eBuildInstrSomeWaveTablesDontExist:
					S = "Some named wave tables or algorithmic wave tables do not exist";
					break;
				case eBuildInstrMultipleOscStereoBias:
					S = "Oscillator parameter 'stereobias' has already been specified";
					break;
				case eBuildInstrMultipleOscDisplacement:
					S = "Oscillator parameter 'displacement' has already been specified";
					break;
				case eBuildInstrMultipleOscSurroundBias:
					S = "Oscillator parameter 'surroundbias' has already been specified";
					break;
				case eBuildInstrMultipleOscFreqAdder:
					S = "Oscillator parameter 'freqadder' has already been specified";
					break;
				case eBuildInstrExpectedSquareOrTriangle:
					S = "Expected 'square' or 'triangle'";
					break;
				case eBuildInstrExpectedEffectName:
					S = "Expected 'delayline', 'nlproc', 'filter', or 'analyzer'";
					break;
				case eBuildInstrExpectedDelayLineElem:
					S = "Expected 'tap' or 'maxdelaytime'";
					break;
				case eBuildInstrExpectedTapChannel:
					S = "Expected 'left', 'right', or 'mono'";
					break;
				case eBuildInstrExpectedTo:
					S = "Expected 'to'";
					break;
				case eBuildInstrExpectedScale:
					S = "Expected 'scale'";
					break;
				case eBuildInstrExpectedTapAttr:
					S = "Expected 'sourceaccent[1-4]', 'targetaccent[1-4]', 'scaleaccent[1-4]', "
						"'lowpass', or 'freqaccent[1-4]'";
					break;
				case eBuildInstrMultipleSourceAccent1:
					S = "Delay tap parameter 'sourceaccent1' has already been specified";
					break;
				case eBuildInstrMultipleSourceAccent2:
					S = "Delay tap parameter 'sourceaccent2' has already been specified";
					break;
				case eBuildInstrMultipleSourceAccent3:
					S = "Delay tap parameter 'sourceaccent3' has already been specified";
					break;
				case eBuildInstrMultipleSourceAccent4:
					S = "Delay tap parameter 'sourceaccent4' has already been specified";
					break;
				case eBuildInstrMultipleTargetAccent1:
					S = "Delay tap parameter 'targetaccent1' has already been specified";
					break;
				case eBuildInstrMultipleTargetAccent2:
					S = "Delay tap parameter 'targetaccent2' has already been specified";
					break;
				case eBuildInstrMultipleTargetAccent3:
					S = "Delay tap parameter 'targetaccent3' has already been specified";
					break;
				case eBuildInstrMultipleTargetAccent4:
					S = "Delay tap parameter 'targetaccent4' has already been specified";
					break;
				case eBuildInstrMultipleScaleAccent1:
					S = "Delay tap parameter 'scaleaccent1' has already been specified";
					break;
				case eBuildInstrMultipleScaleAccent2:
					S = "Delay tap parameter 'scaleaccent2' has already been specified";
					break;
				case eBuildInstrMultipleScaleAccent3:
					S = "Delay tap parameter 'scaleaccent3' has already been specified";
					break;
				case eBuildInstrMultipleScaleAccent4:
					S = "Delay tap parameter 'scaleaccent4' has already been specified";
					break;
				case eBuildInstrMultipleFilter:
					S = "Delay tap filter has already been specified";
					break;
				case eBuildInstrMultipleMaxDelayTime:
					S = "Delay line parameter 'maxdelaytime' has already been specified";
					break;
				case eBuildInstrExpectedSlope:
					S = "Expected 'slope'";
					break;
				case eBuildInstrExpectedCenter:
					S = "Expected 'center'";
					break;
				case eBuildInstrExpectedSamplelist:
					S = "Expected 'samplelist'";
					break;
				case eBuildInstrExpectedEnvelope:
					S = "Expected 'envelope'";
					break;
				case eBuildInstrExpectedWavetable:
					S = "Expected 'wavetable'";
					break;
				case eBuildInstrUndefinedWavetable:
					S = "Specified wavetable does not exist";
					break;
				case eBuildInstrExpectedInputscaling:
					S = "Expected 'inputscaling'";
					break;
				case eBuildInstrExpectedOutputscaling:
					S = "Expected 'outputscaling'";
					break;
				case eBuildInstrExpectedNLAttribute:
					S = "Expected 'inputaccent[1-4]', 'outputaccent[1-4]', or 'indexaccent[1-4]'";
					break;
				case eBuildInstrMultipleInputaccent1:
					S = "Nonlinear processor parameter 'inputaccent1' has already been specified";
					break;
				case eBuildInstrMultipleInputaccent2:
					S = "Nonlinear processor parameter 'inputaccent2' has already been specified";
					break;
				case eBuildInstrMultipleInputaccent3:
					S = "Nonlinear processor parameter 'inputaccent3' has already been specified";
					break;
				case eBuildInstrMultipleInputaccent4:
					S = "Nonlinear processor parameter 'inputaccent4' has already been specified";
					break;
				case eBuildInstrMultipleOutputaccent1:
					S = "Nonlinear processor parameter 'outputaccent1' has already been specified";
					break;
				case eBuildInstrMultipleOutputaccent2:
					S = "Nonlinear processor parameter 'outputaccent2' has already been specified";
					break;
				case eBuildInstrMultipleOutputaccent3:
					S = "Nonlinear processor parameter 'outputaccent3' has already been specified";
					break;
				case eBuildInstrMultipleOutputaccent4:
					S = "Nonlinear processor parameter 'outputaccent4' has already been specified";
					break;
				case eBuildInstrMultipleIndexaccent1:
					S = "Nonlinear processor parameter 'indexaccent1' has already been specified";
					break;
				case eBuildInstrMultipleIndexaccent2:
					S = "Nonlinear processor parameter 'indexaccent2' has already been specified";
					break;
				case eBuildInstrMultipleIndexaccent3:
					S = "Nonlinear processor parameter 'indexaccent3' has already been specified";
					break;
				case eBuildInstrMultipleIndexaccent4:
					S = "Nonlinear processor parameter 'indexaccent4' has already been specified";
					break;
				case eBuildInstrExpectedWavetableindex:
					S = "Expected 'wavetableindex'";
					break;
				case eBuildInstrExpectedFilterType:
					S = "Expected 'lowpass', 'highpass', 'reson', 'zero', 'butterworthlowpass', "
						"'butterworthhighpass', 'butterworthbandpass', 'butterworthbandreject', "
						"'parameq', or 'resonantlowpass'";
					break;
				case eBuildInstrExpectedFreq:
					S = "Expected 'freq'";
					break;
				case eBuildInstrExpectedBandwidth:
					S = "Expected 'bandwidth'";
					break;
				case eBuildInstrExpectedDefaultScaling:
					S = "Expected 'defaultscaling'";
					break;
				case eBuildInstrExpectedResonScaling:
					S = "Expected 'defaultscaling', 'unitymidbandgain', or 'unitynoisegain'";
					break;
				case eBuildInstrExpectedZeroScaling:
					S = "Expected 'defaultscaling' or 'unityzerohertzgain'";
					break;
				case eBuildInstrExpectedFilterAttr:
					S = "Expected 'freqaccent[1-4]', 'bandwidthaccent[1-4]', 'outputscaling', "
						"'outputaccent[1-4]', or 'gainaccent[1-4]'";
					break;
				case eBuildInstrMultipleFreqaccent1:
					S = "Filter parameter 'freqaccent1' has already been specified";
					break;
				case eBuildInstrMultipleFreqaccent2:
					S = "Filter parameter 'freqaccent2' has already been specified";
					break;
				case eBuildInstrMultipleFreqaccent3:
					S = "Filter parameter 'freqaccent3' has already been specified";
					break;
				case eBuildInstrMultipleFreqaccent4:
					S = "Filter parameter 'freqaccent4' has already been specified";
					break;
				case eBuildInstrMultipleBandwidthaccent1:
					S = "Filter parameter 'bandwidthaccent1' has already been specified";
					break;
				case eBuildInstrMultipleBandwidthaccent2:
					S = "Filter parameter 'bandwidthaccent2' has already been specified";
					break;
				case eBuildInstrMultipleBandwidthaccent3:
					S = "Filter parameter 'bandwidthaccent3' has already been specified";
					break;
				case eBuildInstrMultipleBandwidthaccent4:
					S = "Filter parameter 'bandwidthaccent4' has already been specified";
					break;
				case eBuildInstrMultipleOutputScaling:
					S = "Filter parameter 'outputscaling' has already been specified";
					break;
				case eBuildInstrMultipleOutputScalingAccent1:
					S = "Filter parameter 'outputaccent1' has already been specified";
					break;
				case eBuildInstrMultipleOutputScalingAccent2:
					S = "Filter parameter 'outputaccent2' has already been specified";
					break;
				case eBuildInstrMultipleOutputScalingAccent3:
					S = "Filter parameter 'outputaccent3' has already been specified";
					break;
				case eBuildInstrMultipleOutputScalingAccent4:
					S = "Filter parameter 'outputaccent4' has already been specified";
					break;
				case eBuildInstrExpectedFilterChannel:
					S = "Expected 'left', 'right', 'mono', 'defaultscaling', "
						"'unitymidbandgain', 'unitynoisegain', or 'unityzerohertzgain'";
					break;
				case eBuildInstrNullFilterHasNoFreqAccent1:
					S = "Parameter 'freqaccent1' can't be specified for null filter";
					break;
				case eBuildInstrNullFilterHasNoFreqAccent2:
					S = "Parameter 'freqaccent2' can't be specified for null filter";
					break;
				case eBuildInstrNullFilterHasNoFreqAccent3:
					S = "Parameter 'freqaccent3' can't be specified for null filter";
					break;
				case eBuildInstrNullFilterHasNoFreqAccent4:
					S = "Parameter 'freqaccent4' can't be specified for null filter";
					break;
				case eBuildInstrFilterHasNoBandwidthAccent1:
					S = "Parameter 'bandwidthaccent1' can only be specified for filters "
						"'reson', 'zero', 'butterworthbandpass', 'butterworthbandreject', "
						"'parameq', and 'resonantlowpass'";
					break;
				case eBuildInstrFilterHasNoBandwidthAccent2:
					S = "Parameter 'bandwidthaccent2' can only be specified for filters "
						"'reson', 'zero', 'butterworthbandpass', and 'butterworthbandreject', "
						"'parameq', and 'resonantlowpass'";
					break;
				case eBuildInstrFilterHasNoBandwidthAccent3:
					S = "Parameter 'bandwidthaccent3' can only be specified for filters "
						"'reson', 'zero', 'butterworthbandpass', and 'butterworthbandreject', "
						"'parameq', and 'resonantlowpass'";
					break;
				case eBuildInstrFilterHasNoBandwidthAccent4:
					S = "Parameter 'bandwidthaccent4' can only be specified for filters "
						"'reson', 'zero', 'butterworthbandpass', and 'butterworthbandreject', "
						"'parameq', and 'resonantlowpass'";
					break;
				case eBuildInstrExpectedScoreEffect:
					S = "Expected 'scoreeffect'";
					break;
				case eBuildInstrExpectedOscillatorEffect:
					S = "Expected 'delayline', 'nlproc', 'filter', or 'analyzer'";
					break;
				case eBuildInstrExpectedSourceEnvelope:
					S = "Expected 'sourceenvelope'";
					break;
				case eBuildInstrExpectedTargetEnvelope:
					S = "Expected 'targetenvelope'";
					break;
				case eBuildInstrExpectedScaleEnvelope:
					S = "Expected 'scaleenvelope'";
					break;
				case eBuildInstrExpectedSourceLfoOrTo:
					S = "Expected 'sourcelfo' or 'to'";
					break;
				case eBuildInstrExpectedTargetLfoOrScaleEnvelope:
					S = "Expected 'targetlfo' or 'scaleenvelope'";
					break;
				case eBuildInstrExpectedScaleLfoCutoffOrSemicolon:
					S = "Expected 'scalelfo', 'lowpass', or ';'";
					break;
				case eBuildInstrExpectedInputScalingEnvelope:
					S = "Expected 'inputscalingenvelope'";
					break;
				case eBuildInstrExpectedOutputScalingEnvelope:
					S = "Expected 'outputscalingenvelope'";
					break;
				case eBuildInstrExpectedIndexEnvelope:
					S = "Expected 'indexenvelope'";
					break;
				case eBuildInstrExpectedInputScalingLfoOrOutputScalingEnvelope:
					S = "Expected 'inputscalinglfo' or 'outputscalingenvelope'";
					break;
				case eBuildInstrExpectedOutputScalingLfoOrIndexEnvelope:
					S = "Expected 'outputscalinglfo' or 'indexenvelope'";
					break;
				case eBuildInstrExpectedIndexLfoOrSemicolon:
					S = "Expected 'indexlfo' or ';'";
					break;
				case eBuildInstrExpectedFreqEnvelope:
					S = "Expected 'freqenvelope'";
					break;
				case eBuildInstrExpectedBandwidthEnvelope:
					S = "Expected 'bandwidthenvelope'";
					break;
				case eBuildInstrExpectedFreqLfoOrScalingOrChannel:
					S = "Expected 'freqlfo', 'left', 'right', 'mono', 'defaultscaling', "
						"'unitymidbandgain', 'unitynoisegain', 'unityzerohertzgain', "
						"or 'bandwidthenvelope'";
					break;
				case eBuildInstrExpectedBandwidthLfoOrScalingOrChannel:
					S = "Expected 'bandwidthlfo', 'gainenvelope', 'left', 'right', 'mono', "
						"'defaultscaling', 'unitymidbandgain', 'unitynoisegain', "
						"or 'unityzerohertzgain'";
					break;
				case eBuildInstrExpectedOutputScalingLfoOrSemicolon:
					S = "Expected 'outputscalinglfo' or ';'";
					break;
				case eBuildInstrExpectedFilter:
					S = "Expected 'filter' or '"CPAREN"'";
					break;
				case eBuildInstrExpectedFreqLfoOrSemicolon:
					S = "Expected 'freqlfo' or ';'";
					break;
				case eBuildInstrMultipleDelayLowpassFreq:
					S = "Delay tap parameter 'lowpass freq' has already been specified";
					break;
				case eBuildInstrMultipleDelayFilterAccent1:
					S = "Delay tap parameter 'freqaccent1' has already been specified";
					break;
				case eBuildInstrMultipleDelayFilterAccent2:
					S = "Delay tap parameter 'freqaccent2' has already been specified";
					break;
				case eBuildInstrMultipleDelayFilterAccent3:
					S = "Delay tap parameter 'freqaccent3' has already been specified";
					break;
				case eBuildInstrMultipleDelayFilterAccent4:
					S = "Delay tap parameter 'freqaccent4' has already been specified";
					break;
				case eBuildInstrExpectedIndexLFOOrSemicolon:
					S = "Expected 'indexlfo' or ';'";
					break;
				case eBuildInstrMultiplePitchControl:
					S = "Envelope parameter 'pitchcontrol' has already been specified";
					break;
				case eBuildInstrExpectedGain:
					S = "Expected 'gain'";
					break;
				case eBuildInstrMultipleGainAccent1:
					S = "Filter parameter 'gainaccent1' has already been specified";
					break;
				case eBuildInstrMultipleGainAccent2:
					S = "Filter parameter 'gainaccent2' has already been specified";
					break;
				case eBuildInstrMultipleGainAccent3:
					S = "Filter parameter 'gainaccent3' has already been specified";
					break;
				case eBuildInstrMultipleGainAccent4:
					S = "Filter parameter 'gainaccent4' has already been specified";
					break;
				case eBuildInstrExpectedGainEnvelope:
					S = "Expected 'gainenvelope'";
					break;
				case eBuildInstrExpectedGainLfoOrScalingOrChannel:
					S = "Expected 'gainlfo', 'left', 'right', 'mono', "
						"'defaultscaling', 'unitymidbandgain', 'unitynoisegain', "
						"or 'unityzerohertzgain'";
					break;
				case eBuildInstrFilterHasNoGainAccent1:
					S = "Parameter 'gainaccent1' can only be applied to parameq or resonantlowpass";
					break;
				case eBuildInstrFilterHasNoGainAccent2:
					S = "Parameter 'gainaccent2' can only be applied to parameq or resonantlowpass";
					break;
				case eBuildInstrFilterHasNoGainAccent3:
					S = "Parameter 'gainaccent3' can only be applied to parameq or resonantlowpass";
					break;
				case eBuildInstrFilterHasNoGainAccent4:
					S = "Parameter 'gainaccent4' can only be applied to parameq or resonantlowpass";
					break;
				case eBuildInstrExpectedOrder:
					S = "Expected 'order'";
					break;
				case eBuildInstrOrderMustBeNonNegativeEvenInteger:
					S = "Filter order must be a non-negative even integer";
					break;
			}

		return S;
	}
