/* FilterSpec.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 "FilterSpec.h"
#include "Memory.h"
#include "Array.h"
#include "LFOListSpecifier.h"
#include "Envelope.h"


struct OneFilterRec
	{
		/* what kind of filtering */
		FilterTypes					FilterType;
		FilterScalings			FilterScaling;
		FilterChannels			Channel;

		/* stuff for resonant lowpass */
		long								LowpassOrder;
		long								BandpassOrder;

		/* these controls only apply to the track effect, not the oscillator effect */
		float								Cutoff;
		float								CutoffAccent1;
		float								CutoffAccent2;
		float								CutoffAccent3;
		float								CutoffAccent4;
		float								Bandwidth;
		float								BandwidthAccent1;
		float								BandwidthAccent2;
		float								BandwidthAccent3;
		float								BandwidthAccent4;
		float								Gain;
		float								GainAccent1;
		float								GainAccent2;
		float								GainAccent3;
		float								GainAccent4;
		float								OutputMultiplier;
		float								OutputMultiplierAccent1;
		float								OutputMultiplierAccent2;
		float								OutputMultiplierAccent3;
		float								OutputMultiplierAccent4;

		/* these controls only apply to the oscillator effect, not the track effect */
		EnvelopeRec*				CutoffEnvelope;
		EnvelopeRec*				BandwidthEnvelope;
		EnvelopeRec*				OutputEnvelope;
		EnvelopeRec*				GainEnvelope;
		LFOListSpecRec*			CutoffLFO;
		LFOListSpecRec*			BandwidthLFO;
		LFOListSpecRec*			OutputLFO;
		LFOListSpecRec*			GainLFO;
	};


struct FilterSpecRec
	{
		ArrayRec*						List;
	};


/* create a new parallel filter specification */
FilterSpecRec*		NewFilterSpec(void)
	{
		FilterSpecRec*	Filter;

		Filter = (FilterSpecRec*)AllocPtrCanFail(sizeof(FilterSpecRec),"FilterSpecRec");
		if (Filter == NIL)
			{
			 FailurePoint1:
				return NIL;
			}
		Filter->List = NewArray();
		if (Filter->List == NIL)
			{
			 FailurePoint2:
				ReleasePtr((char*)Filter);
				goto FailurePoint1;
			}
		return Filter;
	}


/* dispose of a filter specification */
void							DisposeFilterSpec(FilterSpecRec* Filter)
	{
		long						Scan;
		long						Limit;

		CheckPtrExistence(Filter);
		Limit = ArrayGetLength(Filter->List);
		for (Scan = 0; Scan < Limit; Scan += 1)
			{
				OneFilterRec*		FilterElement;

				FilterElement = ArrayGetElement(Filter->List,Scan);
				DisposeEnvelope(FilterElement->CutoffEnvelope);
				DisposeEnvelope(FilterElement->BandwidthEnvelope);
				DisposeEnvelope(FilterElement->OutputEnvelope);
				DisposeEnvelope(FilterElement->GainEnvelope);
				DisposeLFOListSpecifier(FilterElement->CutoffLFO);
				DisposeLFOListSpecifier(FilterElement->BandwidthLFO);
				DisposeLFOListSpecifier(FilterElement->OutputLFO);
				DisposeLFOListSpecifier(FilterElement->GainLFO);
				ReleasePtr((char*)FilterElement);
			}
		DisposeArray(Filter->List);
		ReleasePtr((char*)Filter);
	}


/* add a single filter to the list */
MyBoolean					AppendFilterToSpec(FilterSpecRec* Filter, OneFilterRec* Spec)
	{
		CheckPtrExistence(Filter);
		CheckPtrExistence(Spec);
		return ArrayAppendElement(Filter->List,Spec);
	}


/* get the number of filters */
long							GetNumFiltersInSpec(FilterSpecRec* Filter)
	{
		CheckPtrExistence(Filter);
		return ArrayGetLength(Filter->List);
	}


/* get a filter type for the specified filter spec */
FilterTypes				GetFilterType(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterType:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->FilterType;
	}


/* get which channel to apply a filter to */
FilterChannels		GetFilterChannel(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterChannel:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->Channel;
	}


float							GetFilterCutoff(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterCutoff:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->Cutoff;
	}


