/* EffectSpecList.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 "EffectSpecList.h"
#include "Memory.h"
#include "Array.h"
#include "DelayEffectSpec.h"
#include "NonlinearProcSpec.h"
#include "FilterSpec.h"
#include "AnalyzerSpec.h"


typedef struct
	{
		EffectTypes				Type;
		union
			{
				struct DelayEffectRec*		DelayEffectSpec;
				struct NonlinProcSpecRec*	NLProcEffectSpec;
				struct FilterSpecRec*			FilterEffectSpec;
				struct AnalyzerSpecRec*		AnalyzerEffectSpec;
			} u;
	} EffectNodeRec;


struct EffectSpecListRec
	{
		ArrayRec*					List;
	};


/* create a new effect list */
EffectSpecListRec*	NewEffectSpecList(void)
	{
		EffectSpecListRec*	EffectSpecList;

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


/* dispose of an effect list */
void								DisposeEffectSpecList(EffectSpecListRec* EffectSpecList)
	{
		long							Scan;
		long							Limit;

		CheckPtrExistence(EffectSpecList);
		Limit = GetEffectSpecListLength(EffectSpecList);
		for (Scan = 0; Scan < Limit; Scan += 1)
			{
				EffectNodeRec*		OneEffect;

				OneEffect = (EffectNodeRec*)ArrayGetElement(EffectSpecList->List,Scan);
				CheckPtrExistence(OneEffect);
				switch (OneEffect->Type)
					{
						default:
							EXECUTE(PRERR(ForceAbort,"DisposeEffectSpecList:  unknown effect type"));
							break;
						case eDelayEffect:
							DisposeDelayLineSpec(OneEffect->u.DelayEffectSpec);
							break;
						case eNLProcEffect:
							DisposeNonlinProcSpec(OneEffect->u.NLProcEffectSpec);
							break;
						case eFilterEffect:
							DisposeFilterSpec(OneEffect->u.FilterEffectSpec);
							break;
						case eAnalyzerEffect:
							DisposeAnalyzerSpec(OneEffect->u.AnalyzerEffectSpec);
							break;
					}
				ReleasePtr((char*)OneEffect);
			}
		DisposeArray(EffectSpecList->List);
		ReleasePtr((char*)EffectSpecList);
	}


/* add a delay effect to the spec list */
MyBoolean						AddDelayToEffectSpecList(EffectSpecListRec* EffectSpecList,
											struct DelayEffectRec* DelaySpec)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		CheckPtrExistence(DelaySpec);
		Effect = (EffectNodeRec*)AllocPtrCanFail(sizeof(EffectNodeRec),"EffectNodeRec");
		if (Effect == NIL)
			{
			 FailurePoint1:
				return False;
			}
		Effect->Type = eDelayEffect;
		Effect->u.DelayEffectSpec = DelaySpec;
		if (!ArrayAppendElement(EffectSpecList->List,Effect))
			{
			 FailurePoint2:
				ReleasePtr((char*)Effect);
				goto FailurePoint1;
			}
		return True;
	}


/* add a nonlinear processor to the spec list */
MyBoolean						AddNLProcToEffectSpecList(EffectSpecListRec* EffectSpecList,
											struct NonlinProcSpecRec* NLProcSpec)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		CheckPtrExistence(NLProcSpec);
		Effect = (EffectNodeRec*)AllocPtrCanFail(sizeof(EffectNodeRec),"EffectNodeRec");
		if (Effect == NIL)
			{
			 FailurePoint1:
				return False;
			}
		Effect->Type = eNLProcEffect;
		Effect->u.NLProcEffectSpec = NLProcSpec;
		if (!ArrayAppendElement(EffectSpecList->List,Effect))
			{
			 FailurePoint2:
				ReleasePtr((char*)Effect);
				goto FailurePoint1;
			}
		return True;
	}


/* add a parallel filter array to the spec list */
MyBoolean						AddFilterToEffectSpecList(EffectSpecListRec* EffectSpecList,
											struct FilterSpecRec* FilterSpec)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		CheckPtrExistence(FilterSpec);
		Effect = (EffectNodeRec*)AllocPtrCanFail(sizeof(EffectNodeRec),"EffectNodeRec");
		if (Effect == NIL)
			{
			 FailurePoint1:
				return False;
			}
		Effect->Type = eFilterEffect;
		Effect->u.FilterEffectSpec = FilterSpec;
		if (!ArrayAppendElement(EffectSpecList->List,Effect))
			{
			 FailurePoint2:
				ReleasePtr((char*)Effect);
				goto FailurePoint1;
			}
		return True;
	}


