/* SigLib - DTMF Generation Example

Freq. (Hz) 1209 1336 1477 1633 
	697		1	  2	   3	A 
	770		4	  5	   6	B 
	852		7	  8	   9	C 
	941		*	  0	   #	D 
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <siglib.h>
#include "nhl.h"

/* Define constants */
#define	MAX_SAMPLE_LENGTH		((SLArrayIndex_t)4000)
#define	SAMPLE_RATE				((SLData_t)8000.0)
#define SAMPLES_PER_MS			((SLArrayIndex_t)(SAMPLE_RATE / 1000.0))
#define DETECTION_THRESHOLD		((SLData_t)1000.0)

#define	DTMF_SAMPLE_LENGTH		102L

/* Declare arrays and variables */
SLData_t		*pData;								/* DTMF data */
SLData_t		*pDTMFDetectState;					/* DTMF detector state */
SLData_t		*pDTMFGenCoeffs;					/* DTMF generator frequency look up table */
WAV_FILE_INFO	WavInfo;

char	TextSrcFilename[] = "dtmf.txt";
FILE	*pInputFile;

char	WavDstFilename[] = "dtmf.wav";
FILE	*pOutputFile;

void	main(void);
int read_dtmf_key (char *pTone, SLFixData_t *pPeriod, SLData_t *pMagnitude);

void main (void)

{
	char		Tone;
	SLFixData_t	Period;
	SLData_t	Magnitude;
	long		FileLength = 0;
	SLStatus_t	KeyCode;
	SLFixData_t	SampleCount;
	SLStatus_t	PreviousKeyCode = SIGLIB_NO_DTMF_SIGNAL;	/* Initialise to no DTMF key detected */
	SLFixData_t	KeyCodeLength = 0;							/* Length of key code stream */
	SLFixData_t	KeyCodeRegistered = SIGLIB_FALSE;			/* A key code has not been registered */

	SLFixData_t	PreviousKeyCodeLength = 0L;
	SLData_t	LinearDTMFMagnitude;
	SLData_t	Max = SIGLIB_ZERO;
	SLData_t	NewMax = SIGLIB_ZERO;

	pData = SUF_VectorArrayAllocate (MAX_SAMPLE_LENGTH);
	pDTMFDetectState = SUF_VectorArrayAllocate (SIGLIB_GOERTZEL_DELAY_LENGTH);
	pDTMFGenCoeffs = SUF_VectorArrayAllocate (SIGLIB_DTMF_FTABLE_LENGTH);

	if ((pInputFile = fopen(TextSrcFilename, "r")) == NULL)
	{
		printf ("Can not open input data file %s\n", TextSrcFilename);
		exit (0);
	}

	if ((pOutputFile = fopen(WavDstFilename, "wb")) == NULL)
	{
		printf ("Can not open output data file %s\n", WavDstFilename);
		exit (0);
	}

	WavInfo = wav_set_info ((long)8000, (long)FileLength, (short)1, (short)16, (short)2, (short)1);
	wav_write_header (pOutputFile, WavInfo);

	SIF_DtmfGenerate (pDTMFGenCoeffs,				/* Generator coefficient look up table pointer */
			 		  SAMPLE_RATE);					/* Sample rate */

	while (read_dtmf_key (&Tone, &Period, &Magnitude) == 0)			/* While there are key codes */
	{
		LinearDTMFMagnitude = SDS_dBmToLinear (Magnitude, (SLData_t)32767.0) / SIGLIB_TWO;	/* Note divide by two necessary for SDA_DtmfGenerate () */
		printf ("Tone = %c, Period = %ld (ms), Magn. = %lf (dB), Lin. Magn. = %lf\n", Tone, Period, Magnitude, LinearDTMFMagnitude);

		if (Tone == 'S')
		{
			SDA_Clear (pData,						/* Pointer to destination array */
					   Period*SAMPLES_PER_MS);		/* Array length */
		}
		else
		{
			SDA_DtmfGenerate (pData,						/* Destination array pointer */
							  SUF_AsciiToKeyCode (Tone),	/* Key code */
							  LinearDTMFMagnitude,			/* Signal magnitude */
							  pDTMFGenCoeffs,				/* Generator coefficient look up table pointer */
							  Period*SAMPLES_PER_MS);		/* Array length */
		}

		wav_write_data (pData, pOutputFile, WavInfo, Period*SAMPLES_PER_MS);

		FileLength += Period*SAMPLES_PER_MS;
	}

	printf ("DTMF signal has been generated\nPlease hit <CR> to decode . . .\n");
	getchar();

						/* Now update the header to indicate the filelength */
	WavInfo = wav_set_info ((long)8000, (long)FileLength, (short)1, (short)16, (short)2, (short)1);
	rewind (pOutputFile);
	wav_write_header (pOutputFile, WavInfo);

	fclose (pInputFile);
	fclose (pOutputFile);

						/* We have generated the DTMF file now we will detect the contents */
	if ((pInputFile = fopen(WavDstFilename, "rb")) == NULL)	/* Note this file is binary */
	{
		printf ("Error opening input .WAV file\n");
		exit (1);
	}

	WavInfo = wav_read_header (pInputFile);
	if (WavInfo.NumberOfChannels == 0)				/* Check how many channels */
	{
		printf ("Error reading .WAV file header\n");
		exit (1);
	}

	wav_display_info (WavInfo);
	printf ("\n.WAV file data. '.' indicates no tone present\n");
	printf ("                '-' indicates signal present but not DTMF\n\n");

	SIF_DtmfDetect (pDTMFDetectState,				/* Pointer to filter state array */
			 		((SLData_t)WavInfo.SampleRate),	/* Sample rate */
			  		DTMF_SAMPLE_LENGTH);			/* Array length */

	while ((SampleCount = wav_read_data (pData, pInputFile, WavInfo, DTMF_SAMPLE_LENGTH)) == DTMF_SAMPLE_LENGTH)
	{
		NewMax = SDA_Max (pData, DTMF_SAMPLE_LENGTH);	/* Detect the peak value of the DTMF signal */
		if (NewMax > Max)
			Max = NewMax;

		KeyCode =
			SDA_DtmfDetectAndValidate (pData,				/* Source array pointer */
									   pDTMFDetectState,	/* Pointer to filter state array */
									   DETECTION_THRESHOLD,	/* Threshold for signal energy */
									   &PreviousKeyCode,	/* Pointer to previous key code */
									   &KeyCodeLength,		/* Pointer to key code run length */
									   &KeyCodeRegistered,	/* Pointer to storage for key code registration flag */
									   DTMF_SAMPLE_LENGTH);	/* Array length */

#if COMMENT
		printf ("Keycode = %ld, %lx\n", KeyCode, KeyCode);
		SUF_Debugfprintf ("Keycode = %ld, %lx\n", KeyCode, KeyCode);

		KeyCode =
			SDA_DtmfDetect (pData,					/* Source array pointer */
						 	pDTMFDetectState,		/* Pointer to filter state array */
						 	DTMF_SAMPLE_LENGTH);	/* Array length */
#endif

		if (KeyCode == SIGLIB_NO_SIGNAL_PRESENT)
		{
			printf ("(Length %d)\n", (short)PreviousKeyCodeLength);
			printf (". ");
		}

		else if (KeyCode == SIGLIB_NO_DTMF_SIGNAL)
		{
			printf ("(Length %d)\n", (short)PreviousKeyCodeLength);
			printf ("- ");
		}

		else if (KeyCode != SIGLIB_DTMF_CONTINUATION)
		{
			printf ("(Length %d)\n", (short)PreviousKeyCodeLength);
			printf ("%c ", SUF_KeyCodeToAscii (KeyCode));
		}

		else					/* KeyCode == SIGLIB_DTMF_CONTINUATION */
		{
			PreviousKeyCodeLength = KeyCodeLength;
		}
	}

	printf ("\n\n\n");
	printf ("DTMF signal peak magnitude = %lf\n", Max);
	printf ("\n\n\n");

	SUF_MemoryFree (pData);							/* Free memory */
	SUF_MemoryFree (pDTMFDetectState);
	SUF_MemoryFree (pDTMFGenCoeffs);

}