float							GetFilterCutoffAccent1(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterCutoffAccent1:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->CutoffAccent1;
	}


float							GetFilterCutoffAccent2(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterCutoffAccent2:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->CutoffAccent2;
	}


float							GetFilterCutoffAccent3(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterCutoffAccent3:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->CutoffAccent3;
	}


float							GetFilterCutoffAccent4(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterCutoffAccent4:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->CutoffAccent4;
	}


float							GetFilterBandwidth(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandwidth:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->Bandwidth;
	}


float							GetFilterBandwidthAccent1(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandwidthAccent1:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->BandwidthAccent1;
	}


float							GetFilterBandwidthAccent2(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandwidthAccent2:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->BandwidthAccent2;
	}


float							GetFilterBandwidthAccent3(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandwidthAccent3:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->BandwidthAccent3;
	}


float							GetFilterBandwidthAccent4(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandwidthAccent4:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->BandwidthAccent4;
	}


FilterScalings		GetFilterScalingMode(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterScalingMode:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->FilterScaling;
	}


float							GetFilterOutputMultiplier(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterOutputMultiplier:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->OutputMultiplier;
	}


float							GetFilterOutputMultiplierAccent1(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterOutputMultiplierAccent1:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->OutputMultiplierAccent1;
	}


float							GetFilterOutputMultiplierAccent2(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterOutputMultiplierAccent2:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->OutputMultiplierAccent2;
	}


float							GetFilterOutputMultiplierAccent3(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterOutputMultiplierAccent3:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->OutputMultiplierAccent3;
	}


float							GetFilterOutputMultiplierAccent4(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterOutputMultiplierAccent4:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->OutputMultiplierAccent4;
	}


float							GetFilterGain(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterGain:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->Gain;
	}


float							GetFilterGainAccent1(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterGainAccent1:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->GainAccent1;
	}


float							GetFilterGainAccent2(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterGainAccent2:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->GainAccent2;
	}


float							GetFilterGainAccent3(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterGainAccent3:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->GainAccent3;
	}


float							GetFilterGainAccent4(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterGainAccent4:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->GainAccent4;
	}


struct EnvelopeRec*	GetFilterCutoffEnvelope(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterCutoffEnvelope:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->CutoffEnvelope;
	}


struct EnvelopeRec*	GetFilterBandwidthEnvelope(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandwidthEnvelope:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->BandwidthEnvelope;
	}


struct EnvelopeRec*	GetFilterOutputEnvelope(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterOutputEnvelope:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->OutputEnvelope;
	}


struct EnvelopeRec*	GetFilterGainEnvelope(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterGainEnvelope:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->GainEnvelope;
	}


struct LFOListSpecRec*	GetFilterCutoffLFO(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterCutoffLFO:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->CutoffLFO;
	}


struct LFOListSpecRec*	GetFilterBandwidthLFO(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandwidthLFO:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->BandwidthLFO;
	}


struct LFOListSpecRec*	GetFilterOutputLFO(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterOutputLFO:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->OutputLFO;
	}


struct LFOListSpecRec*	GetFilterGainLFO(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterGainLFO:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->GainLFO;
	}


long							GetFilterLowpassOrder(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterLowpassOrder:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->LowpassOrder;
	}


long							GetFilterBandpassOrder(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetFilterBandpassOrder:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec->BandpassOrder;
	}


/* get a filter specification record */
OneFilterRec*			GetSingleFilterSpec(FilterSpecRec* Filter, long Index)
	{
		OneFilterRec*		Spec;

		CheckPtrExistence(Filter);
		ERROR((Index < 0) || (Index >= GetNumFiltersInSpec(Filter)),
			PRERR(ForceAbort,"GetSingleFilterSpec:  index out of range"));
		Spec = (OneFilterRec*)ArrayGetElement(Filter->List,Index);
		CheckPtrExistence(Spec);
		return Spec;
	}


