/* WaveTableStorageDisplay.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 "WaveTableStorageDisplay.h"
#include "Array.h"
#include "Memory.h"
#include "DataMunging.h"


struct WaveTableStorDispRec
	{
		NumBitsType			NumBits;
		long						FramesPerTable;
		ArrayRec*				TableArray; /* of largefixedsigned[]'s */
	};


/* create a new, empty wave table storage display object */
WaveTableStorDispRec*		NewWaveTableStorDisp(NumBitsType NumBits, long NumFrames)
	{
		WaveTableStorDispRec*	StorDisp;

		ERROR((NumBits != eSample8bit) && (NumBits != eSample16bit),PRERR(ForceAbort,
			"NewWaveTableStorDisp:  bad number of bits"));
		ERROR((NumFrames != 2) && (NumFrames != 4) && (NumFrames != 8) && (NumFrames != 16)
			&& (NumFrames != 32) && (NumFrames != 64) && (NumFrames != 128)
			&& (NumFrames != 256) && (NumFrames != 512) && (NumFrames != 1024)
			&& (NumFrames != 2048) && (NumFrames != 4096) && (NumFrames != 8192)
			&& (NumFrames != 16384) && (NumFrames != 32768) && (NumFrames != 65536),
			PRERR(ForceAbort,"NewWaveTableStorDisp:  bad number of frames"));
		StorDisp = (WaveTableStorDispRec*)AllocPtrCanFail(sizeof(WaveTableStorDispRec),
			"WaveTableStorDispRec");
		if (StorDisp == NIL)
			{
			 FailurePoint1:
				return NIL;
			}
		StorDisp->NumBits = NumBits;
		StorDisp->FramesPerTable = NumFrames;
		StorDisp->TableArray = NewArray();
		if (StorDisp->TableArray == NIL)
			{
			 FailurePoint2:
				ReleasePtr((char*)StorDisp);
				goto FailurePoint1;
			}
		return StorDisp;
	}


/* dispose of the wave table storage object */
void										DisposeWaveTableStorDisp(WaveTableStorDispRec* StorDisp)
	{
		long									Limit;
		long									Scan;

		CheckPtrExistence(StorDisp);
		Limit = ArrayGetLength(StorDisp->TableArray);
		for (Scan = 0; Scan < Limit; Scan += 1)
			{
				ReleasePtr((char*)ArrayGetElement(StorDisp->TableArray,Scan));
			}
		DisposeArray(StorDisp->TableArray);
		ReleasePtr((char*)StorDisp);
	}


/* get the number of frames per table */
long										WaveTableStorDispNumFramesPerTable(WaveTableStorDispRec* StorDisp)
	{
		CheckPtrExistence(StorDisp);
		return StorDisp->FramesPerTable;
	}


/* get the number of tables */
long										WaveTableStorDispNumTables(WaveTableStorDispRec* StorDisp)
	{
		CheckPtrExistence(StorDisp);
		return ArrayGetLength(StorDisp->TableArray);
	}


/* get the number of bits for the wave table */
NumBitsType							WaveTableStorDispNumBits(WaveTableStorDispRec* StorDisp)
	{
		CheckPtrExistence(StorDisp);
		return StorDisp->NumBits;
	}


/* change the number of bits for the wave table */
void										SetWaveTableStorDispNumBits(WaveTableStorDispRec* StorDisp,
													NumBitsType NewNumBits)
	{
		CheckPtrExistence(StorDisp);
		ERROR((NewNumBits != eSample8bit) && (NewNumBits != eSample16bit),PRERR(ForceAbort,
			"SetWaveTableStorDispNumBits:  bad number of bits"));
		StorDisp->NumBits = NewNumBits;
	}


/* get a reference to a table.  this is NOT copied, and there is no type information. */
/* The last element is a repeat of the first, and is provided for making anti-aliasing */
/* more efficient. */
largefixedsigned*				WaveTableStorDispGetTable(WaveTableStorDispRec* StorDisp,
													long Index)
	{
		CheckPtrExistence(StorDisp);
		ERROR((Index < 0) || (Index >= WaveTableStorDispNumTables(StorDisp)),
			PRERR(ForceAbort,"WaveTableStorDispGetTable:  index out of range"));
		return (largefixedsigned*)ArrayGetElement(StorDisp->TableArray,Index);
	}


