/* FilterArray.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 "FilterArray.h"
#include "Memory.h"
#include "FilterSpec.h"
#include "FilterFirstOrderLowpass.h"
#include "FilterFirstOrderHighpass.h"
#include "FilterSecondOrderReson.h"
#include "FilterSecondOrderZero.h"
#include "FilterButterworthLowpass.h"
#include "FilterButterworthHighpass.h"
#include "FilterButterworthBandpass.h"
#include "FilterButterworthBandreject.h"
#include "FilterNull.h"
#include "FilterParametricEqualizer.h"
#include "FilterResonantLowpass.h"


typedef struct FilterRec
	{
		struct FilterRec*		Next;
		union
			{
				FirstOrderLowpassRec*			FirstOrderLowpass;
				FirstOrderHighpassRec*		FirstOrderHighpass;
				SecondOrderResonRec*			SecondOrderReson;
				SecondOrderZeroRec*				SecondOrderZero;
				ButterworthLowpassRec*		ButterworthLowpass;
				ButterworthHighpassRec*		ButterworthHighpass;
				ButterworthBandpassRec*		ButterworthBandpass;
				ButterworthBandrejectRec*	ButterworthBandreject;
				FilterNullRec*						NullFilter;
				ParametricEqualizerRec*		ParamEQ;
				ResonantLowpassRec*				ResonantLowpass;
				void*											GenericRef;
			} Left;
		union
			{
				FirstOrderLowpassRec*			FirstOrderLowpass;
				FirstOrderHighpassRec*		FirstOrderHighpass;
				SecondOrderResonRec*			SecondOrderReson;
				SecondOrderZeroRec*				SecondOrderZero;
				ButterworthLowpassRec*		ButterworthLowpass;
				ButterworthHighpassRec*		ButterworthHighpass;
				ButterworthBandpassRec*		ButterworthBandpass;
				ButterworthBandrejectRec*	ButterworthBandreject;
				FilterNullRec*						NullFilter;
				ParametricEqualizerRec*		ParamEQ;
				ResonantLowpassRec*				ResonantLowpass;
				void*											GenericRef;
			} Right;
		float								(*ApplyFilter)(void* Ref, float Xin);
		float								CurrentMultiplier;
		FilterTypes					FilterType;
		FilterScalings			FilterScaling;
		float								Cutoff;
		float								CutoffAccent1;
		float								CutoffAccent2;
		float								CutoffAccent3;
		float								CutoffAccent4;
		float								Bandwidth;
		float								BandwidthAccent1;
		float								BandwidthAccent2;
		float								BandwidthAccent3;
		float								BandwidthAccent4;
		float								OutputMultiplier;
		float								OutputMultiplierAccent1;
		float								OutputMultiplierAccent2;
		float								OutputMultiplierAccent3;
		float								OutputMultiplierAccent4;
		float								Gain;
		float								GainAccent1;
		float								GainAccent2;
		float								GainAccent3;
		float								GainAccent4;
	} FilterRec;


struct FilterArrayRec
	{
		/* list of filters to process */
		FilterRec*					Filters;

		/* stuff */
		long								SamplingRate;
		MyBoolean						StereoFlag;

		/* garbage link */
		FilterArrayRec*			Next;
	};


static FilterArrayRec*				FilterArrayFreeList = NIL;
static FilterRec*							FilterFreeList = NIL;


