//	Sample Creation routines (encode and filter) for ARDOP Modem

#include "ARDOPC.h"
#include <math.h>

#define ARDOPBufferSize 12000 * 100

extern char CWIDMark[32];

extern short ARDOPTXBuffer[4][ARDOPBufferSize];	// Enough to hold whole frame of samples

extern int ARDOPTXLen[4];				// Length of frame
extern int ARDOPTXPtr[4];				// Tx Pointer

extern int intSessionBW;	// Negotiated speed

#pragma warning(disable : 4244)		// Code does lots of  float to int

FILE * fp1;

float dblQAMCarRatio = 1.0f / 1.765f;   //Optimum for 8,8 circular constellation with no phase offset: (Dmin inner to inner = Dmin inner to outer) 

#define MAX(x, y) ((x) > (y) ? (x) : (y))

// Function to generate the Two-tone leader and Frame Sync (used in all frame types) 

extern short Dummy;

int intSoftClipCnt = 0;
BOOL SendingHeader200 = 0;		// Set when sending header in 200 Hz Modes

void ARDOPFlush();

int intBW;			// Requested connect speed
int intSessionBW;	// Negotiated speed
UCHAR bytLastReceivedDataFrameType;
UCHAR bytLastARQSessionID;
int blnPending = 0;
int intSessionBW = 500;

void ARDOPSampleSink(short Sample);
extern CONST short int50BaudTwoToneLeaderTemplate[240];  // holds just 1 symbol (20 ms) of the leader


extern int TrailerLength;

void AddTrailer(int Chan)
{
	int intAddedSymbols = 1 + TrailerLength / 10; // add 1 symbol + 1 per each 10 ms of MCB.Trailer
	int i, k;

	for (i = 1; i <= intAddedSymbols; i++)
	{
		for (k = 0; k < 120; k++)
		{
			ARDOPSampleSink(intQAM50bdCarTemplate[5][0][k % 60]);
		}
	}
}

extern int Number;

void ARDOPFlush(int Chan)
{
	AddTrailer(Chan);			// add the trailer.
	ARDOPTXPtr[Chan] = 0;
	ARDOPTXLen[Chan] = Number;
}

// Function to soft clip combined waveforms. 
int SoftClip(int intInput)
{
	if (intInput > 30000) // soft clip above/below 30000
	{
		intInput = 30000; //min(32700, 30000 + 20 * sqrt(intInput - 30000));
		intSoftClipCnt += 1;
	}
	else if(intInput < -30000)
	{
		intInput = -30000; //max(-32700, -30000 - 20 * sqrt(-(intInput + 30000)));
		intSoftClipCnt += 1;
	}

	if (intInput == 0)
		intInput = 0;


	return intInput;
}


void GetTwoToneLeaderWithSync(int intSymLen)
{
	// Generate a 50 baud (20 ms symbol time) 2 tone leader 
    // leader tones used are 1475 and 1525 Hz.  
  
	int intSign = 1;
	int i, j;
	short intSample;

    if ((intSymLen & 1) == 1) 
		intSign = -1;

	for (i = 0; i < intSymLen; i++)   //for the number of symbols needed (two symbols less than total leader length) 
	{
		for (j = 0; j < 240; j++)	// for 240 samples per symbol (50 baud) 
		{
           if (i != (intSymLen - 1)) 
			   intSample = intSign * int50BaudTwoToneLeaderTemplate[j];
		   else
			   intSample = -intSign * int50BaudTwoToneLeaderTemplate[j];
   
		   ARDOPSampleSink(intSample);
		}
		intSign = -intSign;
	}
}