/*
Function : read_dtmf_key ()
Read a set of dtmf keys
Return codes :
	0 - success
	1 - end of file
	2 - [START] not found
*/
int read_dtmf_key (char *pTone, SLFixData_t *pPeriod, SLData_t *pMagnitude)

{
	static int FirstTimeFlag = 1;
	static int StartFound = 0;
	char InputString[80];
	char *InputStringPtr;
	char ch;

	InputStringPtr = InputString;

	if (FirstTimeFlag == 1)			/* Read past header */
	{
		while (((ch = (char)getc(pInputFile)) != EOF) && !StartFound)	/* Get next character in source file */
		{
			if (ch != ((char)0x0a))
				*InputStringPtr++ = ch;		/* Store character in word array */

			else							/* End of line */
			{
				*InputStringPtr = '\0';		/* Store end of string in word array */
				InputStringPtr = InputString;
			}

			if (!strcmp (InputString, "[START]"))
				StartFound = 1;
		}

		FirstTimeFlag = 0;
		ungetc (ch, pInputFile);			/* Unget the last character */

		if (!StartFound)
		{
			return(2);						/* We have not found the start of the data */
		}
	}

	if (fscanf (pInputFile, "%c, %ld, %lf\n", pTone, pPeriod, pMagnitude) != EOF)
	{
		if (*pPeriod > 500L)
			*pPeriod = 500L;
		if (*pMagnitude > SIGLIB_ZERO)
			*pMagnitude = -*pMagnitude;
		return(0);
	}

	else
		return(1);							/* Failure */
}