/* add an analyzer to the spec list */
MyBoolean						AddAnalyzerToEffectSpecList(EffectSpecListRec* EffectSpecList,
											struct AnalyzerSpecRec* AnalyzerSpec)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		CheckPtrExistence(AnalyzerSpec);
		Effect = (EffectNodeRec*)AllocPtrCanFail(sizeof(EffectNodeRec),"EffectNodeRec");
		if (Effect == NIL)
			{
			 FailurePoint1:
				return False;
			}
		Effect->Type = eAnalyzerEffect;
		Effect->u.AnalyzerEffectSpec = AnalyzerSpec;
		if (!ArrayAppendElement(EffectSpecList->List,Effect))
			{
			 FailurePoint2:
				ReleasePtr((char*)Effect);
				goto FailurePoint1;
			}
		return True;
	}


/* find out how many effects are in the list */
long								GetEffectSpecListLength(EffectSpecListRec* EffectSpecList)
	{
		CheckPtrExistence(EffectSpecList);
		return ArrayGetLength(EffectSpecList->List);
	}


/* get the type of the specified effect */
EffectTypes					GetEffectSpecListElementType(EffectSpecListRec* EffectSpecList,
											long Index)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		ERROR((Index < 0) || (Index >= GetEffectSpecListLength(EffectSpecList)),
			PRERR(ForceAbort,"GetEffectSpecListElementType:  index out of range"));
		Effect = (EffectNodeRec*)ArrayGetElement(EffectSpecList->List,Index);
		CheckPtrExistence(Effect);
		return Effect->Type;
	}


/* get the delay effect at the specified index */
struct DelayEffectRec*	GetDelayEffectFromEffectSpecList(
											EffectSpecListRec* EffectSpecList, long Index)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		ERROR((Index < 0) || (Index >= GetEffectSpecListLength(EffectSpecList)),
			PRERR(ForceAbort,"GetDelayEffectFromEffectSpecList:  index out of range"));
		Effect = (EffectNodeRec*)ArrayGetElement(EffectSpecList->List,Index);
		CheckPtrExistence(Effect);
		ERROR(Effect->Type != eDelayEffect,PRERR(ForceAbort,
			"GetDelayEffectFromEffectSpecList:  effect isn't a delay"));
		return Effect->u.DelayEffectSpec;
	}


/* get the nonlinear processor from the specified index */
struct NonlinProcSpecRec*	GetNLProcEffectFromEffectSpecList(
											EffectSpecListRec* EffectSpecList, long Index)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		ERROR((Index < 0) || (Index >= GetEffectSpecListLength(EffectSpecList)),
			PRERR(ForceAbort,"GetNLProcEffectFromEffectSpecList:  index out of range"));
		Effect = (EffectNodeRec*)ArrayGetElement(EffectSpecList->List,Index);
		CheckPtrExistence(Effect);
		ERROR(Effect->Type != eNLProcEffect,PRERR(ForceAbort,
			"GetNLProcEffectFromEffectSpecList:  effect isn't a nonlinear processor"));
		return Effect->u.NLProcEffectSpec;
	}


/* get the filter from the specified index */
struct FilterSpecRec*	GetFilterEffectFromEffectSpecList(
											EffectSpecListRec* EffectSpecList, long Index)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		ERROR((Index < 0) || (Index >= GetEffectSpecListLength(EffectSpecList)),
			PRERR(ForceAbort,"GetFilterEffectFromEffectSpecList:  index out of range"));
		Effect = (EffectNodeRec*)ArrayGetElement(EffectSpecList->List,Index);
		CheckPtrExistence(Effect);
		ERROR(Effect->Type != eFilterEffect,PRERR(ForceAbort,
			"GetFilterEffectFromEffectSpecList:  effect isn't a filter"));
		return Effect->u.FilterEffectSpec;
	}


struct AnalyzerSpecRec*	GetAnalyzerEffectFromEffectSpecList(
											EffectSpecListRec* EffectSpecList, long Index)
	{
		EffectNodeRec*		Effect;

		CheckPtrExistence(EffectSpecList);
		ERROR((Index < 0) || (Index >= GetEffectSpecListLength(EffectSpecList)),
			PRERR(ForceAbort,"GetAnalyzerEffectFromEffectSpecList:  index out of range"));
		Effect = (EffectNodeRec*)ArrayGetElement(EffectSpecList->List,Index);
		CheckPtrExistence(Effect);
		ERROR(Effect->Type != eAnalyzerEffect,PRERR(ForceAbort,
			"GetAnalyzerEffectFromEffectSpecList:  effect isn't a analyzer"));
		return Effect->u.AnalyzerEffectSpec;
	}