void SendLeaderAndSYNC(UCHAR * bytEncodedBytes, int intLeaderLen)
{
	int intLeaderLenMS;
	int j, k, n;
	UCHAR bytMask;
	UCHAR bytSymToSend;
	short intSample;
	if (intLeaderLen == 0)
		intLeaderLenMS = LeaderLength;
	else
		intLeaderLenMS = intLeaderLen;

 	// Create the leader

	GetTwoToneLeaderWithSync(intLeaderLenMS / 20);
		       
	//Create the 8 symbols (16 bit) 50 baud 4FSK frame type with Implied SessionID

	for(j = 0; j < 2; j++)		 // for the 2 bytes of the frame type
	{              
		bytMask = 0x30;
		
		for(k = 0; k < 4; k++)	 // for 4 symbols per byte (3 data + 1 parity)
		{
			if (k < 3)
				bytSymToSend = (bytMask & bytEncodedBytes[j]) >> (2 * (2 - k));
			else
				bytSymToSend = ComputeTypeParity(bytEncodedBytes[j]);

			for(n = 0; n < 240; n++)
			{
//				if ( ARQBandwidth == XB2500)		// 2500 Hz
//				{
//					if (bytSymToSend < 2)
//						intSample = (0.62 * intFSK50bdCarTemplate[4 + bytSymToSend][n]) + (0.62 * intFSK50bdCarTemplate[bytSymToSend][n]); // 4 is offset to center tones 1350, 1450, 1550, 1650Hz
//					else
//						intSample = (0.62 * intFSK50bdCarTemplate[4 + bytSymToSend][n]) + (0.62 * intFSK50bdCarTemplate[8 + bytSymToSend][n]); // 4 is offset to center tones 1350, 1450, 1550, 1650Hz, 8 is offset to tones 1800 and 1900
//				}
//				else
					intSample = intFSK50bdCarTemplate[bytSymToSend + 4][n];
				
				ARDOPSampleSink(intSample);	
			}
			bytMask = bytMask >> 2;
		}
	}
}

void Mod4FSKDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan)
{
	// Function to Modulate data encoded for 4FSK, create
	// the 16 bit samples and send to sound interface

	// Function works for 1, 2 or 4 simultaneous carriers 

	int intNumCar, intBaud, intDataLen, intRSLen, intDataPtr, intSampPerSym, intDataBytesPerCar;
	BOOL blnOdd;

	int intSample;

	char strType[18] = "";
	char strMod[16] = "";

	UCHAR bytSymToSend, bytMask, bytMinQualThresh;

	float dblCarScalingFactor;
	int intLeaderLenMS;
	int k, m, n;
	UCHAR Type = bytEncodedBytes[0];

	if (!FrameInfo(Type, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType))
		return;

	if (strcmp(strMod, "4FSK") != 0)
		return;

	Debugprintf("Sending Frame Type %s", strType);
	DrawTXFrame(strType);

	if (bytEncodedBytes[0] == PktFrameHeader)
	{
		// Leader is 4FSK which needs 500 filter

		if (pktBW[pktMode] < 1000)
			initFilter(500, 1500, Chan);
		else
			initFilter(2500, 1500, Chan);
	}
	else
	{
		if (ARQBandwidth == XB200)
			initFilter(200, 1500, Chan);
		else if (intNumCar == 1)
			initFilter(500, 1500, Chan);
		else
			initFilter(2500, 1500, Chan);
	}

	if (intLeaderLen == 0)
		intLeaderLenMS = LeaderLength;
	else
		intLeaderLenMS = intLeaderLen;

	switch (intBaud)
	{
	case 50:

		intSampPerSym = 240;
		break;

	case 100:

		intSampPerSym = 120;
	}

	intDataBytesPerCar = (Len - 2) / intNumCar;		// We queue the samples here, so dont copy below

	SendLeaderAndSYNC(bytEncodedBytes, intLeaderLen);

	intDataPtr = 2;

Reenter:

	switch (intNumCar)
	{
	case 1:			 // use carriers 0-3

		dblCarScalingFactor = 1.0; //  (scaling factors determined emperically to minimize crest factor) 

		for (m = 0; m < intDataBytesPerCar; m++)  // For each byte of input data
		{
			bytMask = 0xC0;		 // Initialize mask each new data byte

			for (k = 0; k < 4; k++)		// for 4 symbol values per byte of data
			{
				bytSymToSend = (bytMask & bytEncodedBytes[intDataPtr]) >> (2 * (3 - k)); // Values 0-3

				for (n = 0; n < intSampPerSym; n++)	 // Sum for all the samples of a symbols 
				{
					if (intBaud == 50)
					{
						if (intSessionBW == 200 && (bytSymToSend == 0 || bytSymToSend == 3))
							// This scales down the two outer tones in 200 Hz mode to restrict bandwidth slightly
							intSample = 0.7f * intFSK50bdCarTemplate[4 + bytSymToSend][n]; //4 is offset to center tones 1350, 1450, 1550, 1650Hz
						else
							intSample = intFSK50bdCarTemplate[4 + bytSymToSend][n]; //4 is offset to center tones 1350, 1450, 1550, 1650Hz
					}
					else if (intBaud == 100)		// Used for OFDMACK
					{
						intSample = intFSK100bdCarTemplate[bytSymToSend][n];
					}
					ARDOPSampleSink(intSample);
				}

				bytMask = bytMask >> 2;
			}
			intDataPtr += 1;
		}

		if (Type == PktFrameHeader)
		{

			// just sent packet header. Send rest in current mode
			// Assumes we are using 4FSK for Packet Header

			bytEncodedBytes[0] = Type = PktFrameData;	// Prevent reentry

			strcpy(strMod, &pktMod[pktMode][0]);
			intDataBytesPerCar = pktDataLen + pktRSLen + 3;
			intDataPtr = 11;		// Over Header
			intNumCar = pktCarriers[pktMode];

			// This assumes Packet Data is sent as PSK/QAM

			switch (intNumCar)
			{
			case 1:
				//		intCarStartIndex = 4;
				dblCarScalingFactor = 1.0f; // Starting at 1500 Hz  (scaling factors determined emperically to minimize crest factor)  TODO:  needs verification
				break;
			case 2:
				//		intCarStartIndex = 3;
				dblCarScalingFactor = 0.53f; // Starting at 1400 Hz
				break;
			case 4:
				//		intCarStartIndex = 2;
				dblCarScalingFactor = 0.29f; // Starting at 1200 Hz
				break;
			case 8:
				//		intCarStartIndex = 0;
				dblCarScalingFactor = 0.17f; // Starting at 800 Hz
			}

			// Reenter to send rest of variable length packet frame

			if (pktFSK[pktMode])
				goto Reenter;
			else
				ModPSKDataAndPlay(bytEncodedBytes, 0, 0, Chan);
			return;
		}

		ARDOPFlush(Chan);

		break;

	case 2:			// use carriers 0-3 and 8-11 (50 baud only)

		dblCarScalingFactor = 0.6f; //  (scaling factors determined emperically to minimize crest factor)

		for (m = 0; m < intDataBytesPerCar; m++)	  // For each byte of input data 
		{
			bytMask = 0xC0;	// Initialize mask each new data byte

			for (k = 0; k < 4; k++)		// for 4 symbol values per byte of data
			{
				for (n = 0; n < intSampPerSym; n++)	 // for all the samples of a symbol for 2 carriers
				{
					//' First carrier

					bytSymToSend = (bytMask & bytEncodedBytes[intDataPtr]) >> (2 * (3 - k)); // Values 0-3
					intSample = intFSK50bdCarTemplate[bytSymToSend][n];
					// Second carrier

					bytSymToSend = (bytMask & bytEncodedBytes[intDataPtr + intDataBytesPerCar]) >> (2 * (3 - k));	// Values 0-3
					intSample = SoftClip(dblCarScalingFactor * (intSample + intFSK50bdCarTemplate[8 + bytSymToSend][n]));

					ARDOPSampleSink(intSample);
				}
				bytMask = bytMask >> 2;
			}
			intDataPtr += 1;
		}

		ARDOPFlush(Chan);

		break;
	}
}