/* create a new filter specification record */
OneFilterRec*			NewSingleFilterSpec(FilterTypes FilterType)
	{
		OneFilterRec*		Spec;

		ERROR((FilterType != eFilterNull)
			&& (FilterType != eFilterFirstOrderLowpass)
			&& (FilterType != eFilterFirstOrderHighpass)
			&& (FilterType != eFilterSecondOrderResonant)
			&& (FilterType != eFilterSecondOrderZero)
			&& (FilterType != eFilterButterworthLowpass)
			&& (FilterType != eFilterButterworthHighpass)
			&& (FilterType != eFilterButterworthBandpass)
			&& (FilterType != eFilterButterworthBandreject)
			&& (FilterType != eFilterParametricEQ)
			&& (FilterType != eFilterResonantLowpass),PRERR(ForceAbort,
			"NewSingleFilterSpec:  unknown filter type"));
		Spec = (OneFilterRec*)AllocPtrCanFail(sizeof(OneFilterRec),"OneFilterRec");
		if (Spec == NIL)
			{
			 FailurePoint1:
				return NIL;
			}
		Spec->CutoffEnvelope = NewEnvelope();
		if (Spec->CutoffEnvelope == NIL)
			{
			 FailurePoint2:
				ReleasePtr((char*)Spec);
				goto FailurePoint1;
			}
		Spec->BandwidthEnvelope = NewEnvelope();
		if (Spec->BandwidthEnvelope == NIL)
			{
			 FailurePoint3:
				DisposeEnvelope(Spec->CutoffEnvelope);
				goto FailurePoint2;
			}
		Spec->OutputEnvelope = NewEnvelope();
		if (Spec->OutputEnvelope == NIL)
			{
			 FailurePoint4:
				DisposeEnvelope(Spec->BandwidthEnvelope);
				goto FailurePoint3;
			}
		Spec->CutoffLFO = NewLFOListSpecifier();
		if (Spec->CutoffLFO == NIL)
			{
			 FailurePoint5:
				DisposeEnvelope(Spec->OutputEnvelope);
				goto FailurePoint4;
			}
		Spec->BandwidthLFO = NewLFOListSpecifier();
		if (Spec->BandwidthLFO == NIL)
			{
			 FailurePoint6:
				DisposeLFOListSpecifier(Spec->CutoffLFO);
				goto FailurePoint5;
			}
		Spec->OutputLFO = NewLFOListSpecifier();
		if (Spec->OutputLFO == NIL)
			{
			 FailurePoint7:
				DisposeLFOListSpecifier(Spec->BandwidthLFO);
				goto FailurePoint6;
			}
		Spec->GainEnvelope = NewEnvelope();
		if (Spec->GainEnvelope == NIL)
			{
			 FailurePoint8:
				DisposeLFOListSpecifier(Spec->OutputLFO);
				goto FailurePoint7;
			}
		Spec->GainLFO = NewLFOListSpecifier();
		if (Spec->GainLFO == NIL)
			{
			 FailurePoint9:
				DisposeEnvelope(Spec->GainEnvelope);
				goto FailurePoint8;
			}
		Spec->FilterType = FilterType;
		Spec->FilterScaling = eFilterDefaultScaling;
		Spec->Channel = eFilterBoth;
		Spec->LowpassOrder = 2;
		Spec->BandpassOrder = 2;
		Spec->Cutoff = 0;
		Spec->CutoffAccent1 = 0;
		Spec->CutoffAccent2 = 0;
		Spec->CutoffAccent3 = 0;
		Spec->CutoffAccent4 = 0;
		Spec->Bandwidth = 0;
		Spec->BandwidthAccent1 = 0;
		Spec->BandwidthAccent2 = 0;
		Spec->BandwidthAccent3 = 0;
		Spec->BandwidthAccent4 = 0;
		Spec->Gain = 0;
		Spec->GainAccent1 = 0;
		Spec->GainAccent2 = 0;
		Spec->GainAccent3 = 0;
		Spec->GainAccent4 = 0;
		Spec->OutputMultiplier = 1;
		Spec->OutputMultiplierAccent1 = 0;
		Spec->OutputMultiplierAccent2 = 0;
		Spec->OutputMultiplierAccent3 = 0;
		Spec->OutputMultiplierAccent4 = 0;
		return Spec;
	}


