/* Complex Frequency Shifting Example
	Simulated sample rate = 10 KHz
	Input signal frequency = 100 Hz
	Modulation frequency = 1 KHz
*/

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <siglib.h>
#include "GraphFunctions.h"

/* Define constants */
#define	SAMPLE_LENGTH					((SLArrayIndex_t)512)
#define	COMP_SHFT_CARRIER_TABLE_LENGTH	((SLArrayIndex_t)1000)
#define	FILTER_LENGTH					((SLArrayIndex_t)10)

#define	SAMPLE_RATE				((SLData_t)10000.0)		/* Sample rates normalized to 1 Hz */
#define	CARRIER_FREQUENCY		((SLData_t)1000.0)		/* Modulation carrier frequency */
#define	MODULATING_FREQUENCY	((SLData_t)100.0)		/* Frequency of modulating signal */

#define CARRIER_TABLE_LENGTH	((SLArrayIndex_t)(SAMPLE_RATE / CARRIER_FREQUENCY))


/* Global variables */
SLData_t		pModulatingData [SAMPLE_LENGTH];
SLData_t		pModulatedData [SAMPLE_LENGTH];
SLData_t		pShiftedData [SAMPLE_LENGTH];

SLData_t		ModulatingSignalPhase;

SLData_t		*pCarrierTable;
SLArrayIndex_t	CarrierTableIndex;

SLData_t		*pCombFilter1, *pCombFilter2, *pSineTable;
SLData_t		CombFilter1Sum, CombFilter2Sum;
SLArrayIndex_t	CombFilterpPhase, SineTablePhase;

void main (void);