// Function to extract an 8PSK symbol from an encoded data array


UCHAR GetSym8PSK(int intDataPtr, int k, int intCar, UCHAR * bytEncodedBytes, int intDataBytesPerCar)
{
	int int3Bytes = bytEncodedBytes[intDataPtr + intCar * intDataBytesPerCar];
//	int intMask  = 7;
	int intSym;
	UCHAR bytSym;

	int3Bytes = int3Bytes << 8;
	int3Bytes += bytEncodedBytes[intDataPtr + intCar * intDataBytesPerCar + 1];
	int3Bytes = int3Bytes << 8;
	int3Bytes += bytEncodedBytes[intDataPtr + intCar * intDataBytesPerCar + 2];  // now have 3 bytes, 24 bits or 8 8PSK symbols 
//	intMask = intMask << (3 * (7 - k));
	intSym = int3Bytes >> (3 * (7 - k));
	bytSym = intSym & 7;	//(intMask && int3Bytes) >> (3 * (7 - k));

	return bytSym;
}



// Function to Modulate data encoded for PSK and 16QAM, create
// the 16 bit samples and send to sound interface
   

void ModPSKDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan)
{
	int intNumCar, intBaud, intDataLen, intRSLen, intDataPtr, intSampPerSym, intDataBytesPerCar;
	BOOL blnOdd;
	int Type = bytEncodedBytes[0];

	int intSample;
	char strType[18] = "";
	char strMod[16] = "";
	UCHAR bytSym, bytSymToSend, bytMinQualThresh;
	float dblCarScalingFactor;
	int intLeaderLenMS;
	int i, j, k, l = 4, n;
	int intCarStartIndex;
	int intPeakAmp;
	int intCarIndex;
	BOOL QAM = 0;

	UCHAR bytLastSym[43]; // = {0}; // Holds the last symbol sent (per carrier). bytLastSym(4) is 1500 Hz carrier (only used on 1 carrier modes) 

	if (!FrameInfo(Type, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType))
		return;

	intDataBytesPerCar = (Len - 2) / intNumCar;		// We queue the samples here, so dont copy below

	// These new scaling factor combined with soft clipping to provide near optimum scaling Jan 6, 2018 
	// The Test form was changed to calculate the Peak power to RMS power (PAPR) of the test waveform and count the number of "soft clips" out of ~ 50,000 samples. 
	// These values arrived at emperically using the Test form (Quick brown fox message) to minimize PAPR at a minor decrease in maximum constellation quality

	if (strstr(strMod, "16QAM"))
	{
		// QAM Modes

		QAM = 1;
		l = 2;				// 2 symbols per byte

		switch (intNumCar)
		{
		case 1:
			intCarStartIndex = 5;
			dblCarScalingFactor = 2.0f; // Starting at 1500 Hz  Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98
			break;
		case 2:
			intCarStartIndex = 4;
			dblCarScalingFactor = 1.0f;
			break;
		case 10:
			intCarStartIndex = 0;
			dblCarScalingFactor = 0.4f;
		}
	}
	else  // 4PSK
	{
		switch (intNumCar)
		{
		case 1:
			intCarStartIndex = 5;
			dblCarScalingFactor = 2.0f; // Starting at 1500 Hz  Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98
			break;
		case 2:
			intCarStartIndex = 4;
			dblCarScalingFactor = 1.2f;
			break;
		case 10:
			intCarStartIndex = 0;
			dblCarScalingFactor = 0.35f;
		}
	}

	if (intBaud == 50)
		intSampPerSym = 240;
	else
		intSampPerSym = 120;

	if (Type == PktFrameData)
	{
		intDataBytesPerCar = pktDataLen + pktRSLen + 3;
		intDataPtr = 11;		// Over Header
		goto PktLoopBack;
	}

	Debugprintf("Sending Frame Type %s", strType);
	DrawTXFrame(strType);

	if (intNumCar == 1)
		initFilter(200, 1500, Chan);
	else if (intNumCar == 2 || intNumCar == 9)
		initFilter(500, 1500, Chan);
	else
		initFilter(2500, 1500, Chan);

	if (intLeaderLen == 0)
		intLeaderLenMS = LeaderLength;
	else
		intLeaderLenMS = intLeaderLen;

	intSoftClipCnt = 0;

	// Create the leader

	SendLeaderAndSYNC(bytEncodedBytes, intLeaderLen);
	SendingHeader200 = FALSE;

	intPeakAmp = 0;

	intDataPtr = 2;  // initialize pointer to start of data.

PktLoopBack:		// Reenter here to send rest of variable length packet frame


	// Now create a reference symbol for each carrier

	//	We have to do each carrier for each sample, as we write
	//	the sample immediately 

	for (n = 0; n < intSampPerSym; n++)  // Sum for all the samples of a symbols 
	{
		intSample = 0;
		intCarIndex = intCarStartIndex;  // initialize to correct starting carrier

		for (i = 0; i < intNumCar; i++)	// across all carriers
		{
			bytSymToSend = 0;  //  using non 0 causes error on first data byte 12/8/2014   ...Values 0-3  not important (carries no data).   (Possible chance for Crest Factor reduction?)       
			bytLastSym[intCarIndex] = 0;


			intSample += intQAM50bdCarTemplate[intCarIndex][0][n % 120];

			intCarIndex++;
			if (intCarIndex == 5)
				intCarIndex = 6;	// skip over 1500 Hz for multi carrier modes (multi carrier modes all use even hundred Hz tones)
		}
		intSample = SoftClip(intSample * 0.5 * dblCarScalingFactor);
		ARDOPSampleSink(intSample);
	}

	// End of reference phase generation 

	// Unlike ARDOP_WIN we send samples as they are created,
	// so we loop through carriers, then data bytes

	for (j = 0; j < intDataBytesPerCar; j++)	//  for each referance and data symbol 
	{
		// Loop through each symbol of byte (4 for PSK 2 for QAM

		for (k = 0; k < l; k++)
		{
			for (n = 0; n < intSampPerSym; n++)
			{
				intSample = 0;
				intCarIndex = intCarStartIndex; // initialize the carrrier index

				for (i = 0; i < intNumCar; i++) // across all active carriers
				{
					if (QAM == 0)
					{
						bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> (2 * (3 - k))) & 3;
						bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 3);  // Values 0-3

						if (bytSymToSend < 2) // This uses the symmetry of the symbols to reduce the table size by a factor of 2
							intSample += intQAM50bdCarTemplate[intCarIndex][2 * bytSymToSend][n % 120]; //  double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols)
						else if (bytSymToSend < 4)
							intSample -= intQAM50bdCarTemplate[intCarIndex][2 * (bytSymToSend - 2)][n % 120]; // subtract 2 from the symbol value before doubling and subtract value of table 

					}
					else
					{
						// For 16QAM the angle is sent differential but the amplitude is sent as is for the symbol...verified 4/20 2018

						bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> (4 * (1 - k))) & 15;
						bytSymToSend = ((bytLastSym[intCarIndex] & 7) + (bytSym & 7) & 7); // Compute the differential phase to send
						bytSymToSend = bytSymToSend | (bytSym & 8); // add in the amplitude bit directly from symbol 

						// 4bits/symbol (use table symbol values 0, 1, 2, 3, -0, -1, -2, -3) and modulate amplitude with MSB

						if (bytSymToSend < 4)// This uses the symmetry of the symbols to reduce the table size by a factor of 2
							intSample += intQAM50bdCarTemplate[intCarIndex][bytSymToSend][n % 120]; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols)
						else if (bytSymToSend < 8)
							intSample -= intQAM50bdCarTemplate[intCarIndex][(bytSymToSend - 4)][n % 120]; // subtract 4 from the symbol value before doubling and subtract value of table 
						else if (bytSymToSend < 12)
							intSample += dblQAMCarRatio * intQAM50bdCarTemplate[intCarIndex][bytSymToSend - 8][n % 120]; // subtract 4 from the symbol value before doubling and subtract value of table         
						else
							intSample -= dblQAMCarRatio * intQAM50bdCarTemplate[intCarIndex][bytSymToSend - 12][n % 120]; //  subtract 4 from the symbol value before doubling and subtract value of table 
					}

					if (n == intSampPerSym - 1)		// Last sample?
						bytLastSym[intCarIndex] = bytSymToSend;

					intCarIndex += 1;
					if (intCarIndex == 5)
						intCarIndex = 6;  // skip over 1500 Hz carrier for multicarrier modes
				}

				// Done all carriers - send sample

				intSample = SoftClip(intSample * 0.5 * dblCarScalingFactor);
				ARDOPSampleSink(intSample);
			}

			// Done all samples for this symbol
			// now next symbol of byte

		}
		intDataPtr++;
	}

	if (Type == PktFrameHeader)
	{
		// just sent packet header. Send rest in current mode

		Type = 0;			// Prevent reentry

		strcpy(strMod, &pktMod[pktMode][0]);
		intDataBytesPerCar = pktDataLen + pktRSLen + 3;
		intDataPtr = 11;		// Over Header
		intNumCar = pktCarriers[pktMode];

		switch (intNumCar)
		{
		case 1:
			intCarStartIndex = 4;
			//			dblCarScalingFactor = 1.0f; // Starting at 1500 Hz  (scaling factors determined emperically to minimize crest factor)  TODO:  needs verification
			dblCarScalingFactor = 1.2f; // Starting at 1500 Hz  Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98
		case 2:
			intCarStartIndex = 3;
			//			dblCarScalingFactor = 0.53f;
			if (strcmp(strMod, "16QAM") == 0)
				dblCarScalingFactor = 0.67f; // Carriers at 1400 and 1600 Selected to give < 2.5% clipped values yielding a PAPR = 2.17, Constellation Quality >92
			else
				dblCarScalingFactor = 0.65f; // Carriers at 1400 and 1600 Selected to give < 4% clipped values yielding a PAPR = 2.0, Constellation Quality >95
			break;
		case 4:
			intCarStartIndex = 2;
			//			dblCarScalingFactor = 0.29f; // Starting at 1200 Hz
			dblCarScalingFactor = 0.4f;  // Starting at 1200 Hz  Selected to give < 3% clipped values yielding a PAPR = 2.26, Constellation Quality >95
			break;
		case 8:
			intCarStartIndex = 0;
			//			dblCarScalingFactor = 0.17f; // Starting at 800 Hz
			if (strcmp(strMod, "16QAM") == 0)
				dblCarScalingFactor = 0.27f; // Starting at 800 Hz  Selected to give < 1% clipped values yielding a PAPR = 2.64, Constellation Quality >94
			else
				dblCarScalingFactor = 0.25f; // Starting at 800 Hz  Selected to give < 2% clipped values yielding a PAPR = 2.5, Constellation Quality >95
		}
		goto PktLoopBack;		// Reenter to send rest of variable length packet frame
	}

	ARDOPFlush(Chan);

	if (intSoftClipCnt > 0)
		Debugprintf("Soft Clips %d ", intSoftClipCnt);

}



