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


struct NonlinProcSpecRec
	{
		/* what kind of effect */
		NLProcWaveType			WaveType;
		union
			{
				struct WaveTableObjectRec*			DataWaveTable;
				struct AlgoWaveTableObjectRec*	AlgoWaveTable;
			} u;

		/* these controls only apply to the track effect, not the oscillator effect */
		float								InputScaling;
		float								InputAccent1;
		float								InputAccent2;
		float								InputAccent3;
		float								InputAccent4;
		float								OutputScaling;
		float								OutputAccent1;
		float								OutputAccent2;
		float								OutputAccent3;
		float								OutputAccent4;
		float								WaveTableIndex;
		float								IndexAccent1;
		float								IndexAccent2;
		float								IndexAccent3;
		float								IndexAccent4;

		/* these controls apply only to the oscillator effect, not the track effect */
		EnvelopeRec*				InputEnvelope;
		EnvelopeRec*				OutputEvelope;
		EnvelopeRec*				IndexEnvelope;
		LFOListSpecRec*			InputLFO;
		LFOListSpecRec*			OutputLFO;
		LFOListSpecRec*			IndexLFO;
	};


/* create a new nonlinear processor specifier */
NonlinProcSpecRec*	NewNonlinProcSpecDataWave(struct WaveTableObjectRec* Wave)
	{
		NonlinProcSpecRec*	NLProc;

		CheckPtrExistence(Wave);
		NLProc = (NonlinProcSpecRec*)AllocPtrCanFail(sizeof(NonlinProcSpecRec),
			"NonlinProcSpecRec");
		if (NLProc == NIL)
			{
			 FailurePoint1:
				return NIL;
			}
		NLProc->InputEnvelope = NewEnvelope();
		if (NLProc->InputEnvelope == NIL)
			{
			 FailurePoint2:
				ReleasePtr((char*)NLProc);
				goto FailurePoint1;
			}
		NLProc->OutputEvelope = NewEnvelope();
		if (NLProc->OutputEvelope == NIL)
			{
			 FailurePoint3:
				DisposeEnvelope(NLProc->InputEnvelope);
				goto FailurePoint2;
			}
		NLProc->IndexEnvelope = NewEnvelope();
		if (NLProc->IndexEnvelope == NIL)
			{
			 FailurePoint4:
				DisposeEnvelope(NLProc->OutputEvelope);
				goto FailurePoint3;
			}
		NLProc->InputLFO = NewLFOListSpecifier();
		if (NLProc->InputLFO == NIL)
			{
			 FailurePoint5:
				DisposeEnvelope(NLProc->IndexEnvelope);
				goto FailurePoint4;
			}
		NLProc->OutputLFO = NewLFOListSpecifier();
		if (NLProc->OutputLFO == NIL)
			{
			 FailurePoint6:
				DisposeLFOListSpecifier(NLProc->InputLFO);
				goto FailurePoint5;
			}
		NLProc->IndexLFO = NewLFOListSpecifier();
		if (NLProc->IndexLFO == NIL)
			{
			 FailurePoint7:
				DisposeLFOListSpecifier(NLProc->OutputLFO);
				goto FailurePoint6;
			}
		NLProc->WaveType = eNLDataWaveTable;
		NLProc->u.DataWaveTable = Wave;
		NLProc->InputScaling = 1;
		NLProc->InputAccent1 = 0;
		NLProc->InputAccent2 = 0;
		NLProc->InputAccent3 = 0;
		NLProc->InputAccent4 = 0;
		NLProc->OutputScaling = 1;
		NLProc->OutputAccent1 = 0;
		NLProc->OutputAccent2 = 0;
		NLProc->OutputAccent3 = 0;
		NLProc->OutputAccent4 = 0;
		NLProc->WaveTableIndex = 0;
		NLProc->IndexAccent1 = 0;
		NLProc->IndexAccent2 = 0;
		NLProc->IndexAccent3 = 0;
		NLProc->IndexAccent4 = 0;
		return NLProc;
	}