void main (void)
{
	GraphObject *h2DGraph;							/* Declare graph object */

	SLFixData_t	action, io = 0;
	time_t		ltime;

	time (&ltime);
	srand ((unsigned int) ltime);					/* Randomise the seed */

	pCombFilter1 = SUF_VectorArrayAllocate (FILTER_LENGTH);
	pCombFilter2 = SUF_VectorArrayAllocate (FILTER_LENGTH);
	pSineTable = SUF_VectorArrayAllocate (COMP_SHFT_CARRIER_TABLE_LENGTH);
	pCarrierTable = SUF_AmCarrierArrayAllocate (CARRIER_FREQUENCY, SAMPLE_RATE);

	SIF_AmplitudeModulate (pCarrierTable,			/* Carrier table pointer */
						   &CarrierTableIndex,		/* Carrier table index */
						   CARRIER_TABLE_LENGTH);	/* Modulator array length */

	SIF_ComplexShift (pCombFilter1,					/* Comb filter 1 pointer */
					  &CombFilter1Sum,				/* Comb filter 1 running sum */
					  pCombFilter2,					/* Comb filter 2 pointer */
					  &CombFilter2Sum,				/* Comb filter 2 running sum */
					  &CombFilterpPhase,			/* Comb filter phase */
					  pSineTable,					/* Sine table pointer */
					  &SineTablePhase,				/* Sine table phase for mixer */
					  FILTER_LENGTH,				/* Length of comb filter */
					  COMP_SHFT_CARRIER_TABLE_LENGTH/* Length of demodulation sine table */);

	h2DGraph =										/* Initialize graph */
		Create2DGraph ("Complex Shift",				/* Graph title */
					   "Time",						/* X-Axis label */
					   "Magnitude",					/* Y-Axis label */
					   SV_AUTO_SCALE,				/* Scaling mode */
					   SV_SIGNED,					/* Sign mode */
					   SV_GRAPH_LINE,				/* Graph type */
					   "localhost");				/* Graph server */
	if (h2DGraph == NULL)							/* Graph creation failed - e.g is server running ? */
	{
		printf ("\nGraph creation failure. Please check that the server is running\n");
		exit (1);
	}

	ModulatingSignalPhase = SIGLIB_ZERO;			/* Initialise signal phases */

	printf ("Hit p to pause, i to swap i/o display or any other key to exit\n");
	printf ("Input signal\n");

	for (;;)
	{
		if (kbhit ())
		{
			action = tolower (getch ());
			if (action == 'p')
			{
				while (!kbhit ())
					;
				getch ();
			}
			else if (action == 'i')
			{
				if (io == 0)
				{
					io = 1;
					printf ("Output signal\n");
				}
				else
				{
					io = 0;
					printf ("Input signal\n");
				}
			}
			else
			{
				break;								/* Exit */
			}
		}

																/* Generate the modulating signal */
		SDA_SignalGenerate (pModulatingData,					/* Pointer to destination array */
							SIGLIB_SQUARE_WAVE,					/* Signal type - Square wave */
							((SLData_t)0.4),					/* Signal peak level */
							SIGLIB_FILL,						/* Fill (overwrite) or add to existing array contents */
							MODULATING_FREQUENCY / SAMPLE_RATE,	/* Signal frequency */
							SIGLIB_HALF,						/* D.C. Offset */
							((SLData_t)0.75),					/* Duty cycle */
							SIGLIB_ZERO,						/* Signal end value - Unused */
							&ModulatingSignalPhase,				/* Signal phase - maintained across array boundaries */
							SIGLIB_NULL_DATA_PTR,				/* Unused */
							SAMPLE_LENGTH);						/* Output array length */

															/* Modulate the signal */
		SDA_AmplitudeModulate (pModulatingData,				/* Modulating signal source pointer */
							pCarrierTable,					/* Carrier table pointer */
							pModulatedData,					/* Modulated signal destination pointer */
							&CarrierTableIndex,				/* Carrier table index */
							CARRIER_TABLE_LENGTH,			/* Modulator array length */
							SAMPLE_LENGTH);					/* Array length */

		SDA_ComplexShift (pModulatedData,					/* Modulating signal source pointer */
						pShiftedData,						/* Modulated signal destination pointer */
						pCombFilter1,						/* Comb filter 1 pointer */
						&CombFilter1Sum,					/* Comb filter 1 running sum */
						pCombFilter2,						/* Comb filter 2 pointer */
						&CombFilter2Sum,					/* Comb filter 2 running sum */
						&CombFilterpPhase,					/* Comb filter phase */
						pSineTable,							/* Sine table pointer */
						&SineTablePhase,					/* Sine table phase for mixer */
						CARRIER_FREQUENCY / SAMPLE_RATE,	/* Mix frequency */
						FILTER_LENGTH,						/* Length of comb filter */
						COMP_SHFT_CARRIER_TABLE_LENGTH,		/* Sine table size for mixer */
						SAMPLE_LENGTH);						/* Array length */
	
		if (io == 0)				/* Display input or output array */
		{
			Display2DGraph (h2DGraph,				/* Graph handle */
						    "Modulated Data",		/* Title of the dataset */
						    pModulatedData,			/* Array of Double dataset */
						    SAMPLE_LENGTH,			/* Number of data points */
							SV_GRAPH_LINE,			/* Graph type */
						    SV_MAGENTA,				/* Colour */
							SV_HIDE_MARKERS,		/* Marker enable / disable */
							SV_GRAPH_NEW);			/* New graph */
		}
		else
		{
			Display2DGraph (h2DGraph,				/* Graph handle */
						    "Shifted Data",			/* Title of the dataset */
						    pShiftedData,			/* Array of Double dataset */
						    SAMPLE_LENGTH,			/* Number of data points */
							SV_GRAPH_LINE,			/* Graph type */
						    SV_MAGENTA,				/* Colour */
							SV_HIDE_MARKERS,		/* Marker enable / disable */
							SV_GRAPH_NEW);			/* New graph */
		}
	}

	SUF_MemoryFree (pCombFilter1);					/* Free memory */
	SUF_MemoryFree (pCombFilter2);
	SUF_MemoryFree (pSineTable);
	SUF_MemoryFree (pCarrierTable);
}