//	Resends the last frame

void RemodulateLastFrame(int Chan)
{	
	int intNumCar, intBaud, intDataLen, intRSLen;
	UCHAR bytMinQualThresh;
	BOOL blnOdd;

	char strType[18] = "";
    char strMod[16] = "";

	if (!FrameInfo(bytEncodedBytes[0], &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType))
		return;

	if (strcmp(strMod, "4FSK") == 0)
	{
		Mod4FSKDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader, Chan);  // Modulate Data frame 
		return;
	}

	if (strcmp(strMod, "OFDM") == 0)
	{
		int save = OFDMMode;
		OFDMMode = LastSentOFDMMode;

		ModOFDMDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader, Chan);  // Modulate Data frame 

		OFDMMode = save;

		return;
	}

	ModPSKDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader, Chan);  // Modulate Data frame 
}

// Filter State Variables

static float dblR = (float)0.9995f;	// insures stability (must be < 1.0) (Value .9995 7/8/2013 gives good results)
static int intN = 120;				//Length of filter 12000/100
static float dblRn;

static float dblR2;
static float dblCoef[34] = {0.0f};			// the coefficients
float dblZin = 0, dblZin_1 = 0, dblZin_2 = 0, dblZComb= 0;  // Used in the comb generator

// The resonators 
      