/* dispose of a single filter specification record */
void							DisposeSingleFilterSpec(OneFilterRec* Spec)
	{
		CheckPtrExistence(Spec);
		DisposeEnvelope(Spec->CutoffEnvelope);
		DisposeEnvelope(Spec->BandwidthEnvelope);
		DisposeEnvelope(Spec->OutputEnvelope);
		DisposeEnvelope(Spec->GainEnvelope);
		DisposeLFOListSpecifier(Spec->CutoffLFO);
		DisposeLFOListSpecifier(Spec->BandwidthLFO);
		DisposeLFOListSpecifier(Spec->OutputLFO);
		DisposeLFOListSpecifier(Spec->GainLFO);
		ReleasePtr((char*)Spec);
	}


void							SetSingleFilterCutoff(OneFilterRec* Spec, float Cutoff)
	{
		CheckPtrExistence(Spec);
		Spec->Cutoff = Cutoff;
	}


void							SetSingleFilterCutoffAccent1(OneFilterRec* Spec, float Accent1)
	{
		CheckPtrExistence(Spec);
		Spec->CutoffAccent1 = Accent1;
	}


void							SetSingleFilterCutoffAccent2(OneFilterRec* Spec, float Accent2)
	{
		CheckPtrExistence(Spec);
		Spec->CutoffAccent2 = Accent2;
	}


void							SetSingleFilterCutoffAccent3(OneFilterRec* Spec, float Accent3)
	{
		CheckPtrExistence(Spec);
		Spec->CutoffAccent3 = Accent3;
	}


void							SetSingleFilterCutoffAccent4(OneFilterRec* Spec, float Accent4)
	{
		CheckPtrExistence(Spec);
		Spec->CutoffAccent4 = Accent4;
	}


void							SetSingleFilterBandwidth(OneFilterRec* Spec, float Bandwidth)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterSecondOrderResonant)
			&& (Spec->FilterType != eFilterSecondOrderZero)
			&& (Spec->FilterType != eFilterButterworthBandpass)
			&& (Spec->FilterType != eFilterButterworthBandreject)
			&& (Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterBandwidth:  filter type has no bandwidth parameter"));
		Spec->Bandwidth = Bandwidth;
	}


void							SetSingleFilterBandwidthAccent1(OneFilterRec* Spec, float Accent1)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterSecondOrderResonant)
			&& (Spec->FilterType != eFilterSecondOrderZero)
			&& (Spec->FilterType != eFilterButterworthBandpass)
			&& (Spec->FilterType != eFilterButterworthBandreject)
			&& (Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterBandwidthAccent1:  filter type has no bandwidth parameter"));
		Spec->BandwidthAccent1 = Accent1;
	}


void							SetSingleFilterBandwidthAccent2(OneFilterRec* Spec, float Accent2)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterSecondOrderResonant)
			&& (Spec->FilterType != eFilterSecondOrderZero)
			&& (Spec->FilterType != eFilterButterworthBandpass)
			&& (Spec->FilterType != eFilterButterworthBandreject)
			&& (Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterBandwidthAccent2:  filter type has no bandwidth parameter"));
		Spec->BandwidthAccent2 = Accent2;
	}


void							SetSingleFilterBandwidthAccent3(OneFilterRec* Spec, float Accent3)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterSecondOrderResonant)
			&& (Spec->FilterType != eFilterSecondOrderZero)
			&& (Spec->FilterType != eFilterButterworthBandpass)
			&& (Spec->FilterType != eFilterButterworthBandreject)
			&& (Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterBandwidthAccent3:  filter type has no bandwidth parameter"));
		Spec->BandwidthAccent3 = Accent3;
	}


void							SetSingleFilterBandwidthAccent4(OneFilterRec* Spec, float Accent4)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterSecondOrderResonant)
			&& (Spec->FilterType != eFilterSecondOrderZero)
			&& (Spec->FilterType != eFilterButterworthBandpass)
			&& (Spec->FilterType != eFilterButterworthBandreject)
			&& (Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterBandwidthAccent4:  filter type has no bandwidth parameter"));
		Spec->BandwidthAccent4 = Accent4;
	}


