//GraphicEQ.c Graphic Equalizer using TI floating-point FFT functions

#include <math.h>
#include "GraphicEQcoeff.h"       //time-domain FIR coefficients
#define PI 3.14159265358979
#define PTS 256                   //number of points for FFT
#define SQRT_PTS 16
#define RADIX 2			
#define DELTA (2*PI)/PTS
typedef struct Complex_tag {float real,imag;} COMPLEX;
#pragma DATA_ALIGN(W,sizeof(COMPLEX))
#pragma DATA_ALIGN(samples,sizeof(COMPLEX))
#pragma DATA_ALIGN(h,sizeof(COMPLEX))
COMPLEX W[PTS/RADIX] ;		    //twiddle array 
COMPLEX samples[PTS];
COMPLEX h[PTS];
COMPLEX bass[PTS], mid[PTS], treble[PTS];
short buffercount = 0;            //buffer count for iobuffer samples  
float iobuffer[PTS/2];            //primary input/output buffer
float overlap[PTS/2];		    //intermediate result buffer
short i;                          //index variable 
short flag = 0;                   //set to indicate iobuffer full
float a, b;                       //variables for complex multiply
short NUMCOEFFS = sizeof(lpcoeff)/sizeof(float);
short iTwid[SQRT_PTS] ;		    //PTS/2+1 > sqrt(PTS)
float bass_gain = 1.0;            //initial gain values 
float mid_gain = 0.0;             //change with GraphicEQ.gel
float treble_gain = 1.0;

interrupt void c_int11(void)      //ISR
{
 output_sample((int)(iobuffer[buffercount]));
 iobuffer[buffercount++] = (float)(input_sample());
 if (buffercount >= PTS/2)        //for overlap-add method iobuffer
  {                               //is half size of FFT used
   buffercount = 0;
   flag = 1;
  }
}
     
main()
{
 digitrev_index(iTwid, PTS/RADIX, RADIX);	
 for( i = 0; i < PTS/RADIX; i++ )
  {
   W[i].real = cos(DELTA*i);
   W[i].imag = sin(DELTA*i);
  }
 bitrev(W, iTwid, PTS/RADIX);     //bit reverse W

 for (i=0 ; i<PTS ; i++)
  {
   bass[i].real = 0.0;
   bass[i].imag = 0.0;
   mid[i].real = 0.0;
   mid[i].imag = 0.0;
   treble[i].real = 0.0;
   treble[i].imag = 0.0;
  }
 for (i=0; i<NUMCOEFFS; i++)      //same # of coeff for each filter
  {                             
   bass[i].real = lpcoeff[i];     //lowpass coeff
   mid[i].real =  bpcoeff[i];     //bandpass coeff
   treble[i].real = hpcoeff[i];   //highpass coef
  }                        
 
 cfftr2_dit(bass,W,PTS);          //transform each band into frequency
 cfftr2_dit(mid,W,PTS);
 cfftr2_dit(treble,W,PTS); 
 
 comm_intr();                     //initialise DSK, codec, McBSP
 while(1) 				    //frame processing infinite loop
  {
   while (flag == 0);             //wait for iobuffer full
          flag = 0;
   for (i=0 ; i<PTS/2 ; i++)      //iobuffer into samples buffer  
    {                               
     samples[i].real = iobuffer[i];
     iobuffer[i] = overlap[i];    //previously processed output 
    }					    //to iobuffer
   for (i=0 ; i<PTS/2 ; i++)       
    {                             //upper-half samples to overlap
     overlap[i] = samples[i+PTS/2].real;
     samples[i+PTS/2].real = 0.0; //zero-pad input from iobuffer
    }                             
   for (i=0 ; i<PTS ; i++)                          
     samples[i].imag = 0.0;       //init samples buffer
   
   cfftr2_dit(samples,W,PTS);
   
   for (i=0 ; i<PTS ; i++)        //construct freq domain filter 
    {                             //sum of bass,mid,treble coeffs 
    h[i].real = bass[i].real*bass_gain + mid[i].real*mid_gain
		  + treble[i].real*treble_gain;
    h[i].imag = bass[i].imag*bass_gain + mid[i].imag*mid_gain
		  + treble[i].imag*treble_gain;
    }          
   for (i=0; i<PTS; i++)          //frequency-domain representation
    {                             //complex multiply samples by h
     a = samples[i].real;
     b = samples[i].imag;
     samples[i].real = h[i].real*a - h[i].imag*b;
     samples[i].imag = h[i].real*b + h[i].imag*a;
    }
   
   icfftr2_dif(samples,W,PTS);
   
   for (i=0 ; i<PTS ; i++) 
      samples[i].real /= PTS;
   for (i=0 ; i<PTS/2 ; i++)      //add 1st half to overlap
      overlap[i] += samples[i].real;
  }                               //end of infinite loop
}                                 //end of main()