float dblZout_0[34] = {0.0f};	// resonator outputs
float dblZout_1[34] = {0.0f};	// resonator outputs delayed one sample
float dblZout_2[34] = {0.0f};	// resonator outputs delayed two samples

int fWidth;				// Filter BandWidth
int SampleNo;
int outCount = 0;
int first, last;		// Filter slots
int centreSlot;

float largest = 0;
float smallest = 0;

short Last120[256];		// Now need 240 for 200 Hz filter

int Last120Get = 0;
int Last120Put = 120;

extern int Number;				// Number waiting to be sent

UCHAR bytPendingSessionID;
UCHAR bytSessionID = 0x3f;
BOOL blnARQConnected;

extern unsigned short buffer[2][1200];

unsigned short * DMABuffer;

unsigned short * SendtoCard(unsigned short * buf, int n);
unsigned short * SoundInit();

// initFilter is called to set up each packet. It selects filter width

void initFilter(int Width, int Centre, int Chan)
{
	int i, j;
	fWidth = Width;
	centreSlot = Centre / 100;
	largest = smallest = 0;
	SampleNo = 0;
	Number = 0;
	outCount = 0;
	memset(Last120, 0, 256);

	DMABuffer = &ARDOPTXBuffer[Chan][0];

//	KeyPTT(TRUE);
	SoundIsPlaying = TRUE;
//	StopCapture();

	Last120Get = 0;
	Last120Put = 120;

	dblRn = powf(dblR, intN);
	dblR2 = powf(dblR, 2);

	dblZin_2 = dblZin_1 = 0;

	switch (fWidth)
	{
	case 200:

		// Used for PSK 200 Hz modulation XMIT filter  
		// implements 5 50 Hz wide sections centered on 1500 Hz  (~200 Hz wide @ - 30dB centered on 1500 Hz)
 
		SendingHeader200 = TRUE;
		intN = 240;
		Last120Put = 240;
		centreSlot = Centre / 50;
		first = centreSlot - 3;
		last = centreSlot + 3;		// 7 filter sections
		break;

	case 500:

		// implements 7 100 Hz wide sections centered on 1500 Hz  (~500 Hz wide @ - 30dB centered on 1500 Hz)

		intN = 120;
		first = centreSlot - 3;
		last = centreSlot + 3;		// 7 filter sections
		break;

	case 2500:
		
		// implements 26 100 Hz wide sections centered on 1500 Hz  (~2000 Hz wide @ - 30dB centered on 1500 Hz)

		intN = 120;
		first = centreSlot - 13;
		last = centreSlot + 13;		// 27 filter sections
		break;
	
	default:

		Debugprintf("Invalid Filter Width %d", fWidth);
	}


	for (j = first; j <= last; j++)
	{
		dblZout_0[j] = 0;
		dblZout_1[j] = 0;
		dblZout_2[j] = 0;
	}

	// Initialise the coefficients

//	if (dblCoef[last] == 0.0)
	{
		for (i = first; i <= last; i++)
		{
			double x = 2 * M_PI * i / intN;
			x = cosf(1);

			dblCoef[i] = 2.0 * dblR * cosf(2 * M_PI * i / intN); // For Frequency = bin i
		}
	}
 }