/* create a new nonlinear processor specifier */
NonlinProcSpecRec*	NewNonlinProcSpecAlgoWave(struct AlgoWaveTableObjectRec* Wave)
	{
		NonlinProcSpecRec*	NLProc;

		CheckPtrExistence(Wave);
		NLProc = (NonlinProcSpecRec*)AllocPtrCanFail(sizeof(NonlinProcSpecRec),
			"NonlinProcSpecRec");
		if (NLProc == NIL)
			{
			 FailurePoint1:
				return NIL;
			}
		NLProc->InputEnvelope = NewEnvelope();
		if (NLProc->InputEnvelope == NIL)
			{
			 FailurePoint2:
				ReleasePtr((char*)NLProc);
				goto FailurePoint1;
			}
		NLProc->OutputEvelope = NewEnvelope();
		if (NLProc->OutputEvelope == NIL)
			{
			 FailurePoint3:
				DisposeEnvelope(NLProc->InputEnvelope);
				goto FailurePoint2;
			}
		NLProc->IndexEnvelope = NewEnvelope();
		if (NLProc->IndexEnvelope == NIL)
			{
			 FailurePoint4:
				DisposeEnvelope(NLProc->OutputEvelope);
				goto FailurePoint3;
			}
		NLProc->InputLFO = NewLFOListSpecifier();
		if (NLProc->InputLFO == NIL)
			{
			 FailurePoint5:
				DisposeEnvelope(NLProc->IndexEnvelope);
				goto FailurePoint4;
			}
		NLProc->OutputLFO = NewLFOListSpecifier();
		if (NLProc->OutputLFO == NIL)
			{
			 FailurePoint6:
				DisposeLFOListSpecifier(NLProc->InputLFO);
				goto FailurePoint5;
			}
		NLProc->IndexLFO = NewLFOListSpecifier();
		if (NLProc->IndexLFO == NIL)
			{
			 FailurePoint7:
				DisposeLFOListSpecifier(NLProc->OutputLFO);
				goto FailurePoint6;
			}
		NLProc->WaveType = eNLAlgoWaveTable;
		NLProc->u.AlgoWaveTable = Wave;
		NLProc->InputScaling = 1;
		NLProc->InputAccent1 = 0;
		NLProc->InputAccent2 = 0;
		NLProc->InputAccent3 = 0;
		NLProc->InputAccent4 = 0;
		NLProc->OutputScaling = 1;
		NLProc->OutputAccent1 = 0;
		NLProc->OutputAccent2 = 0;
		NLProc->OutputAccent3 = 0;
		NLProc->OutputAccent4 = 0;
		return NLProc;
	}


/* dispose of the nonlinear processor specifier */
void								DisposeNonlinProcSpec(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		DisposeEnvelope(NLProc->InputEnvelope);
		DisposeEnvelope(NLProc->OutputEvelope);
		DisposeEnvelope(NLProc->IndexEnvelope);
		DisposeLFOListSpecifier(NLProc->InputLFO);
		DisposeLFOListSpecifier(NLProc->OutputLFO);
		DisposeLFOListSpecifier(NLProc->IndexLFO);
		ReleasePtr((char*)NLProc);
	}


void								PutNLProcInputScaling(NonlinProcSpecRec* NLProc, float InputScaling)
	{
		CheckPtrExistence(NLProc);
		NLProc->InputScaling = InputScaling;
	}


void								PutNLProcInputAccent1(NonlinProcSpecRec* NLProc, float InputAccent1)
	{
		CheckPtrExistence(NLProc);
		NLProc->InputAccent1 = InputAccent1;
	}


void								PutNLProcInputAccent2(NonlinProcSpecRec* NLProc, float InputAccent2)
	{
		CheckPtrExistence(NLProc);
		NLProc->InputAccent2 = InputAccent2;
	}


void								PutNLProcInputAccent3(NonlinProcSpecRec* NLProc, float InputAccent3)
	{
		CheckPtrExistence(NLProc);
		NLProc->InputAccent3 = InputAccent3;
	}


void								PutNLProcInputAccent4(NonlinProcSpecRec* NLProc, float InputAccent4)
	{
		CheckPtrExistence(NLProc);
		NLProc->InputAccent4 = InputAccent4;
	}


void								PutNLProcOutputScaling(NonlinProcSpecRec* NLProc, float OutputScaling)
	{
		CheckPtrExistence(NLProc);
		NLProc->OutputScaling = OutputScaling;
	}


void								PutNLProcOutputAccent1(NonlinProcSpecRec* NLProc, float OutputAccent1)
	{
		CheckPtrExistence(NLProc);
		NLProc->OutputAccent1 = OutputAccent1;
	}


void								PutNLProcOutputAccent2(NonlinProcSpecRec* NLProc, float OutputAccent2)
	{
		CheckPtrExistence(NLProc);
		NLProc->OutputAccent2 = OutputAccent2;
	}


