/* v:\ece420\54x\dspclib\lab4bmain.c */
/* PN generation, IIR filtering, and autocorrelation added */
/* by Matt Kleffner - 9/2004 */
/* Original by dgs  - 9/14/2001 */
/* Use governed by the Creative Commons Attribution License */

#include "v:\ece420\54x\dspclib\core.h"

/* #define N 1024 */             /* Number of FFT points */
#include "lab4b.h"               /* Define N here in header file */

/* function defined in pn.c */
int randsample(unsigned int *iseed);

/* IIR values and buffers (declared in c_fft_given_iirc.asm) */
#define IIR_order 4
extern int scale;
extern int coef[IIR_order];
extern int state[IIR_order];
int iirptr;

/* function defined in autocorr.c */
void autocorr(void);

/* Function defined by c_fft_given_iirc.asm */
void bit_rev_fft(void);

/* FFT data buffers (declared in c_fft_given_iirc.asm) */
extern int bit_rev_data[N*2];   /* Data input for bit-reverse function */
extern int fft_data[N*2];       /* In-place FFT & Output array */

/* Our input/output buffers */
int inputs[N];
int outputs[N];
int display_inputs[N];
int autocorr_in[N];
int autocorr_out[N];

unsigned int *iseed;            /* seed for randsample() */

volatile int input_full = 0;    /* volatile means interrupt changes it */
int count = 0;

interrupt void irq(void)
{
  int *Xmitptr,*Rcvptr;         /* pointers to Xmit & Rcv Bufs */
  int i;

  static int in_irq = 0;        /* Flag to prevent reentrance */

  /* Make sure we're not in the interrupt (should never happen) */
  if( in_irq )
    return;

  /* Mark we're processing, and enable interrupts */
  in_irq = 1;
  enable_irq();

  /* The following waitaudio call is guaranteed not to
     actually wait; it will simply return the pointers. */
  WaitAudio(&Rcvptr,&Xmitptr);

  /* input_full should never be true... */
  if( !input_full )
  {
    for (i=0; i<BlockLen; i++)
    {
      /* Save input, send display_inputs to channel 1 */
      inputs[count] = Rcvptr[4*i];
      Xmitptr[6*i] = display_inputs[count];
      /* inputs[count] = Xmitptr[6*i] = Rcvptr[4*i];  */

      /* Send FFT output to channel 2 */
      Xmitptr[6*i+1] = outputs[count];

      count++;
    }
    /* Have we collected enough data yet? */
  }
    if( count >= N ) input_full = 1;

  /* We're not in the interrupt anymore... */
  disable_irq();
  in_irq = 0;
}

main()
{
  int i,j;
  *iseed = 1;
  iirptr = 0;
  /* Initialize IRQ stuff */
  count = 0;
  input_full = 0;

  /* Initialize autocorr_out to zero since some values will remain zero */
  for (i = 0; i < N; ++i)
  {
     autocorr_out[i] = 0;
     display_inputs[i] = 0;
  }
  for (i = 0; i < IIR_order; ++i) state[i] = 0;

  SetAudioInterrupt(irq);       /* Set up interrupts */

  while (1)
  {
    while( !input_full );       /* Wait for a data buffer to collect */

    /* From here until we clear input_full can only take *
     * BlockLen sample times, so don't do too much here. */

    /* First, transfer inputs and outputs */

    for (i = 0; i < N; i++) {
        display_inputs[i] = autocorr_in[i];
        outputs[i] = fft_data[i*2] << 8;

        /* Some statements useful in debugging */
        /* display_inputs[i] = inputs[i]; */
        /* autocorr_in[i] = inputs[i] */
    }
    /* Last, set the DC coefficient to -1 for a trigger pulse */
    outputs[0] = -32768;

    /* Done with that... ready for new data collection */
    count = 0;		      /* Need to reset the count               */
    input_full = 0;     /* Mark we're ready to collect more data */

    /*************************************************************/
    /* Now that we've gotten the data moved, we can do the	     */
    /* more lengthy processing.					                    */

    /* Generate PN input */
    for (i = 0; i < N; ++i)
      autocorr_in[i] = randsample(iseed);

    /* Filter PN input */
    for (i = 0; i < N; ++i)
    {
       int sum = 0;
       /* Calculate and sum all feedback terms except the "oldest" one */
       for (j = 0; j < (IIR_order-1); ++j)
       {
          sum += ((long int)coef[j] * (long int)state[iirptr]) >> 15;
          /* Avoid usage of "modulo" routine */
          iirptr++;
          if (iirptr == IIR_order) iirptr = 0;
       }
       /* Calculate and sum oldest feedback term without incrementing iirptr */
       sum += ((long int)coef[IIR_order-1] * (long int)state[iirptr]) >> 15;

       autocorr_in[i] = ((long int)scale * (long int)autocorr_in[i]) >> 15;
       autocorr_in[i] += sum;
       state[iirptr] = autocorr_in[i];
    }

    /* Calculate autocorrelation */
    autocorr();

    /* Transfer autocorr output to FFT input buffer */
    for (i = 0; i < N; i++) {
        bit_rev_data[i*2] = autocorr_out[i];
        bit_rev_data[i*2+1] = 0;
    }
    /* Bit-reverse and compute FFT */
    bit_rev_fft();

    /* Done, wait for next time around! */
  }
}