void ARDOPSampleSink(short Sample)
{
	//	Filter and send to sound interface

	// This version is passed samples one at a time, as we don't have
	//	enough RAM in embedded systems to hold a full audio frame

	int intFilLen = intN / 2;
	int j;
	float intFilteredSample = 0;			//  Filtered sample

	//	We save the previous intN samples
	//	The samples are held in a cyclic buffer

	if (SampleNo < intN)
		dblZin = Sample;
	else
		dblZin = Sample - dblRn * Last120[Last120Get];

	if (++Last120Get == (intN + 1))
		Last120Get = 0;

	// Compute the Comb

	dblZComb = dblZin - dblZin_2 * dblR2;
	dblZin_2 = dblZin_1;
	dblZin_1 = dblZin;

	// Now the resonators

	for (j = first; j <= last; j++)
	{
		dblZout_0[j] = dblZComb + dblCoef[j] * dblZout_1[j] - dblR2 * dblZout_2[j];
	
		if (dblZout_0[j] != dblZout_0[j])
			j = j;
		
		dblZout_2[j] = dblZout_1[j];
		dblZout_1[j] = dblZout_0[j];

		switch (fWidth)
		{
		case 200:

			// scale each by transition coeff and + (Even) or - (Odd) 

			if (SampleNo >= intFilLen)
			{
				if (j == first || j == last)
				{
					if (SendingHeader200)
						intFilteredSample -= dblZout_0[j];  // This provides no attenuation to the Frame Type tones at 1350 and 1650
					else
						intFilteredSample -= 0.1 * dblZout_0[j]; // This smaller value required to filter down to 200 Hz bandwidth
				}
				else if ((j & 1) == 0)
					intFilteredSample += (int)dblZout_0[j];
				else
					intFilteredSample -= (int)dblZout_0[j];
			}

			break;

		case 500:

			// scale each by transition coeff and + (Even) or - (Odd) 
			// Resonators 12 and 18 scaled to get best shape and side lobe supression to - 45 dB while keeping BW at 500 Hz @ -26 dB
			// practical range of scaling .05 to .25
			// Scaling also accomodates for the filter "gain" of approx 60. 

			if (SampleNo >= intFilLen)
			{
				if (j == first || j == last)
					intFilteredSample += 0.389f * dblZout_0[j];
				else if ((j & 1) == 0)
					intFilteredSample += (int)dblZout_0[j];
				else
					intFilteredSample -= (int)dblZout_0[j];
			}

			break;

		case 2500:

			// scale each by transition coeff and + (Even) or - (Odd) 
			// Resonators 2 and 28 scaled to get best shape and side lobe supression to - 45 dB while keeping BW at 500 Hz @ -26 dB
			// practical range of scaling .05 to .25
			// Scaling also accomodates for the filter "gain" of approx 60. 

			if (SampleNo >= intFilLen)
			{
				if (j == first || j == last)
					intFilteredSample += 0.3891f * dblZout_0[j];
				else if ((j & 1) == 0)	// Even
					intFilteredSample += (int)dblZout_0[j];
				else
					intFilteredSample -= (int)dblZout_0[j];
			}
		}
	}

	if (SampleNo >= intFilLen)
	{
		intFilteredSample = intFilteredSample * 0.00833333333f; //  rescales for gain of filter
		largest = max(largest, intFilteredSample);
		smallest = min(smallest, intFilteredSample);

		if (intFilteredSample > 32700)  // Hard clip above 32700
			intFilteredSample = 32700;
		else if (intFilteredSample < -32700)
			intFilteredSample = -32700;

#ifdef TEENSY	
		int work = (short)(intFilteredSample);
		DMABuffer[Number++] = (work + 32768) >> 4; // 12 bit left justify
#else
		DMABuffer[Number++] = (short)intFilteredSample;
#endif
		if (Number == ARDOPBufferSize)
		{
			// send this buffer to sound interface (shouldn't happen)

			DMABuffer = SendtoCard(DMABuffer, SendSize);
			Number = 0;
		}
	}

	Last120[Last120Put++] = Sample;

	if (Last120Put == (intN + 1))
		Last120Put = 0;

	SampleNo++;
}



