/* WaveIndexUtility.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 "WaveIndexUtility.h"
#include "64BitMath.h"
#include "Memory.h"


/* perform wavetable indirection on an 8 bit wave */
/* returns a value between MAX16BIT and MIN16BIT */
signed long					WaveTable8Bit(float Phase, FastFixedType TableIndex,
											long NumTables, long Frames, signed char** Matrix)
	{
		FastFixedType			Index;
		LongLongRec				FrameIndex;

		Index = (NumTables - 1) * TableIndex;
		if (Index < 0)
			{
				Index = 0;
			}
		else if (Index > Int2FastFixed(NumTables - 1))
			{
				Index = Int2FastFixed(NumTables - 1);
			}
		Double2LongLong(Phase,&FrameIndex);
		if (FastFixed2Int(Index) == NumTables - 1)
			{
				/* this is done in case the wave table index is at the maximum, */
				/* in which case there is no table+1 to interpolate with. */
				signed char*				WaveData;

				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					LeftValue;
				signed long					RightValue;

				PRNGCHK(Matrix,&(Matrix[FastFixed2Int(Index)]),
					sizeof(Matrix[FastFixed2Int(Index)]));
				WaveData = Matrix[FastFixed2Int(Index)];

				LeftWeight = LongLongLowHalf(FrameIndex) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(FrameIndex) & (Frames - 1);
				/* L+F(R-L) */
				LeftValue = ((signed long)WaveData[ArraySubscript]) << 8; /* convert to 16-bit */
				RightValue = ((signed long)WaveData[ArraySubscript + 1]) << 8; /* to 16-bit */
				return LeftValue + ((LeftWeight * (RightValue - LeftValue)) >> 15);
			}
		 else
			{
				signed char*				WaveData0;
				signed char*				WaveData1;
				FastFixedType				Wave0Weight;

				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					Left0Value;
				signed long					Right0Value;
				signed long					Left1Value;
				signed long					Right1Value;
				FastFixedType				Wave0Temp;

				PRNGCHK(Matrix,&(Matrix[FastFixed2Int(Index)]),
					sizeof(Matrix[FastFixed2Int(Index)]));
				WaveData0 = (signed char*)(Matrix[
					FastFixed2Int(Index)]);
				PRNGCHK(Matrix,&(Matrix[FastFixed2Int(Index) + 1]),
					sizeof(Matrix[FastFixed2Int(Index) + 1]));
				WaveData1 = Matrix[FastFixed2Int(Index) + 1];
				Wave0Weight = Index & FASTFIXEDFRACTMASK;

				LeftWeight = LongLongLowHalf(FrameIndex) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(FrameIndex) & (Frames - 1);
				/* L+F(R-L) -- applied twice */
				Left0Value = ((signed long)WaveData0[ArraySubscript]) << 8; /* convert to 16-bit */
				Right0Value = ((signed long)WaveData0[ArraySubscript + 1]) << 8; /* to 16-bit */
				Left1Value = ((signed long)WaveData1[ArraySubscript]) << 8; /* convert to 16-bit */
				Right1Value = ((signed long)WaveData1[ArraySubscript + 1]) << 8; /* to 16-bit */
				Wave0Temp = Left0Value + ((LeftWeight * (Right0Value - Left0Value)) >> 15);
				return Wave0Temp + ((Wave0Weight * (Left1Value + ((LeftWeight
					* (Right1Value - Left1Value)) >> 15) - Wave0Temp)) >> 15);
			}
	}


/* perform wavetable indirection on a 16 bit wave */
/* returns a value between MAX16BIT and MIN16BIT */
signed long					WaveTable16Bit(float Phase, FastFixedType TableIndex,
											long NumTables, long Frames, signed short** Matrix)
	{
		FastFixedType			Index;
		LongLongRec				FrameIndex;

		Index = (NumTables - 1) * TableIndex;
		if (Index < 0)
			{
				Index = 0;
			}
		else if (Index > Int2FastFixed(NumTables - 1))
			{
				Index = Int2FastFixed(NumTables - 1);
			}
		Double2LongLong(Phase,&FrameIndex);
		if (FastFixed2Int(Index) == NumTables - 1)
			{
				/* this is done in case the wave table index is at the maximum, */
				/* in which case there is no table+1 to interpolate with. */
				signed short*				WaveData;

				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					LeftValue;
				signed long					RightValue;

				PRNGCHK(Matrix,&(Matrix[FastFixed2Int(Index)]),
					sizeof(Matrix[FastFixed2Int(Index)]));
				WaveData = Matrix[FastFixed2Int(Index)];

				LeftWeight = LongLongLowHalf(FrameIndex) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(FrameIndex) & (Frames - 1);
				/* L+F(R-L) */
				LeftValue = WaveData[ArraySubscript];
				RightValue = WaveData[ArraySubscript + 1];
				return LeftValue + ((LeftWeight * (RightValue - LeftValue)) >> 15);
			}
		 else
			{
				signed short*				WaveData0;
				signed short*				WaveData1;
				FastFixedType				Wave0Weight;

				FastFixedType				LeftWeight;
				long								ArraySubscript;
				signed long					Left0Value;
				signed long					Right0Value;
				signed long					Left1Value;
				signed long					Right1Value;
				FastFixedType				Wave0Temp;

				PRNGCHK(Matrix,&(Matrix[FastFixed2Int(Index)]),
					sizeof(Matrix[FastFixed2Int(Index)]));
				WaveData0 = Matrix[FastFixed2Int(Index)];
				PRNGCHK(Matrix,&(Matrix[FastFixed2Int(Index) + 1]),
					sizeof(Matrix[FastFixed2Int(Index) + 1]));
				WaveData1 = Matrix[FastFixed2Int(Index) + 1];
				Wave0Weight = Index & FASTFIXEDFRACTMASK;

				LeftWeight = LongLongLowHalf(FrameIndex) >> (32 - FASTFIXEDPRECISION);
				ArraySubscript = LongLongHighHalf(FrameIndex) & (Frames - 1);
				/* L+F(R-L) -- applied twice */
				Left0Value = WaveData0[ArraySubscript];
				Right0Value = WaveData0[ArraySubscript + 1];
				Left1Value = WaveData1[ArraySubscript];
				Right1Value = WaveData1[ArraySubscript + 1];
				Wave0Temp = Left0Value + ((LeftWeight * (Right0Value - Left0Value)) >> 15);
				return Wave0Temp + ((Wave0Weight * (Left1Value + ((LeftWeight
					* (Right1Value - Left1Value)) >> 15) - Wave0Temp)) >> 15);
			}
	}