/* append a new (zeroed out) table to the end of the array */
MyBoolean								WaveTableStorDispAppendEntry(WaveTableStorDispRec* StorDisp)
	{
		largefixedsigned*			NewSlice;
		long									Scan;

		CheckPtrExistence(StorDisp);
		NewSlice = (largefixedsigned*)AllocPtrCanFail(sizeof(largefixedsigned)
			* (StorDisp->FramesPerTable + 1),"WaveTableStorDispRec slice");
		/* + 1 used for the antialiasing slot */
		if (NewSlice == NIL)
			{
			 FailurePoint1:
				return False;
			}
		if (!ArrayAppendElement(StorDisp->TableArray,NewSlice))
			{
			 FailurePoint2:
				ReleasePtr((char*)NewSlice);
				goto FailurePoint1;
			}
		for (Scan = 0; Scan < StorDisp->FramesPerTable + 1; Scan += 1)
			{
				PRNGCHK(NewSlice,&(NewSlice[Scan]),sizeof(NewSlice[Scan]));
				NewSlice[Scan] = 0;
			}
		return True;
	}


/* put a value into a frame in a table */
void										WaveTableStorDispSetFrame(WaveTableStorDispRec* StorDisp,
													long TableIndex, long FrameIndex, largefixedsigned Value)
	{
		largefixedsigned*			TheSlice;

		CheckPtrExistence(StorDisp);
		ERROR((TableIndex < 0) || (TableIndex >= WaveTableStorDispNumTables(StorDisp)),
			PRERR(ForceAbort,"WaveTableStorDispSetFrame:  table index out of range"));
		ERROR((FrameIndex < 0) || (FrameIndex >= StorDisp->FramesPerTable),
			PRERR(ForceAbort,"WaveTableStorDispSetFrame:  frame in table index out of range"));
		TheSlice = WaveTableStorDispGetTable(StorDisp,TableIndex);
		PRNGCHK(TheSlice,&(TheSlice[FrameIndex]),sizeof(TheSlice[FrameIndex]));
		TheSlice[FrameIndex] = Value;
		if (FrameIndex == 0)
			{
				PRNGCHK(TheSlice,&(TheSlice[StorDisp->FramesPerTable]),
					sizeof(TheSlice[StorDisp->FramesPerTable]));
				TheSlice[StorDisp->FramesPerTable] = Value; /* anti-aliasing loopback value */
			}
	}


/* get a value from a frame in a table */
largefixedsigned				WaveTableStorDispGetFrame(WaveTableStorDispRec* StorDisp,
													long TableIndex, long FrameIndex)
	{
		largefixedsigned*			TheSlice;

		CheckPtrExistence(StorDisp);
		ERROR((TableIndex < 0) || (TableIndex >= WaveTableStorDispNumTables(StorDisp)),
			PRERR(ForceAbort,"WaveTableStorDispGetFrame:  table index out of range"));
		ERROR((FrameIndex < 0) || (FrameIndex >= StorDisp->FramesPerTable),
			PRERR(ForceAbort,"WaveTableStorDispGetFrame:  frame in table index out of range"));
		TheSlice = WaveTableStorDispGetTable(StorDisp,TableIndex);
		PRNGCHK(TheSlice,&(TheSlice[FrameIndex]),sizeof(TheSlice[FrameIndex]));
		return TheSlice[FrameIndex];
	}


/* make a duplicate of the wave table */
WaveTableStorDispRec*		WaveTableStorDispDuplicate(WaveTableStorDispRec* Original)
	{
		WaveTableStorDispRec*	Copy;
		long									Limit;
		long									Scan;

		CheckPtrExistence(Original);
		Copy = (WaveTableStorDispRec*)AllocPtrCanFail(sizeof(WaveTableStorDispRec),
			"WaveTableStorDispRec");
		if (Copy == NIL)
			{
			 FailurePoint1:
				return NIL;
			}
		Copy->NumBits = Original->NumBits;
		Copy->FramesPerTable = Original->FramesPerTable;
		Copy->TableArray = NewArray();
		if (Copy->TableArray == NIL)
			{
			 FailurePoint2:
				ReleasePtr((char*)Copy);
				goto FailurePoint1;
			}
		Limit = ArrayGetLength(Original->TableArray);
		for (Scan = 0; Scan < Limit; Scan += 1)
			{
				char*									Temp;

				Temp = CopyPtr((char*)ArrayGetElement(Original->TableArray,Scan));
				if (Temp == NIL)
					{
					 FailurePoint3:
						Limit = ArrayGetLength(Copy->TableArray);
						for (Scan = 0; Scan < Limit; Scan += 1)
							{
								ReleasePtr((char*)ArrayGetElement(Copy->TableArray,Scan));
							}
						DisposeArray(Copy->TableArray);
						goto FailurePoint2;
					}
				SetTag(Temp,"WaveTableStorDispRec:  slice");
				if (!ArrayAppendElement(Copy->TableArray,Temp))
					{
					 FailurePoint3a:
						ReleasePtr((char*)Temp);
						goto FailurePoint3;
					}
			}
		return Copy;
	}