extern int dttTimeoutTrip;

extern UCHAR bytSessionID;


// Subroutine to make a CW ID Wave File

void sendCWID(char * strID, BOOL CWOnOff, int Chan)
{
	// This generates a phase synchronous FSK MORSE keying of strID
	// FSK used to maintain VOX on some sound cards
	// Sent at 90% of  max ampllitude

	char strAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/"; 

	//Look up table for strAlphabet...each bit represents one dot time, 3 adjacent dots = 1 dash
	// one dot spacing between dots or dashes

	int intCW[] = {0x17, 0x1D5, 0x75D, 0x75, 0x1, 0x15D, 
           0x1DD, 0x55, 0x5, 0x1777, 0x1D7, 0x175,
           0x77, 0x1D, 0x777, 0x5DD, 0x1DD7, 0x5D, 
           0x15, 0x7, 0x57, 0x157, 0x177, 0x757, 
           0x1D77, 0x775, 0x77777, 0x17777, 0x5777, 0x1577,
           0x557, 0x155, 0x755, 0x1DD5, 0x7775, 0x1DDDD, 0x1D57, 0x1D57};


	float dblHiPhaseInc = 2 * M_PI * 1509.375f / 12000; // 1609.375 Hz High tone
	float dblLoPhaseInc = 2 * M_PI * 1390.625f / 12000; // 1390.625  low tone
	float dblHiPhase = 0;
 	float dblLoPhase = 0;
 	int  intDotSampCnt = 768;  // about 12 WPM or so (should be a multiple of 256
	short intDot[768];
	short intSpace[768];
	int i, j, k;
	int intAmp = 26000;	   // Selected to have some margin in calculations with 16 bit values (< 32767) this must apply to all filters as well. 
	char * index;
	int intMask;
	int idoffset;
	int Filter = 1500;

	if (CWIDMark[0])
	{
		// Want  nonstandard tones

		float Mark = atof(CWIDMark);
		float Space = Mark - 200;

		dblHiPhaseInc = 2 * M_PI * Mark / 12000; // 1609.375 Hz High tone
		dblLoPhaseInc = 2 * M_PI * Space / 12000; // 1390.625  low tone

		if (CWOnOff)
			Filter = Mark;
		else
			Filter = (Mark + Space) / 2;
	}

    strlop(strID, '-');		// Remove any SSID    

	// Generate the dot samples (high tone) and space samples (low tone) 

	for (i = 0; i < intDotSampCnt; i++)
	{
		if (CWOnOff)
			intSpace[i] = 0;
		else
			intSpace[i] = sin(dblLoPhase) * 0.9 * intAmp;

		intDot[i] = sin(dblHiPhase) * 0.9 * intAmp;

		dblHiPhase += dblHiPhaseInc;
		if (dblHiPhase > 2 * M_PI)
			dblHiPhase -= 2 * M_PI;
		dblLoPhase += dblLoPhaseInc;
		if (dblLoPhase > 2 * M_PI)
			dblLoPhase -= 2 * M_PI;
	}
	
	if (CWOnOff)
		initFilter(500, Filter, Chan);
	else
		initFilter(200, Filter, Chan);


	//Generate leader for VOX 6 dots long

	for (k = 6; k >0; k--)
		for (i = 0; i < intDotSampCnt; i++)
			ARDOPSampleSink(intSpace[i]);

	for (j = 0; j < strlen(strID); j++)
	{
		index = strchr(strAlphabet, strID[j]);
		if (index)
			idoffset = index - &strAlphabet[0];
		else
			idoffset = 0;

		intMask = 0x40000000;

		if (index == NULL)
		{
			// process this as a space adding 6 dots worth of space to the wave file

			for (k = 6; k >0; k--)
				for (i = 0; i < intDotSampCnt; i++)
					ARDOPSampleSink(intSpace[i]);
		}
		else
		{
		while (intMask > 0) //  search for the first non 0 bit
			if (intMask & intCW[idoffset])
				break;	// intMask is pointing to the first non 0 entry
			else
				intMask >>= 1;	//  Right shift mask
				
		while (intMask > 0) //  search for the first non 0 bit
		{
			if (intMask & intCW[idoffset])
				for (i = 0; i < intDotSampCnt; i++)
					ARDOPSampleSink(intDot[i]);
			else
				for (i = 0; i < intDotSampCnt; i++)
					ARDOPSampleSink(intSpace[i]);
	
			intMask >>= 1;	//  Right shift mask
		}
		}
			// add 2 dot spaces for inter letter spacing
			for (k = 4; k >0; k--)
				for (i = 0; i < intDotSampCnt; i++)
					ARDOPSampleSink(intSpace[i]);
	}
	
	//add 3 spaces for the end tail
	
//	for (k = 6; k >0; k--)
//		for (i = 0; i < intDotSampCnt; i++)
//			ARDOPSampleSink(intSpace[i]);

	ARDOPTXPtr[Chan] = 0;
	ARDOPTXLen[Chan] = Number;
	Number = 0;
}