/* SigLib Frequency Domain Pitch Shifting
by interpolation, The process used is equivalent to time-domain
sin(x) / x interpolation. The shifted signal is a sine wave.

This algorithm benefits from using overlapping windows, in general,
the greater the overlap, the better the performance. ie. the lower
the distortion.
*/

#include <stdio.h>
#include <siglib.h>
#include "GraphFunctions.h"

#define	LENGTH1				((SLArrayIndex_t)64)
#define	LENGTH2				256L
#define	SMALL_FFT_SIZE		LENGTH1
#define	LOG_SMALL_FFT_SIZE	6L
#define	LARGE_FFT_SIZE		LENGTH2
#define	LOG_LARGE_FFT_SIZE	((SLArrayIndex_t)8)

SLData_t	pRealInput[LENGTH2], pImagInput[LENGTH2];
SLData_t	pRealOutput[LENGTH2], pImagOutput[LENGTH2];
SLData_t	*pFFTCoeffs;
SLData_t	SinePhase;

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


						/* Allocate enough space for largest FFT */
	pFFTCoeffs = SUF_FftCoefficientAllocate (LARGE_FFT_SIZE);

	h2DGraph =										/* Initialize graph */
		Create2DGraph ("Frequency Domain Interpolation",	/* Graph title */
					   "Time / Frequency",			/* 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);
	}

													/* Initialise FFT */
	SIF_Fft (pFFTCoeffs,							/* Pointer to FFT coefficients */
			 SIGLIB_NULL_ARRAY_INDEX_PTR,			/* Pointer to bit reverse address table - NOT USED */
			 SMALL_FFT_SIZE);						/* FFT Size */

	SinePhase = SIGLIB_ZERO;

	SDA_SignalGenerate (pRealInput,					/* Pointer to destination array */
						SIGLIB_SINE_WAVE,			/* Signal type - Sine wave */
						((SLData_t)0.9),			/* Signal peak level */
						SIGLIB_FILL,				/* Fill (overwrite) or add to existing array contents */
						((SLData_t)0.038),			/* Signal frequency */
						SIGLIB_ZERO,				/* D.C. Offset */
						SIGLIB_ZERO,				/* Unused */
						SIGLIB_ZERO,				/* Signal end value - Unused */
						&SinePhase,					/* Signal phase - maintained across array boundaries */
						SIGLIB_NULL_DATA_PTR,		/* Unused */
						LENGTH1);					/* Output array length */

	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Source signal (time domain)",	/* Title of the dataset */
				    pRealInput,						/* Array of Double dataset */
				    LENGTH1,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_MAGENTA,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	printf ("\nSource signal (time domain)\nPlease hit <Carriage Return> to continue . . ."); getchar ();

													/* Perform real FFT */
	SDA_Rfft (pRealInput,							/* Pointer to real array */
			  pImagInput,							/* Pointer to imaginary array */
			  pFFTCoeffs,							/* Pointer to FFT coefficients */
			  SIGLIB_NULL_ARRAY_INDEX_PTR,			/* Pointer to bit reverse address table - NOT USED */
			  SMALL_FFT_SIZE,						/* FFT size */
			  LOG_SMALL_FFT_SIZE);					/* log2 FFT size */


	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Source signal (frequency domain - real)",	/* Title of the dataset */
				    pRealInput,						/* Array of Double dataset */
				    LENGTH1,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_MAGENTA,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Source signal (frequency domain - imag)",	/* Title of the dataset */
				    pImagInput,						/* Array of Double dataset */
				    LENGTH1,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_BLUE,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("\nSource signal (frequency domain)\nPlease hit <Carriage Return> to continue . . ."); getchar ();

						/* Perform frequency domain interpolation */
						/* Interp. factor defined by array length ratios */
	SDA_FdInterpolate2 (pRealInput,					/* Pointer to real source array */
						pImagInput,					/* Pointer to imaginary source array */
						pRealOutput,				/* Pointer to real destination array */
						pImagOutput,				/* Pointer to imaginary destination array */
						LENGTH1,					/* Source array length */
						LENGTH2);					/* Destination array length */


	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (frequency domain - real)",	/* Title of the dataset */
				    pRealOutput,					/* Array of Double dataset */
				    LENGTH2,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_MAGENTA,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (frequency domain - imag)",	/* Title of the dataset */
				    pImagOutput,					/* Array of Double dataset */
				    LENGTH2,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_BLUE,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("\nInterpolated signal (frequency domain)\nPlease hit <Carriage Return> to continue . . ."); getchar ();


													/* Prepare for inverse FFT */
	SIF_Fft (pFFTCoeffs,							/* Pointer to FFT coefficients */
			 SIGLIB_NULL_ARRAY_INDEX_PTR,			/* Pointer to bit reverse address table - NOT USED */
			 LARGE_FFT_SIZE);						/* FFT Size */

	SDA_Cifft (pRealOutput, pImagOutput, pFFTCoeffs, SIGLIB_NULL_ARRAY_INDEX_PTR, LARGE_FFT_SIZE, LOG_LARGE_FFT_SIZE);	/* Perform FFT */


	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (time domain - real)",	/* Title of the dataset */
				    pRealOutput,					/* Array of Double dataset */
				    LENGTH2,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_MAGENTA,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (time domain - imag)",	/* Title of the dataset */
				    pImagOutput,					/* Array of Double dataset */
				    LENGTH2,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_BLUE,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("\nInterpolated signal (time domain)\nPlease hit <Carriage Return> to continue . . ."); getchar ();

	
													/* Copy the array and reverse the process */
	SDA_Copy (pRealOutput,							/* Pointer to source array */
			  pRealInput,							/* Pointer to destination array */
			  LENGTH2);								/* Array length */

													/* Perform real FFT */
	SDA_Rfft (pRealInput,							/* Pointer to real array */
			  pImagInput,							/* Pointer to imaginary array */
			  pFFTCoeffs,							/* Pointer to FFT coefficients */
			  SIGLIB_NULL_ARRAY_INDEX_PTR,			/* Pointer to bit reverse address table - NOT USED */
			  LARGE_FFT_SIZE,						/* FFT size */
			  LOG_LARGE_FFT_SIZE);					/* log2 FFT size */


	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Source signal (frequency domain - real)",	/* Title of the dataset */
				    pRealInput,						/* Array of Double dataset */
				    LENGTH2,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_MAGENTA,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Source signal (frequency domain - imag)",	/* Title of the dataset */
				    pImagInput,						/* Array of Double dataset */
				    LENGTH2,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_BLUE,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("\nSource signal (frequency domain)\nPlease hit <Carriage Return> to continue . . ."); getchar ();


						/* Perform frequency domain interpolation */
						/* Interp. factor defined by array length ratios */
	SDA_FdInterpolate2 (pRealInput,					/* Pointer to real source array */
						pImagInput,					/* Pointer to imaginary source array */
						pRealOutput,				/* Pointer to real destination array */
						pImagOutput,				/* Pointer to imaginary destination array */
						LENGTH2,					/* Source array length */
						LENGTH1);					/* Destination array length */


	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (frequency domain - real)",	/* Title of the dataset */
				    pRealOutput,					/* Array of Double dataset */
				    LENGTH1,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_MAGENTA,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (frequency domain - imag)",	/* Title of the dataset */
				    pImagOutput,					/* Array of Double dataset */
				    LENGTH1,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_BLUE,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("\nInterpolated signal (frequency domain)\nPlease hit <Carriage Return> to continue . . ."); getchar ();


													/* Prepare for inverse FFT */
	SIF_Fft (pFFTCoeffs,							/* Pointer to FFT coefficients */
			 SIGLIB_NULL_ARRAY_INDEX_PTR,			/* Pointer to bit reverse address table - NOT USED */
			 SMALL_FFT_SIZE);						/* FFT Size */

	SDA_Cifft (pRealOutput, pImagOutput, pFFTCoeffs, SIGLIB_NULL_ARRAY_INDEX_PTR, SMALL_FFT_SIZE, LOG_SMALL_FFT_SIZE);	/* Perform FFT */

	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (time domain - real)",	/* Title of the dataset */
				    pRealOutput,					/* Array of Double dataset */
				    LENGTH1,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_MAGENTA,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Interpolated signal (time domain - imag)",	/* Title of the dataset */
				    pImagOutput,					/* Array of Double dataset */
				    LENGTH1,						/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_BLUE,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("\nInterpolated signal (time domain)\n");

	SUF_MemoryFree (pFFTCoeffs);					/* Free memory */
}

