/* FilterSecondOrderReson.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.             */
/*                                                                           */
/*****************************************************************************/

/* Based on material from pages 184-190 of */
/* Dodge, Charles and Jerse, Thomas A. */
/* Computer Music:  Synthesis, Composition, and Performance */
/* Schirmer Books, New York, 1985 */

#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"

#include "FilterSecondOrderReson.h"
#include "Memory.h"
#include "FloatingPoint.h"


struct SecondOrderResonRec
	{
		/* link */
		SecondOrderResonRec*		Next;

		/* state variables */
		float										Ym1;
		float										Ym2;

		/* coefficients */
		float										A0;
		float										B1;
		float										B2;
	};


static SecondOrderResonRec*		FreeList = NIL;


/* flush free list */
void											FlushCachedSecondOrderResonStuff(void)
	{
		while (FreeList != NIL)
			{
				SecondOrderResonRec*		Temp;

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


/* create a new filter record */
SecondOrderResonRec*			NewSecondOrderReson(void)
	{
		SecondOrderResonRec*		Filter;

		if (FreeList != NIL)
			{
				Filter = FreeList;
				FreeList = FreeList->Next;
			}
		 else
			{
				Filter = (SecondOrderResonRec*)AllocPtrCanFail(sizeof(SecondOrderResonRec),
					"SecondOrderResonRec");
				if (Filter == NIL)
					{
						return NIL;
					}
			}
		Filter->Ym1 = 0;
		Filter->Ym2 = 0;
		return Filter;
	}


/* dispose filter record */
void											DisposeSecondOrderReson(SecondOrderResonRec* Filter)
	{
		CheckPtrExistence(Filter);
		Filter->Next = FreeList;
		FreeList = Filter;
	}


/* adjust filter coefficients */
void											SetSecondOrderResonCoefficients(SecondOrderResonRec* Filter,
														float Cutoff, float Bandwidth, FilterScalings Scaling,
														long SamplingRate)
	{
		CheckPtrExistence(Filter);
		Filter->B2 = DEXP(-6.28318530717958648 * Bandwidth / SamplingRate);
		Filter->B1 = ((-4 * Filter->B2) / (1 + Filter->B2))
			* DCOS(6.28318530717958648 * Cutoff / SamplingRate);
		switch (Scaling)
			{
				default:
					EXECUTE(PRERR(ForceAbort,"SetSecondOrderResonCoefficients:  unknown scaling"));
					break;
				case eFilterDefaultScaling:
					Filter->A0 = 1;
					break;
				case eFilterResonMidbandGain1:
					Filter->A0 = (1 - Filter->B2) * DSQRT(1 - Filter->B1 * Filter->B1
						/ (4 * Filter->B2));
					break;
				case eFilterResonNoiseGain1:
					{
						float										X;
						float										Y;

						X = 1 + Filter->B2;
						Y = 1 - Filter->B2;
						Filter->A0 = DSQRT( (X * X - Filter->B1 * Filter->B1)
							* Y / X);
					}
					break;
			}
	}


/* apply filter to a sample value */
float											ApplySecondOrderReson(SecondOrderResonRec* Filter, float Xin)
	{
		float										Y;

		CheckPtrExistence(Filter);
		Y = Filter->A0 * Xin - Filter->B1 * Filter->Ym1 - Filter->B2 * Filter->Ym2;
		Filter->Ym2 = Filter->Ym1;
		Filter->Ym1 = Y;
		return Y;
	}
