/*
 * This software is released under GPL. If you don't know what that is
 * immediately point your webbrowser to  http://www.gnu.org and read
 * all about it.
 *
 * The short version: You can modify the sources for your own purposes
 * but you must include the new source if you distribute a derived  work.
 *
 * (C) 2002, 2003, 2004 Jens M Andreasen <ja@linux.nu>
 */ 

#ifndef MMX4_H
#define MMX4_H
//#include "mmx.h"

//#define OMNIMODE 




//#ifdef OMNIMODE
// Tim suggested a smaller footprint
//#define MIDICHANNELS 1 
//#define CHANNELMASK 0x0   
//#else
// Elsewise we are multitimbral
//#define MIDICHANNELS 16
//#define CHANNELMASK 0x0F
//#endif

//#define SAMPLES 64 // number of samples to produce before polling midi
//#define ENVLOOP 4  // number of envelope updates during sample production

//#define OPLOOP SAMPLES/ENVLOOP
//#define OUTBUF SAMPLES * 2 // stereo == 2





typedef struct 
{
  // Each envelope has a current value ..
  mmx_t state02;  // d 
  mmx_t state13;  // d
 
  // .. and a precalculated +/- value to be added .. 
  mmx_t delta02; // d
  mmx_t delta13; // d
  // .. for exactly x samples ..
  int time[4][8];     // [op][step]
  int time_count[4];  // [op]

  // .. before being replaced by the next precalculated delta value
  int delta_value[4][9]; // [op][step]
  int step[4]; // op

  int sustain[4]; // middle level in the sustain loop
  int release[4]; // the release deltas cannot be precalculated

  int running; // bit 0 - 3 set while env still running

}mmx4env_t;

// The state of a single running voice
typedef struct _mmx4
{
  // mmx_t samples[SAMPLES];

  // intonation parameters
  int intonation[4][2]; // w (op) [amount | decay]

  // state of oscillators
  mmx_t state02;  // d (op 0, op 2) 
  mmx_t state13;  // d (op 1, op3)
  // frequency of oscillators
  mmx_t delta02;  // d 
  mmx_t delta13;  // d


  // Each oscillator is phase- and amplitude modulated
  // by every other oscillators previous output

  // Modulaton arguments are skewed diagonally as in:

  // x[3](op2,op1,op0,op3)
  // x[2](op1,op0,op3,op2)
  // x[1](op0,op3,op2,op1)
  // x[0](op3,op2,op1,op0)

  mmx_t pm[4]; // w
  mmx_t am[4]; // w

  // pseudo sin is averaged from two bumpy approximations
  // running 60 degrees apart at the same frequency. 
  // Optionally one part can be octave doubled and/or
  // modified to a second set of waweshapes.
  mmx_t od; // w (op)
  mmx_t complexwawe;
  // Stereo mix
  mmx_t mixL;     // w
  mmx_t mixR;     // w

  mmx_t wheel;    // w 

  // Final utput of oscillator 0,1,2,3
  mmx_t out;      // w


  // Next voice in an asignment que (running, hold, released, silent)
  struct _mmx4 *next; 
  struct _mmx4 *previous; 
  
  // envelopes
  mmx4env_t env;
  

  unsigned char channel; // channel number
  unsigned char key;
}mmx4_t;
// The patch sets up the initial state according to
// key and velocity etc
#define WAWEBUTTON 1
#define WHEELBUTTON 2

typedef struct 
{
  int  pm[4][4]; // [destination] [source]
  int  am[4][4];

  int mix[4][2]; // [op] [left | right]
  
  int  env_level[4][8]; // [op] [stage]
  int  env_time[4][8];

  int harmonic[4];

  short intonation[4][2]; // [op] [amount | decay]

  int detune[4];

  short velocityfollow[4];

  unsigned char od[4]; // octave doubling
  unsigned char button[4];

  // key bias
  int breakpoint[4];   // [op]
  int keybias[4][2];   // [op] [hi | lo value]
  // env keyfollow
  int keyfollow[4][2]; // [op] [attack | sustain-loop]
  // key velocity
  int velocity[4]; // [op]

  int phase[4][2]; // [op] [offset | velocityfollow]
  char name[32];
}mmx4patch_t;

typedef struct {
  mmx_t mmxtmp[2];
  mmx_t wheel;
  mmx4_t *voices;
  mmx4_t *que[4]; // assigned, held, released, silent
  mmx4_t *last[4]; 
  mmx4_t *keyboard[MIDICHANNELS][128];
  int keyTable[128];
  // some controllers
  char holdpedal[MIDICHANNELS];
  short pitchbend[MIDICHANNELS];
  char modulation[MIDICHANNELS];
  char mod_now[MIDICHANNELS];


  mmx4patch_t mmx4patch[128]; // preset patches
  mmx4patch_t mmx4tmpPatch[16]; // actual editable and sounding patch
  int maxpoly;
  char mmx4patchNo[16]; // chosen preset number 

#ifdef OMNIMODE

  int touched[MIDICHANNELS];  
  float fsamples[MIDICHANNELS][2][32]; //[midi channel][left|right][index]
  int delivered; // number of prerendered samples already delivered

#endif

}Mx4state;

extern  Mx4state* mmx4new(int maxpolyphony); 
 // middle A == 440.0
extern  void mmx4reset(Mx4state* mx4,double tuningfork,int samplerate);
extern  void mmx4setpatch(Mx4state* mx4,int channel,int patchnumber);
extern  void mmx4attack(Mx4state* mx4,int channel,int key,int velocity);
extern  void mmx4release(Mx4state* mx4,int channel,int key,int velocity);
extern  void mmx4pitchbend(Mx4state* mx4,int channel,int data1,int data2);
extern  void mmx4control(Mx4state* mx4,int channel,int control,int data);


#ifdef OMNIMODE
// syntax checking only ... 
// use with debugger at your own risk ..
extern void omni(Mx4state* mx4, int request,float* port_left, float* port_right)
#endif

extern  void mmx4play(Mx4state* mx4,short * stereo_out);

#endif