/* set filter scaling mode */
void							SetSingleFilterScalingMode(OneFilterRec* Spec, FilterScalings Scaling)
	{
		CheckPtrExistence(Spec);
		switch (Spec->FilterType)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"SetSingleFilterScalingMode:  bad filter type"));
					break;
				case eFilterNull:
				case eFilterFirstOrderLowpass:
				case eFilterFirstOrderHighpass:
				case eFilterButterworthLowpass:
				case eFilterButterworthHighpass:
				case eFilterButterworthBandpass:
				case eFilterButterworthBandreject:
				case eFilterParametricEQ:
				case eFilterResonantLowpass:
					ERROR(Scaling != eFilterDefaultScaling,PRERR(ForceAbort,
						"SetSingleFilterScalingMode:  invalid scaling"));
					break;
				case eFilterSecondOrderResonant:
					ERROR((Scaling != eFilterDefaultScaling)
						&& (Scaling != eFilterResonMidbandGain1)
						&& (Scaling != eFilterResonNoiseGain1),
						PRERR(ForceAbort,"SetSingleFilterScalingMode:  invalid scaling"));
					break;
				case eFilterSecondOrderZero:
					ERROR((Scaling != eFilterDefaultScaling) && (Scaling != eFilterZeroGain1),
						PRERR(ForceAbort,"SetSingleFilterScalingMode:  invalid scaling"));
					break;
			}
		Spec->FilterScaling = Scaling;
	}


/* set filter channel */
void							SetSingleFilterChannel(OneFilterRec* Spec, FilterChannels Channel)
	{
		CheckPtrExistence(Spec);
		Spec->Channel = Channel;
	}


void							SetSingleFilterOutputMultiplier(OneFilterRec* Spec, float Output)
	{
		CheckPtrExistence(Spec);
		Spec->OutputMultiplier = Output;
	}


void							SetSingleFilterOutputMultiplierAccent1(OneFilterRec* Spec, float Accent1)
	{
		CheckPtrExistence(Spec);
		Spec->OutputMultiplierAccent1 = Accent1;
	}


void							SetSingleFilterOutputMultiplierAccent2(OneFilterRec* Spec, float Accent2)
	{
		CheckPtrExistence(Spec);
		Spec->OutputMultiplierAccent2 = Accent2;
	}


void							SetSingleFilterOutputMultiplierAccent3(OneFilterRec* Spec, float Accent3)
	{
		CheckPtrExistence(Spec);
		Spec->OutputMultiplierAccent3 = Accent3;
	}


void							SetSingleFilterOutputMultiplierAccent4(OneFilterRec* Spec, float Accent4)
	{
		CheckPtrExistence(Spec);
		Spec->OutputMultiplierAccent4 = Accent4;
	}


void							SetSingleFilterGain(OneFilterRec* Spec, float Gain)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterGain:  filter type has no gain parameter"));
		Spec->Gain = Gain;
	}


void							SetSingleFilterGainAccent1(OneFilterRec* Spec, float Accent1)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterGainAccent1:  filter type has no gain parameter"));
		Spec->GainAccent1 = Accent1;
	}


void							SetSingleFilterGainAccent2(OneFilterRec* Spec, float Accent2)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterGainAccent2:  filter type has no gain parameter"));
		Spec->GainAccent2 = Accent2;
	}


void							SetSingleFilterGainAccent3(OneFilterRec* Spec, float Accent3)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterGainAccent3:  filter type has no gain parameter"));
		Spec->GainAccent3 = Accent3;
	}


void							SetSingleFilterGainAccent4(OneFilterRec* Spec, float Accent4)
	{
		CheckPtrExistence(Spec);
		ERROR((Spec->FilterType != eFilterParametricEQ)
			&& (Spec->FilterType != eFilterResonantLowpass),
			PRERR(ForceAbort,"SetSingleFilterGainAccent4:  filter type has no gain parameter"));
		Spec->GainAccent4 = Accent4;
	}


void							SetFilterLowpassOrder(OneFilterRec* Spec, long Order)
	{
		CheckPtrExistence(Spec);
		ERROR(Spec->FilterType != eFilterResonantLowpass,
			PRERR(ForceAbort,"SetFilterLowpassOrder:  bad filter type"));
		Spec->LowpassOrder = Order;
	}


void							SetFilterBandpassOrder(OneFilterRec* Spec, long Order)
	{
		CheckPtrExistence(Spec);
		ERROR(Spec->FilterType != eFilterResonantLowpass,
			PRERR(ForceAbort,"SetFilterBandpassOrder:  bad filter type"));
		Spec->BandpassOrder = Order;
	}