void								PutNLProcOutputAccent3(NonlinProcSpecRec* NLProc, float OutputAccent3)
	{
		CheckPtrExistence(NLProc);
		NLProc->OutputAccent3 = OutputAccent3;
	}


void								PutNLProcOutputAccent4(NonlinProcSpecRec* NLProc, float OutputAccent4)
	{
		CheckPtrExistence(NLProc);
		NLProc->OutputAccent4 = OutputAccent4;
	}


void								PutNLProcWaveTableIndex(NonlinProcSpecRec* NLProc, float WaveTableIndex)
	{
		CheckPtrExistence(NLProc);
		NLProc->WaveTableIndex = WaveTableIndex;
	}


void								PutNLProcIndexAccent1(NonlinProcSpecRec* NLProc, float IndexAccent1)
	{
		CheckPtrExistence(NLProc);
		NLProc->IndexAccent1 = IndexAccent1;
	}


void								PutNLProcIndexAccent2(NonlinProcSpecRec* NLProc, float IndexAccent2)
	{
		CheckPtrExistence(NLProc);
		NLProc->IndexAccent2 = IndexAccent2;
	}


void								PutNLProcIndexAccent3(NonlinProcSpecRec* NLProc, float IndexAccent3)
	{
		CheckPtrExistence(NLProc);
		NLProc->IndexAccent3 = IndexAccent3;
	}


void								PutNLProcIndexAccent4(NonlinProcSpecRec* NLProc, float IndexAccent4)
	{
		CheckPtrExistence(NLProc);
		NLProc->IndexAccent4 = IndexAccent4;
	}


float								GetNLProcInputScaling(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->InputScaling;
	}


float								GetNLProcInputAccent1(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->InputAccent1;
	}


float								GetNLProcInputAccent2(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->InputAccent2;
	}


float								GetNLProcInputAccent3(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->InputAccent3;
	}


float								GetNLProcInputAccent4(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->InputAccent4;
	}


float								GetNLProcOutputScaling(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->OutputScaling;
	}


float								GetNLProcOutputAccent1(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->OutputAccent1;
	}


float								GetNLProcOutputAccent2(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->OutputAccent2;
	}


float								GetNLProcOutputAccent3(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->OutputAccent3;
	}


float								GetNLProcOutputAccent4(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->OutputAccent4;
	}


float								GetNLProcWaveTableIndex(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->WaveTableIndex;
	}


float								GetNLProcIndexAccent1(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->IndexAccent1;
	}


float								GetNLProcIndexAccent2(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->IndexAccent2;
	}


float								GetNLProcIndexAccent3(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->IndexAccent3;
	}


float								GetNLProcIndexAccent4(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->IndexAccent4;
	}


/* get the wave type */
NLProcWaveType			GetNLProcSpecWaveType(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->WaveType;
	}


/* get the algorithmic wave table from the nl proc */
struct AlgoWaveTableObjectRec*	GetNLProcSpecAlgoWaveTable(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		ERROR(eNLAlgoWaveTable != GetNLProcSpecWaveType(NLProc),
			PRERR(ForceAbort,"GetNLProcSpecAlgoWaveTable:  not an algorithmic wave table"));
		return NLProc->u.AlgoWaveTable;
	}


/* get the data wave table from the nl proc */
struct WaveTableObjectRec*	GetNLProcSpecDataWaveTable(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		ERROR(eNLDataWaveTable != GetNLProcSpecWaveType(NLProc),
			PRERR(ForceAbort,"GetNLProcSpecDataWaveTable:  not a data wave table"));
		return NLProc->u.DataWaveTable;
	}


struct EnvelopeRec*	GetNLProcInputEnvelope(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->InputEnvelope;
	}


struct EnvelopeRec*	GetNLProcOutputEnvelope(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->OutputEvelope;
	}


struct EnvelopeRec*	GetNLProcIndexEnvelope(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->IndexEnvelope;
	}


struct LFOListSpecRec*	GetNLProcInputLFO(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->InputLFO;
	}


struct LFOListSpecRec*	GetNLProcOutputLFO(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->OutputLFO;
	}


struct LFOListSpecRec*	GetNLProcIndexLFO(NonlinProcSpecRec* NLProc)
	{
		CheckPtrExistence(NLProc);
		return NLProc->IndexLFO;
	}
