#include <math.h>
#include <stdio.h>
#include <sys/soundcard.h>
#include "OscBank.h"
#include "miditabl.h"
#include "MIDIInpt.h"
#include "RTWvOut.h"

// set this to 1 to have volume and amplitude
// control side by side.

#define POLYPHONY 5
#define PARTIALS 6		// This is default--first command line arg changes
				// this
main(int argc, char** argv)
{
 
  int i, DELTA=1, j;
  int INHARM=1;                 // A flag determininig whether we are controlling
				// frequencies or inharmonic factor.
  int cntOn = 0;		// These are for polyphony!!!
  
  int N = PARTIALS, over = 1;
  int CENTER=60;		// The center of the scale that remains unstretched
  double STRETCH=2, SCALE=2, ROLLOFF=1; // slider paramteres
  double freq=400, temp, temp2, out;
  RTWvOut output;
  OscBank *o[POLYPHONY];
  int sounding[POLYPHONY];
  MIDIInpt controller;
  DataWindow *data;

  double INH_range = 1.1;	// For controlling inharmonicity
  //double INH_mult = log(INH_range)/128;
  double INH_mult = (INH_range-1)/127;
  
  if (argc>1) 
    N = atoi(argv[1]);

  if (argc>2)
    INHARM = atoi(argv[2]);

  if (N>MAXOSC) N = MAXOSC;
  
  for(i=0; i<POLYPHONY; i++)
  {
    o[i] = new OscBank(N, freq);
    o[i]->setRolloff(1.0);
    o[i]->setAmp(1.0/POLYPHONY/N);
    //(N*POLYPHONY));
    sounding[i] = -1;		// -1 = unassigned
  }
  cntOn = 0;

  i = -1;
  data = new DataWindow(3, "Stretched scales/partials", 200, 200);
  char st[20];
  data->SetName(++i, "partials");
  data->SetValue(i, &STRETCH);
  data->SetName(++i, "scale");
  data->SetValue(i, &SCALE);
  data->SetName(++i, "rolloff");
  data->SetValue(i, &ROLLOFF);
  
  data->Update();

  while(1)
  {
    if (controller.nextMessage() > 0) {
      temp2 = controller.getByteThree();
      temp = controller.getByteTwo();	

      if ((controller.getType()==MIDI_NOTEON) && (temp2>=1.0))
      {
	  j = (int) temp;
	  temp = pow(SCALE,double(j-CENTER)/12.0)*__MIDI_To_Pitch[CENTER];
	  //          printf("NoteOn    %4.2fHz %f\n",temp,temp2);
	  int done;
	  done = 0;
	  for(i=0; i<POLYPHONY; i++)
	  {
	    if (sounding[i]==j)
	      done=1;		// already playing this not -- do nothing
	  }
	  
	  if ((!done) && (cntOn<POLYPHONY))  // play this note
	  {
	    cntOn++;
	    for(i=0; sounding[i]>=0; i++) {};  // find the first free osc
	    o[i]->setFreq(temp);
	    sounding[i]=j;
	 
	    //	  data->Update();
	    // printf("NOTEON: osc[%d]=%f, total: %d\n",i, temp, cntOn);
	  }
      }
      else if ((controller.getType()==MIDI_NOTEOFF) ||
	       ((controller.getType()==MIDI_NOTEON) && (temp2<1.0)))
      {
	// if (temp2 < 2.0) temp2 = 64.0;
	if (cntOn>0)
	{
	  j = int(temp);
	  for(i=0; i<POLYPHONY; i++)
	  {
	    if (sounding[i] == j)
	    {
	      sounding[i]=-1;
	      cntOn--;
	    }
	  }
	}
	  //	  printf("NoteOff         0.0 1 %f %f\n",temp,temp2);
      }

      else if (controller.getType() == MIDI_CTL_CHANGE)
      {
	j = (int) temp;
	if (j==0)
	{
	  STRETCH = temp2/127+2;	 
	  for (i=0; i<POLYPHONY; i++)	  
	    o[i]->setStretch(STRETCH);
	}
	else if (j==1)
	{
	  SCALE = temp2/127+2;
	  for (i=0; i<POLYPHONY; i++)
	  {
	    if ((j=sounding[i])>=0)
	    {	      
	      temp = pow(SCALE,double(j-CENTER)/12.0)*__MIDI_To_Pitch[CENTER];
	      o[i]->setFreq(temp);
	    }
	  }
	}
	else if (j==2)
	{
	  ROLLOFF = temp2/127;
	  for (i=0; i<POLYPHONY; i++)	  
	    o[i]->setRolloff(ROLLOFF);
	}
	data->Update();
      }
    }

    out=0;
    for (i=0;i<POLYPHONY;i++)
    {
      if (sounding[i]>=0)
	out += o[i]->tick();
    }
    output.tick(out);
    
  }
}