/* flush cached filter array records */
void							FlushCachedFilterArrayStuff(void)
	{
		while (FilterArrayFreeList != NIL)
			{
				FilterArrayRec*		Temp;

				Temp = FilterArrayFreeList;
				FilterArrayFreeList = FilterArrayFreeList->Next;
				ReleasePtr((char*)Temp);
			}
		while (FilterFreeList != NIL)
			{
				FilterRec*				Temp;

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


/* create a new parallel filter processor */
FilterArrayRec*		NewFilterArrayProcessor(struct FilterSpecRec* Template,
										long FramesPerSecond, MyBoolean StereoFlag)
	{
		FilterArrayRec*	Array;
		long						Scan;
		long						Limit;

		CheckPtrExistence(Template);
		if (FilterArrayFreeList != NIL)
			{
				Array = FilterArrayFreeList;
				FilterArrayFreeList = FilterArrayFreeList->Next;
			}
		 else
			{
				Array = (FilterArrayRec*)AllocPtrCanFail(sizeof(FilterArrayRec),"FilterArrayRec");
				if (Array == NIL)
					{
					 FailurePoint1:
						return NIL;
					}
			}
		Array->SamplingRate = FramesPerSecond;
		Array->StereoFlag = StereoFlag;
		Array->Filters = NIL;
		Limit = GetNumFiltersInSpec(Template);
		for (Scan = 0; Scan < Limit; Scan += 1)
			{
				FilterRec*			Filter;
				MyBoolean				LeftChannel;
				MyBoolean				RightChannel;

				if (FilterFreeList != NIL)
					{
						Filter = FilterFreeList;
						FilterFreeList = FilterFreeList->Next;
					}
				 else
					{
						Filter = (FilterRec*)AllocPtrCanFail(sizeof(FilterRec),"FilterRec");
						if (Filter == NIL)
							{
							 FailurePoint2:
								while (Array->Filters != NIL)
									{
										Filter = Array->Filters;
										Array->Filters = Array->Filters->Next;
										switch (Filter->FilterType)
											{
												default:
													EXECUTE(PRERR(ForceAbort,"NewFilterArrayProcessor:  bad filter type"));
													break;
												case eFilterFirstOrderLowpass:
													if (Filter->Left.FirstOrderLowpass != NIL)
														{
															DisposeFirstOrderLowpass(Filter->Left.FirstOrderLowpass);
														}
													if (Filter->Right.FirstOrderLowpass != NIL)
														{
															DisposeFirstOrderLowpass(Filter->Right.FirstOrderLowpass);
														}
													break;
												case eFilterFirstOrderHighpass:
													if (Filter->Left.FirstOrderHighpass != NIL)
														{
															DisposeFirstOrderHighpass(Filter->Left.FirstOrderHighpass);
														}
													if (Filter->Right.FirstOrderHighpass != NIL)
														{
															DisposeFirstOrderHighpass(Filter->Right.FirstOrderHighpass);
														}
													break;
												case eFilterSecondOrderResonant:
													if (Filter->Left.SecondOrderReson != NIL)
														{
															DisposeSecondOrderReson(Filter->Left.SecondOrderReson);
														}
													if (Filter->Right.SecondOrderReson != NIL)
														{
															DisposeSecondOrderReson(Filter->Right.SecondOrderReson);
														}
													break;
												case eFilterSecondOrderZero:
													if (Filter->Left.SecondOrderZero != NIL)
														{
															DisposeSecondOrderZero(Filter->Left.SecondOrderZero);
														}
													if (Filter->Right.SecondOrderZero != NIL)
														{
															DisposeSecondOrderZero(Filter->Right.SecondOrderZero);
														}
													break;
												case eFilterButterworthLowpass:
													if (Filter->Left.ButterworthLowpass != NIL)
														{
															DisposeButterworthLowpass(Filter->Left.ButterworthLowpass);
														}
													if (Filter->Right.ButterworthLowpass != NIL)
														{
															DisposeButterworthLowpass(Filter->Right.ButterworthLowpass);
														}
													break;
												case eFilterButterworthHighpass:
													if (Filter->Left.ButterworthHighpass != NIL)
														{
															DisposeButterworthHighpass(Filter->Left.ButterworthHighpass);
														}
													if (Filter->Right.ButterworthHighpass != NIL)
														{
															DisposeButterworthHighpass(Filter->Right.ButterworthHighpass);
														}
													break;
												case eFilterButterworthBandpass:
													if (Filter->Left.ButterworthBandpass != NIL)
														{
															DisposeButterworthBandpass(Filter->Left.ButterworthBandpass);
														}
													if (Filter->Right.ButterworthBandpass != NIL)
														{
															DisposeButterworthBandpass(Filter->Right.ButterworthBandpass);
														}
													break;
												case eFilterButterworthBandreject:
													if (Filter->Left.ButterworthBandreject != NIL)
														{
															DisposeButterworthBandreject(Filter->Left.ButterworthBandreject);
														}
													if (Filter->Right.ButterworthBandreject != NIL)
														{
															DisposeButterworthBandreject(Filter->Right.ButterworthBandreject);
														}
													break;
												case eFilterNull:
													if (Filter->Left.NullFilter != NIL)
														{
															DisposeFilterNull(Filter->Left.NullFilter);
														}
													if (Filter->Right.NullFilter != NIL)
														{
															DisposeFilterNull(Filter->Right.NullFilter);
														}
													break;
												case eFilterParametricEQ:
													if (Filter->Left.ParamEQ != NIL)
														{
															DisposeParametricEqualizer(Filter->Left.ParamEQ);
														}
													if (Filter->Right.ParamEQ != NIL)
														{
															DisposeParametricEqualizer(Filter->Right.ParamEQ);
														}
													break;
												case eFilterResonantLowpass:
													if (Filter->Left.ResonantLowpass != NIL)
														{
															DisposeResonantLowpass(Filter->Left.ResonantLowpass);
														}
													if (Filter->Right.ResonantLowpass != NIL)
														{
															DisposeResonantLowpass(Filter->Right.ResonantLowpass);
														}
													break;
											}
										ReleasePtr((char*)Filter);
									}
								ReleasePtr((char*)Array);
								goto FailurePoint1;
							}
					}
				Filter->Next = Array->Filters;
				Array->Filters = Filter;
				Filter->FilterType = GetFilterType(Template,Scan);
				Filter->FilterScaling = GetFilterScalingMode(Template,Scan);
				Filter->Cutoff = GetFilterCutoff(Template,Scan);
				Filter->CutoffAccent1 = GetFilterCutoffAccent1(Template,Scan);
				Filter->CutoffAccent2 = GetFilterCutoffAccent2(Template,Scan);
				Filter->CutoffAccent3 = GetFilterCutoffAccent3(Template,Scan);
				Filter->CutoffAccent4 = GetFilterCutoffAccent4(Template,Scan);
				Filter->Bandwidth = GetFilterBandwidth(Template,Scan);
				Filter->BandwidthAccent1 = GetFilterBandwidthAccent1(Template,Scan);
				Filter->BandwidthAccent2 = GetFilterBandwidthAccent2(Template,Scan);
				Filter->BandwidthAccent3 = GetFilterBandwidthAccent3(Template,Scan);
				Filter->BandwidthAccent4 = GetFilterBandwidthAccent4(Template,Scan);
				Filter->OutputMultiplier = GetFilterOutputMultiplier(Template,Scan);
				Filter->OutputMultiplierAccent1 = GetFilterOutputMultiplierAccent1(Template,Scan);
				Filter->OutputMultiplierAccent2 = GetFilterOutputMultiplierAccent2(Template,Scan);
				Filter->OutputMultiplierAccent3 = GetFilterOutputMultiplierAccent3(Template,Scan);
				Filter->OutputMultiplierAccent4 = GetFilterOutputMultiplierAccent4(Template,Scan);
				Filter->Gain = GetFilterGain(Template,Scan);
				Filter->GainAccent1 = GetFilterGainAccent1(Template,Scan);
				Filter->GainAccent2 = GetFilterGainAccent2(Template,Scan);
				Filter->GainAccent3 = GetFilterGainAccent3(Template,Scan);
				Filter->GainAccent4 = GetFilterGainAccent4(Template,Scan);
				Filter->Left.GenericRef = NIL;
				Filter->Right.GenericRef = NIL;
				switch (GetFilterChannel(Template,Scan))
					{
						default:
							EXECUTE(PRERR(ForceAbort,"NewFilterArrayProcessor:  bad channel type"));
							break;
						case eFilterLeft:
							LeftChannel = True;
							RightChannel = False;
							break;
						case eFilterRight:
							LeftChannel = False;
							RightChannel = True;
							break;
						case eFilterBoth:
							LeftChannel = True;
							RightChannel = True;
							break;
					}
				switch (Filter->FilterType)
					{
						default:
							EXECUTE(PRERR(ForceAbort,"NewFilterArrayProcessor:  bad filter type"));
							break;
						case eFilterFirstOrderLowpass:
							if (LeftChannel)
								{
									Filter->Left.FirstOrderLowpass = NewFirstOrderLowpass();
									if (Filter->Left.FirstOrderLowpass == NIL)
										{
										 FailurePoint2a:
											ReleasePtr((char*)Filter);
											goto FailurePoint2;
										}
								}
							if (RightChannel)
								{
									Filter->Right.FirstOrderLowpass = NewFirstOrderLowpass();
									if (Filter->Right.FirstOrderLowpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyFirstOrderLowpass;
							break;
						case eFilterFirstOrderHighpass:
							if (LeftChannel)
								{
									Filter->Left.FirstOrderHighpass = NewFirstOrderHighpass();
									if (Filter->Left.FirstOrderHighpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.FirstOrderHighpass = NewFirstOrderHighpass();
									if (Filter->Right.FirstOrderHighpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyFirstOrderHighpass;
							break;
						case eFilterSecondOrderResonant:
							if (LeftChannel)
								{
									Filter->Left.SecondOrderReson = NewSecondOrderReson();
									if (Filter->Left.SecondOrderReson == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.SecondOrderReson = NewSecondOrderReson();
									if (Filter->Right.SecondOrderReson == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplySecondOrderReson;
							break;
						case eFilterSecondOrderZero:
							if (LeftChannel)
								{
									Filter->Left.SecondOrderZero = NewSecondOrderZero();
									if (Filter->Left.SecondOrderZero == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.SecondOrderZero = NewSecondOrderZero();
									if (Filter->Right.SecondOrderZero == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplySecondOrderZero;
							break;
						case eFilterButterworthLowpass:
							if (LeftChannel)
								{
									Filter->Left.ButterworthLowpass = NewButterworthLowpass();
									if (Filter->Left.ButterworthLowpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.ButterworthLowpass = NewButterworthLowpass();
									if (Filter->Right.ButterworthLowpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyButterworthLowpass;
							break;
						case eFilterButterworthHighpass:
							if (LeftChannel)
								{
									Filter->Left.ButterworthHighpass = NewButterworthHighpass();
									if (Filter->Left.ButterworthHighpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.ButterworthHighpass = NewButterworthHighpass();
									if (Filter->Right.ButterworthHighpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyButterworthHighpass;
							break;
						case eFilterButterworthBandpass:
							if (LeftChannel)
								{
									Filter->Left.ButterworthBandpass = NewButterworthBandpass();
									if (Filter->Left.ButterworthBandpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.ButterworthBandpass = NewButterworthBandpass();
									if (Filter->Right.ButterworthBandpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyButterworthBandpass;
							break;
						case eFilterButterworthBandreject:
							if (LeftChannel)
								{
									Filter->Left.ButterworthBandreject = NewButterworthBandreject();
									if (Filter->Left.ButterworthBandreject == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.ButterworthBandreject = NewButterworthBandreject();
									if (Filter->Right.ButterworthBandreject == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyButterworthBandreject;
							break;
						case eFilterNull:
							if (LeftChannel)
								{
									Filter->Left.NullFilter = NewFilterNull();
									if (Filter->Left.NullFilter == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.NullFilter = NewFilterNull();
									if (Filter->Right.NullFilter == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyFilterNull;
							break;
						case eFilterParametricEQ:
							if (LeftChannel)
								{
									Filter->Left.ParamEQ = NewParametricEqualizer();
									if (Filter->Left.ParamEQ == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.ParamEQ = NewParametricEqualizer();
									if (Filter->Right.ParamEQ == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyParametricEqualizer;
							break;
						case eFilterResonantLowpass:
							if (LeftChannel)
								{
									Filter->Left.ResonantLowpass = NewResonantLowpass(
										GetFilterLowpassOrder(Template,Scan),
										GetFilterBandpassOrder(Template,Scan));
									if (Filter->Left.ResonantLowpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							if (RightChannel)
								{
									Filter->Right.ResonantLowpass = NewResonantLowpass(
										GetFilterLowpassOrder(Template,Scan),
										GetFilterBandpassOrder(Template,Scan));
									if (Filter->Right.ResonantLowpass == NIL)
										{
											goto FailurePoint2a;
										}
								}
							Filter->ApplyFilter = (float (*)(void*,float))&ApplyResonantLowpass;
							break;
					}
			}
		return Array;
	}


/* dispose of the filter processor */
void							DisposeFilterArrayProcessor(FilterArrayRec* Filters)
	{
		CheckPtrExistence(Filters);
		while (Filters->Filters != NIL)
			{
				FilterRec*			Filter;

				Filter = Filters->Filters;
				Filters->Filters = Filters->Filters->Next;
				switch (Filter->FilterType)
					{
						default:
							EXECUTE(PRERR(ForceAbort,"DisposeFilterArrayProcessor:  bad filter type"));
							break;
						case eFilterFirstOrderLowpass:
							if (Filter->Left.FirstOrderLowpass != NIL)
								{
									DisposeFirstOrderLowpass(Filter->Left.FirstOrderLowpass);
								}
							if (Filter->Right.FirstOrderLowpass != NIL)
								{
									DisposeFirstOrderLowpass(Filter->Right.FirstOrderLowpass);
								}
							break;
						case eFilterFirstOrderHighpass:
							if (Filter->Left.FirstOrderHighpass != NIL)
								{
									DisposeFirstOrderHighpass(Filter->Left.FirstOrderHighpass);
								}
							if (Filter->Right.FirstOrderHighpass != NIL)
								{
									DisposeFirstOrderHighpass(Filter->Right.FirstOrderHighpass);
								}
							break;
						case eFilterSecondOrderResonant:
							if (Filter->Left.SecondOrderReson != NIL)
								{
									DisposeSecondOrderReson(Filter->Left.SecondOrderReson);
								}
							if (Filter->Right.SecondOrderReson != NIL)
								{
									DisposeSecondOrderReson(Filter->Right.SecondOrderReson);
								}
							break;
						case eFilterSecondOrderZero:
							if (Filter->Left.SecondOrderZero != NIL)
								{
									DisposeSecondOrderZero(Filter->Left.SecondOrderZero);
								}
							if (Filter->Right.SecondOrderZero != NIL)
								{
									DisposeSecondOrderZero(Filter->Right.SecondOrderZero);
								}
							break;
						case eFilterButterworthLowpass:
							if (Filter->Left.ButterworthLowpass != NIL)
								{
									DisposeButterworthLowpass(Filter->Left.ButterworthLowpass);
								}
							if (Filter->Right.ButterworthLowpass != NIL)
								{
									DisposeButterworthLowpass(Filter->Right.ButterworthLowpass);
								}
							break;
						case eFilterButterworthHighpass:
							if (Filter->Left.ButterworthHighpass != NIL)
								{
									DisposeButterworthHighpass(Filter->Left.ButterworthHighpass);
								}
							if (Filter->Right.ButterworthHighpass != NIL)
								{
									DisposeButterworthHighpass(Filter->Right.ButterworthHighpass);
								}
							break;
						case eFilterButterworthBandpass:
							if (Filter->Left.ButterworthBandpass != NIL)
								{
									DisposeButterworthBandpass(Filter->Left.ButterworthBandpass);
								}
							if (Filter->Right.ButterworthBandpass != NIL)
								{
									DisposeButterworthBandpass(Filter->Right.ButterworthBandpass);
								}
							break;
						case eFilterButterworthBandreject:
							if (Filter->Left.ButterworthBandreject != NIL)
								{
									DisposeButterworthBandreject(Filter->Left.ButterworthBandreject);
								}
							if (Filter->Right.ButterworthBandreject != NIL)
								{
									DisposeButterworthBandreject(Filter->Right.ButterworthBandreject);
								}
							break;
						case eFilterNull:
							if (Filter->Left.NullFilter != NIL)
								{
									DisposeFilterNull(Filter->Left.NullFilter);
								}
							if (Filter->Right.NullFilter != NIL)
								{
									DisposeFilterNull(Filter->Right.NullFilter);
								}
							break;
						case eFilterParametricEQ:
							if (Filter->Left.ParamEQ != NIL)
								{
									DisposeParametricEqualizer(Filter->Left.ParamEQ);
								}
							if (Filter->Right.ParamEQ != NIL)
								{
									DisposeParametricEqualizer(Filter->Right.ParamEQ);
								}
							break;
						case eFilterResonantLowpass:
							if (Filter->Left.ResonantLowpass != NIL)
								{
									DisposeResonantLowpass(Filter->Left.ResonantLowpass);
								}
							if (Filter->Right.ResonantLowpass != NIL)
								{
									DisposeResonantLowpass(Filter->Right.ResonantLowpass);
								}
							break;
					}
				Filter->Next = FilterFreeList;
				FilterFreeList = Filter;
			}
		Filters->Next = FilterArrayFreeList;
		FilterArrayFreeList = Filters;
	}


/* update filter state with accent information */
void							UpdateFilterArrayState(FilterArrayRec* Filters, float Accent1,
										float Accent2, float Accent3, float Accent4)
	{
		FilterRec*			Scan;

		CheckPtrExistence(Filters);
		Scan = Filters->Filters;
		while (Scan != NIL)
			{
				float						Cutoff;
				float						Bandwidth;
				float						Gain;

				Scan->CurrentMultiplier = Scan->OutputMultiplier
					+ Scan->OutputMultiplierAccent1 * Accent1
					+ Scan->OutputMultiplierAccent2 * Accent2
					+ Scan->OutputMultiplierAccent3 * Accent3
					+ Scan->OutputMultiplierAccent4 * Accent4;
				Cutoff = Scan->Cutoff + Scan->CutoffAccent1 * Accent1
					+ Scan->CutoffAccent2 * Accent2 + Scan->CutoffAccent3 * Accent3
					+ Scan->CutoffAccent4 * Accent4;
				switch (Scan->FilterType)
					{
						default:
							EXECUTE(PRERR(ForceAbort,"UpdateFilterArrayState:  bad filter type"));
							break;
						case eFilterFirstOrderLowpass:
							if (Scan->Left.FirstOrderLowpass != NIL)
								{
									SetFirstOrderLowpassCoefficients(Scan->Left.FirstOrderLowpass,
										Cutoff,Filters->SamplingRate);
								}
							if (Scan->Right.FirstOrderLowpass != NIL)
								{
									SetFirstOrderLowpassCoefficients(Scan->Right.FirstOrderLowpass,
										Cutoff,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterFirstOrderHighpass:
							if (Scan->Left.FirstOrderHighpass != NIL)
								{
									SetFirstOrderHighpassCoefficients(Scan->Left.FirstOrderHighpass,
										Cutoff,Filters->SamplingRate);
								}
							if (Scan->Right.FirstOrderHighpass != NIL)
								{
									SetFirstOrderHighpassCoefficients(Scan->Right.FirstOrderHighpass,
										Cutoff,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterSecondOrderResonant:
							Bandwidth = Scan->Bandwidth + Scan->BandwidthAccent1 * Accent1
								+ Scan->BandwidthAccent2 * Accent2 + Scan->BandwidthAccent3 * Accent3
								+ Scan->BandwidthAccent4 * Accent4;
							if (Scan->Left.SecondOrderReson != NIL)
								{
									SetSecondOrderResonCoefficients(Scan->Left.SecondOrderReson,
										Cutoff,Bandwidth,Scan->FilterScaling,Filters->SamplingRate);
								}
							if (Scan->Right.SecondOrderReson != NIL)
								{
									SetSecondOrderResonCoefficients(Scan->Right.SecondOrderReson,
										Cutoff,Bandwidth,Scan->FilterScaling,Filters->SamplingRate);
								}
							break;
						case eFilterSecondOrderZero:
							Bandwidth = Scan->Bandwidth + Scan->BandwidthAccent1 * Accent1
								+ Scan->BandwidthAccent2 * Accent2 + Scan->BandwidthAccent3 * Accent3
								+ Scan->BandwidthAccent4 * Accent4;
							if (Scan->Left.SecondOrderZero != NIL)
								{
									SetSecondOrderZeroCoefficients(Scan->Left.SecondOrderZero,
										Cutoff,Bandwidth,Scan->FilterScaling,Filters->SamplingRate);
								}
							if (Scan->Right.SecondOrderZero != NIL)
								{
									SetSecondOrderZeroCoefficients(Scan->Right.SecondOrderZero,
										Cutoff,Bandwidth,Scan->FilterScaling,Filters->SamplingRate);
								}
							break;
						case eFilterButterworthLowpass:
							if (Scan->Left.ButterworthLowpass != NIL)
								{
									SetButterworthLowpassCoefficients(Scan->Left.ButterworthLowpass,
										Cutoff,Filters->SamplingRate);
								}
							if (Scan->Right.ButterworthLowpass != NIL)
								{
									SetButterworthLowpassCoefficients(Scan->Right.ButterworthLowpass,
										Cutoff,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterButterworthHighpass:
							if (Scan->Left.ButterworthHighpass != NIL)
								{
									SetButterworthHighpassCoefficients(Scan->Left.ButterworthHighpass,
										Cutoff,Filters->SamplingRate);
								}
							if (Scan->Right.ButterworthHighpass != NIL)
								{
									SetButterworthHighpassCoefficients(Scan->Right.ButterworthHighpass,
										Cutoff,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterButterworthBandpass:
							Bandwidth = Scan->Bandwidth + Scan->BandwidthAccent1 * Accent1
								+ Scan->BandwidthAccent2 * Accent2 + Scan->BandwidthAccent3 * Accent3
								+ Scan->BandwidthAccent4 * Accent4;
							if (Scan->Left.ButterworthBandpass != NIL)
								{
									SetButterworthBandpassCoefficients(Scan->Left.ButterworthBandpass,
										Cutoff,Bandwidth,Filters->SamplingRate);
								}
							if (Scan->Right.ButterworthBandpass != NIL)
								{
									SetButterworthBandpassCoefficients(Scan->Right.ButterworthBandpass,
										Cutoff,Bandwidth,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterButterworthBandreject:
							Bandwidth = Scan->Bandwidth + Scan->BandwidthAccent1 * Accent1
								+ Scan->BandwidthAccent2 * Accent2 + Scan->BandwidthAccent3 * Accent3
								+ Scan->BandwidthAccent4 * Accent4;
							if (Scan->Left.ButterworthBandreject != NIL)
								{
									SetButterworthBandrejectCoefficients(Scan->Left.ButterworthBandreject,
										Cutoff,Bandwidth,Filters->SamplingRate);
								}
							if (Scan->Right.ButterworthBandreject != NIL)
								{
									SetButterworthBandrejectCoefficients(Scan->Right.ButterworthBandreject,
										Cutoff,Bandwidth,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterNull:
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterParametricEQ:
							Bandwidth = Scan->Bandwidth + Scan->BandwidthAccent1 * Accent1
								+ Scan->BandwidthAccent2 * Accent2 + Scan->BandwidthAccent3 * Accent3
								+ Scan->BandwidthAccent4 * Accent4;
							Gain = Scan->Gain + Scan->GainAccent1 * Accent1
								+ Scan->GainAccent2 * Accent2 + Scan->GainAccent3 * Accent3
								+ Scan->GainAccent4 * Accent4;
							if (Scan->Left.ParamEQ != NIL)
								{
									SetParametricEqualizerCoefficients(Scan->Left.ParamEQ,
										Cutoff,Bandwidth,Gain,Filters->SamplingRate);
								}
							if (Scan->Right.ParamEQ != NIL)
								{
									SetParametricEqualizerCoefficients(Scan->Right.ParamEQ,
										Cutoff,Bandwidth,Gain,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
						case eFilterResonantLowpass:
							Bandwidth = Scan->Bandwidth + Scan->BandwidthAccent1 * Accent1
								+ Scan->BandwidthAccent2 * Accent2 + Scan->BandwidthAccent3 * Accent3
								+ Scan->BandwidthAccent4 * Accent4;
							Gain = Scan->Gain + Scan->GainAccent1 * Accent1
								+ Scan->GainAccent2 * Accent2 + Scan->GainAccent3 * Accent3
								+ Scan->GainAccent4 * Accent4;
							if (Scan->Left.ResonantLowpass != NIL)
								{
									SetResonantLowpassCoefficients(Scan->Left.ResonantLowpass,
										Cutoff,Bandwidth,Gain,Filters->SamplingRate);
								}
							if (Scan->Right.ResonantLowpass != NIL)
								{
									SetResonantLowpassCoefficients(Scan->Right.ResonantLowpass,
										Cutoff,Bandwidth,Gain,Filters->SamplingRate);
								}
							ERROR(Scan->FilterScaling != eFilterDefaultScaling,PRERR(ForceAbort,
								"UpdateFilterArrayState:  bad scaling type"));
							break;
					}
				Scan = Scan->Next;
			}
	}


/* apply filter processing to some stuff */
void							ApplyFilterArray(largefixedsigned* Data, long NumFrames,
										FilterArrayRec* Filters)
	{
		long						Scan;

		CheckPtrExistence(Data);
		CheckPtrExistence(Filters);
		if (Filters->StereoFlag)
			{
				for (Scan = 0; Scan < NumFrames; Scan += 1)
					{
						float						LeftInput;
						float						LeftOutput;
						float						RightInput;
						float						RightOutput;
						FilterRec*			Filter;
		
						PRNGCHK(Data,&(Data[2 * Scan]),sizeof(Data[2 * Scan]));
						PRNGCHK(Data,&(Data[2 * Scan + 1]),sizeof(Data[2 * Scan + 1]));
						LeftInput = largefixed2single(Data[2 * Scan]);
						RightInput = largefixed2single(Data[2 * Scan + 1]);
						LeftOutput = 0;
						RightOutput = 0;
						Filter = Filters->Filters;
						while (Filter != NIL)
							{
								if (Filter->Left.GenericRef != NIL)
									{
										LeftOutput += Filter->CurrentMultiplier
											* (*Filter->ApplyFilter)(Filter->Left.GenericRef,LeftInput);
									}
								if (Filter->Right.GenericRef != NIL)
									{
										RightOutput += Filter->CurrentMultiplier
											* (*Filter->ApplyFilter)(Filter->Right.GenericRef,RightInput);
									}
								Filter = Filter->Next;
							}
						Data[2 * Scan] = double2largefixed(LeftOutput);
						Data[2 * Scan + 1] = double2largefixed(RightOutput);
					}
			}
		 else
			{
				for (Scan = 0; Scan < NumFrames; Scan += 1)
					{
						float						LeftInput;
						float						LeftOutput;
						float						RightInput;
						float						RightOutput;
						FilterRec*			Filter;
		
						PRNGCHK(Data,&(Data[Scan]),sizeof(Data[Scan]));
						LeftInput = largefixed2single(Data[Scan]);
						RightInput = largefixed2single(Data[Scan]);
						LeftOutput = 0;
						RightOutput = 0;
						Filter = Filters->Filters;
						while (Filter != NIL)
							{
								if (Filter->Left.GenericRef != NIL)
									{
										LeftOutput += Filter->CurrentMultiplier
											* (*Filter->ApplyFilter)(Filter->Left.GenericRef,LeftInput);
									}
								if (Filter->Right.GenericRef != NIL)
									{
										RightOutput += Filter->CurrentMultiplier
											* (*Filter->ApplyFilter)(Filter->Right.GenericRef,RightInput);
									}
								Filter = Filter->Next;
							}
						Data[Scan] = double2largefixed((LeftOutput + RightOutput) / 2);
					}
			}
	}
