/*
  !MidiPlay   A MIDI synthesiser and file player.

  kbd.c - Keyboard driver

  created  15/01/07
  1.0      14/06/14
*/

#include <math.h>
#include "main.h"
#include "kbd.h"
#include "player.h"
#include "filters.h"
#include "midisyn.h"
#include "kbd_dsplay.h"

syn_t syn;

/*
Stack definition
----------------
To create the effect of a fully polphonic keyboard using a limited number of tone generators, a stack of
generator control words is employed. One word for each generator. When a MIDI NOTE ON message is received,
the generator at the stack bottom is used, it is then moved to the stack top and will be the last to be
picked for a different note. see the function poly_action_key. If a generator is already assigned to the
note then it is retriggered and moved to the top.

                        |--- these bits checked for generator on note --|

 31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   | E | R | T | G | M | S   MIDI Channel  |      MIDI Key number      |     MIDI Key Velocity     |     Generator number      |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  |   |   |   |   |   |   |
  |   |   |   |   |   |  Channel block select
  |   |   |   |   |  Mono instrument
  |   |   |   |  Gate
  |   |   |  Trigger
  |   |  Retune
  |  Retrigger
(spare)

 GATE TRIG action
 ---- ---- ------
   1    1  start attack   (key has been pressed)
   1    0  continue attack/decay/sustain
   0    1  start release  (key has been released)
   0    0  continue release

 stack index = 0, stack bottom, oldest note
             = syn.num_gens-1, stack top, newest note
*/

// lowest bit number of fields
#define GEN         0 // generator number, 7 bits
#define VELOCITY    7 // key velocity, 7 bits
#define KEY        14 // midi key number, 7 bits
#define CHANNEL    21 // midi channel number, 4 bits
#define CHAN_EXTN  25 // channel extension
#define MONO       26 // set if the generator is being used for a monophonic instrument
#define GATE       27 // set if the note is down, generator envelope control
#define TRIG       28 // set if the note up/down status has changed, generator envelope control
#define RETUNE     29 // set if the note is only to be retuned
#define RETRIGGER  30 // set if the note is being retriggered
// field masks
#define GEN_MASK   ((1<<7)-1) // 7 bits wide, for up to 128 generators
#define VEL_MASK   ((1<<7)-1) // 7 bits wide, velocity = 0..127
#define KEY_MASK   ((1<<7)-1) // 7 bits wide, for 128 midi keys
#define CHAN_MASK  ((1<<5)-1) // 5 bits wide, for 2 banks of 16 midi channels
#define EXTN_MASK  ((1<<1)-1) // 1 bits wide, to select 1 of 2 channel banks

// soundset.c
extern const ins_t def_instrument[];
#define PURE_SINE 195 // Instrument number for the Pure Sinewave instrument
// Remember to check this with the current default set.
// (note. It will be ONE LESS than the commented number against "Sine 1" in SoundSet.c).

extern const unsigned short int env_scale_table[NUM_NOTES]; // tables.c
extern const unsigned short int sine_table[1792];
// fmull.s
unsigned int fmull48(unsigned int x, unsigned int y);
unsigned int fmull47(unsigned int x, unsigned int y);

// ================== User Instrument Control and Display ======================
/*
 * user instrument data output
 * ---------------------------
 * display_user - user friendly with descriptions
 * dump_user    - in a form that can be fed back in as a command script
 */
static void print_env(int n, char *name, const env_t *e)
{
  myprintf("%s envelope:\n", name);
  myprintf("%d delay         %d\n", n, e->delay);
  myprintf("%d attack step   %d\n", n+1, e->attack_step);
  myprintf("%d attack target %d\n", n+2, e->attack_target);
  myprintf("%d attack hold   %d\n", n+3, e->hold);
  myprintf("%d decay step    %d\n", n+4, e->decay_step);
  myprintf("%d decay target  %d\n", n+5, e->decay_target);
  myprintf("%d sustain step  %d\n", n+6, e->sustain_step);
  myprintf("%d release step  %d\n", n+7, e->release_step);
}
static void print_wave(int n, char *name, const tone_t *t)
{
  myprintf("%s:\n", name);
  myprintf("%d wave      %d (%s)\n", n, t->number, syn.idat.harm[t->number].name);
  myprintf("%d pitch     %d\n", n+1, t->pitch);
  myprintf("%d init pitch %d\n", n+2, t->initial_pitch);
  myprintf("%d glide     %d\n", n+3, t->glide);
  print_env(n+4, "", &t->env);
}
static void print_user(void)
{
  ins_t *u = &syn.user;
  unsigned int s = u->switches;
  myprintf("-- user --\n(%s)\n", u->name);
  print_wave(0, " Tone 1", &u->wave[0]);
  print_wave(12, " Tone 2", &u->wave[1]);
  print_env(24, " Noise", &u->noise_env);
  print_env(32, " Filter", &u->filter_env);
  myprintf(" Misc:\n");
  myprintf("40 switches  %d (%08x)\n", s, s);
  myprintf("40:0 lowpass filter                %s\n", offon[(s >> LOWPASS) & 1]);
  myprintf("40:1 bandpass filter               %s\n", offon[(s >> BANDPASS) & 1]);
  myprintf("40:2 highpass filter               %s\n", offon[(s >> HIGHPASS) & 1]);
  myprintf("40:3 filtered tone generator       %s\n", offon[(s >> FILTERED_TONE) & 1]);
  myprintf("40:4 tone 1 output enable          %s\n", offon[(s >> TONE1_OUT) & 1]);
  myprintf("40:5 tone 2 output enable          %s\n", offon[(s >> TONE2_OUT) & 1]);
  myprintf("40:6 tone 1 and tone 2 ring mod    %s\n", offon[(s >> TONE_RING_MOD) & 1]);
  myprintf("40:7 tone 1 pitch modulation       %s\n", offon[(s >> PITCH1_MOD) & 1]);
  myprintf("40:8 tone 2 pitch modulation       %s\n", offon[(s >> PITCH2_MOD) & 1]);
  myprintf("40:9 tone 1 unsigned amp mod       %s\n", offon[(s >> AMP1_MOD) & 1]);
  myprintf("40:10 tone 1 signed amp mod        %s\n", offon[(s >> AMP1_RING) & 1]);
  myprintf("40:11 tone 2 unsigned amp mod      %s\n", offon[(s >> AMP2_MOD) & 1]);
  myprintf("40:12 tone 2 signed amp mod        %s\n", offon[(s >> AMP2_RING) & 1]);
  myprintf("40:13 noise amp mod                %s\n", offon[(s >> NOISE_MOD) & 1]);
  myprintf("40:14 filter pitch mod             %s\n", offon[(s >> FILTER_MOD) & 1]);
  myprintf("40:15 tone envelope retrig         %s\n", offon[(s >> WAVE_RETRIGGER) & 1]);
  myprintf("40:16 noise envelope retrig        %s\n", offon[(s >> NOISE_RETRIGGER) & 1]);
  myprintf("40:17 filter envelope retrig       %s\n", offon[(s >> FILTER_RETRIGGER) & 1]);
  myprintf("40:18 tone pitch key track         %s\n", offon[(s >> PITCH_TRACK) & 1]);
  myprintf("40:19 filter freq key track        %s\n", offon[(s >> FILTER_TRACK) & 1]);
  myprintf("40:20 tone env time pitch track    %s\n", offon[(s >> WAVE_ENV_TRACK) & 1]);
  myprintf("40:21 noise env time pitch track   %s\n", offon[(s >> NOISE_ENV_TRACK) & 1]);
  myprintf("40:22 filter env time pitch track  %s\n", offon[(s >> FILTER_ENV_TRACK) & 1]);
  myprintf("40:23 inverted filter env          %s\n", offon[(s >> INV_FILTER_ENV) & 1]);
  myprintf("40:24 defined length               %s\n", offon[(s >> DEFINED_LENGTH) & 1]);
  myprintf("40:25 monophonic                   %s\n", offon[(s >> MONO_SCAN) & 1]);
  myprintf("41 filter fc %d\n", u->filter_fc);
  myprintf("42 filter q  %d\n", u->filter_q);
  myprintf("43 retrigger %d\n", u->retrig);
  myprintf("44 mod wave  %d (%s)\n", u->mod_wave, syn.idat.harm[u->mod_wave].name);
  myprintf("45 mod rate  %d\n", u->mod_rate);
  myprintf("46 mod depth %d\n", u->mod_depth);
  myprintf("47 FM depth  %d\n", u->fm_depth);
  myprintf("48 detune    %d\n", u->detune);
  myprintf("49 gain      %d\n", u->gain);
}


/*
 * format_user
 * -----------
 * creates a command list from the User instrument data.
 */
static char *format_env(char *s, int n, const env_t *e)
{
  s += sprintf(s, "USER,%d,%d\n", n,   e->delay);
  s += sprintf(s, "USER,%d,%d\n", n+1, e->attack_step);
  s += sprintf(s, "USER,%d,%d\n", n+2, e->attack_target);
  s += sprintf(s, "USER,%d,%d\n", n+3, e->hold);
  s += sprintf(s, "USER,%d,%d\n", n+4, e->decay_step);
  s += sprintf(s, "USER,%d,%d\n", n+5, e->decay_target);
  s += sprintf(s, "USER,%d,%d\n", n+6, e->sustain_step);
  s += sprintf(s, "USER,%d,%d\n", n+7, e->release_step);
  return s;
}
static char *format_wave(char *s, int n, const tone_t *t)
{
  s += sprintf(s, "USER,%d,%d\n", n,   t->number);
  s += sprintf(s, "USER,%d,%d\n", n+1, t->pitch);
  s += sprintf(s, "USER,%d,%d\n", n+2, t->initial_pitch);
  s += sprintf(s, "USER,%d,%d\n", n+3, t->glide);
  s = format_env(s, n+4, &t->env);
  return s;
}
char *format_user(char *s)
{
  ins_t *u = &syn.user;
  s += sprintf(s, "USER,-1,%s\n", u->name);
  s = format_wave(s, 0,  &u->wave[0]);
  s = format_wave(s, 12, &u->wave[1]);
  s = format_env (s, 24, &u->noise_env);
  s = format_env (s, 32, &u->filter_env);
  s += sprintf(s, "USER,40,%d\n", u->switches);
  s += sprintf(s, "USER,41,%d\n", u->filter_fc);
  s += sprintf(s, "USER,42,%d\n", u->filter_q);
  s += sprintf(s, "USER,43,%d\n", u->retrig);
  s += sprintf(s, "USER,44,%d\n", u->mod_wave);
  s += sprintf(s, "USER,45,%d\n", u->mod_rate);
  s += sprintf(s, "USER,46,%d\n", u->mod_depth);
  s += sprintf(s, "USER,47,%d\n", u->fm_depth);
  s += sprintf(s, "USER,48,%d\n", u->detune);
  s += sprintf(s, "USER,49,%d\n", u->gain);
  return s;
}

static void dump_user(void)
{
  char s[1024];
  format_user(s);
  myprintf("%s", s);
}


/*
 * display_user
 * ------------
 * updates the editor window with the syn.user instrument data
 */
void display_user(void)
{
  int data[7];

  data[0] = syn.kbd_patch.cur;
  if(syn.kbd_patch.list[syn.kbd_patch.cur].hi == PERCUSSION_BANK)
  {
    syn.user = (ins_t){{0}};
    strcpy(syn.user.name, "Drum Kit not editable");
    data[1] = (int)syn.idat.bank[syn.idat.kits[syn.kbd_patch.list[syn.kbd_patch.cur].prg]-1].name;
  }
  else
  {
    if(syn.kbd_patch.list[syn.kbd_patch.cur].hi == PERCUSSION_INST)
      data[1] = (int)syn.idat.bank[syn.idat.kits[syn.kbd_patch.list[syn.kbd_patch.cur].prg]-1].name;
    else
      data[1] = (int)syn.idat.bank[syn.idat.banks[syn.kbd_patch.list[syn.kbd_patch.cur].lo]-1].name;
  }
  data[2] = (int)&syn.user;
  data[3] = syn.kbd_patch.list[syn.kbd_patch.cur].prg;
  data[4] = syn.kbd_patch.list[syn.kbd_patch.cur].hi;
  data[5] = syn.kbd_patch.list[syn.kbd_patch.cur].lo;
  data[6] = (int)syn.idat.name;
  midiPlayer_display(ITEM_USER, data);
}

/*
 * cmd_user
 * --------
 * Displays and controls the syn.user instrument.
 */
int cmd_user(char *msg, int len)
{
  int addr, data;
  ins_t *u = &syn.user;
  unsigned int *s = &u->switches;

  if(len == 0) // descriptive format
    print_user();

  else if(msg[0] == '?') // display help
    myprintf(" Displays and controls the user instrument.\n"
             "        display in a descriptive format\n"
             "  ,<ctrl>,<data>  set control, -3 to 49, to data\n"
             "  ,S,<data>       set switches to hex data\n"
             " The data range depends on the control\n");

  else if(msg[0] == '!') // command format
    dump_user();

  else if(((msg[1] == 'S')||(msg[1] == 's')) &&
           (sscanf(msg+2, ",%x", &data) == 1)) // set switches in hex
  {
    *s = data;
    display_user();
  }

  else if(sscanf(msg, ",%d,%d", &addr, &data) == 2) // set variable
  {
    switch(addr)
    {
      // set parameters to a value
      case  0: u->wave[0].number = data; break;
      case  1: u->wave[0].pitch = data; break;
      case  2: u->wave[0].initial_pitch = data; break;
      case  3: u->wave[0].glide = data; break;
      case  4: u->wave[0].env.delay = data; break;
      case  5: u->wave[0].env.attack_step = data; break;
      case  6: u->wave[0].env.attack_target = data; break;
      case  7: u->wave[0].env.hold = data; break;
      case  8: u->wave[0].env.decay_step = data; break;
      case  9: u->wave[0].env.decay_target = data; break;
      case 10: u->wave[0].env.sustain_step = data; break;
      case 11: u->wave[0].env.release_step = data; break;

      case 12: u->wave[1].number = data; break;
      case 13: u->wave[1].pitch = data; break;
      case 14: u->wave[1].initial_pitch = data; break;
      case 15: u->wave[1].glide = data; break;
      case 16: u->wave[1].env.delay = data; break;
      case 17: u->wave[1].env.attack_step = data; break;
      case 18: u->wave[1].env.attack_target = data; break;
      case 19: u->wave[1].env.hold = data; break;
      case 20: u->wave[1].env.decay_step = data; break;
      case 21: u->wave[1].env.decay_target = data; break;
      case 22: u->wave[1].env.sustain_step = data; break;
      case 23: u->wave[1].env.release_step = data; break;

      case 24: u->noise_env.delay = data; break;
      case 25: u->noise_env.attack_step = data; break;
      case 26: u->noise_env.attack_target = data; break;
      case 27: u->noise_env.hold = data; break;
      case 28: u->noise_env.decay_step = data; break;
      case 29: u->noise_env.decay_target = data; break;
      case 30: u->noise_env.sustain_step = data; break;
      case 31: u->noise_env.release_step = data; break;

      case 32: u->filter_env.delay = data; break;
      case 33: u->filter_env.attack_step = data; break;
      case 34: u->filter_env.attack_target = data; break;
      case 35: u->filter_env.hold = data; break;
      case 36: u->filter_env.decay_step = data; break;
      case 37: u->filter_env.decay_target = data; break;
      case 38: u->filter_env.sustain_step = data; break;
      case 39: u->filter_env.release_step = data; break;

      case 40: *s = data; break;
      case 41: u->filter_fc = data; break;
      case 42: u->filter_q = data; break;
      case 43: u->retrig = data; break;
      case 44: u->mod_wave = data; break;
      case 45: u->mod_rate = data; break;
      case 46: u->mod_depth = data; break;
      case 47: u->fm_depth = data; break;
      case 48: u->detune = data; break;
      case 49: u->gain = data; break;

      // increment / decrement paramters, data = +1 or -1
      case 90: // wave1 wave
        u->wave[0].number += data;
        if(u->wave[0].number < 0) u->wave[0].number = 0;
        else if(u->wave[0].number >= syn.idat.num_waves) u->wave[0].number = syn.idat.num_waves - 1;
        break;

      case 91: // wave2 wave
        u->wave[1].number += data;
        if(u->wave[1].number < 0) u->wave[1].number = 0;
        else if(u->wave[1].number >= syn.idat.num_waves) u->wave[1].number = syn.idat.num_waves - 1;
        break;

      case 92: // mod wave
        u->mod_wave += data;
        if(u->mod_wave < 0) u->mod_wave = 0;
        else if(u->mod_wave >= syn.idat.num_waves) u->mod_wave = syn.idat.num_waves - 1;
        break;

      case 93: u->wave[0].initial_pitch += data; break; // wave1 initial pitch
      case 94: u->wave[1].initial_pitch += data; break; // wave2 initial pitch
      case 95: u->wave[0].pitch += data; break; // wave1 final pitch
      case 96: u->wave[1].pitch += data; break; // wave2 final pitch
      case 97: u->filter_fc += data; break; // filter cutoff frequency

      // set individual switches, data = 0 or 1
      case 100: *s = (*s & ~(1<<LOWPASS)) | (data << LOWPASS); break;
      case 101: *s = (*s & ~(1<<BANDPASS)) | (data << BANDPASS); break;
      case 102: *s = (*s & ~(1<<HIGHPASS)) | (data << HIGHPASS); break;
      case 103: *s = (*s & ~(1<<FILTERED_TONE)) | (data << FILTERED_TONE); break;
      case 104: *s = (*s & ~(1<<TONE1_OUT)) | (data << TONE1_OUT); break;
      case 105: *s = (*s & ~(1<<TONE2_OUT)) | (data << TONE2_OUT); break;
      case 106: *s = (*s & ~(1<<TONE_RING_MOD)) | (data << TONE_RING_MOD); break;
      case 107: *s = (*s & ~(1<<PITCH1_MOD)) | (data << PITCH1_MOD); break;
      case 108: *s = (*s & ~(1<<PITCH2_MOD)) | (data << PITCH2_MOD); break;
      case 109: *s = (*s & ~(1<<AMP1_MOD)) | (data << AMP1_MOD); break;
      case 110: *s = (*s & ~(1<<AMP1_RING)) | (data << AMP1_RING); break;
      case 111: *s = (*s & ~(1<<AMP2_MOD)) | (data << AMP2_MOD); break;
      case 112: *s = (*s & ~(1<<AMP2_RING)) | (data << AMP2_RING); break;
      case 113: *s = (*s & ~(1<<NOISE_MOD)) | (data << NOISE_MOD); break;
      case 114: *s = (*s & ~(1<<FILTER_MOD)) | (data << FILTER_MOD); break;
      case 115: *s = (*s & ~(1<<WAVE_RETRIGGER)) | (data << WAVE_RETRIGGER); break;
      case 116: *s = (*s & ~(1<<NOISE_RETRIGGER)) | (data << NOISE_RETRIGGER); break;
      case 117: *s = (*s & ~(1<<FILTER_RETRIGGER)) | (data << FILTER_RETRIGGER); break;
      case 118: *s = (*s & ~(1<<PITCH_TRACK)) | (data << PITCH_TRACK); break;
      case 119: *s = (*s & ~(1<<FILTER_TRACK)) | (data << FILTER_TRACK); break;
      case 120: *s = (*s & ~(1<<WAVE_ENV_TRACK)) | (data << WAVE_ENV_TRACK); break;
      case 121: *s = (*s & ~(1<<NOISE_ENV_TRACK)) | (data << NOISE_ENV_TRACK); break;
      case 122: *s = (*s & ~(1<<FILTER_ENV_TRACK)) | (data << FILTER_ENV_TRACK); break;
      case 123: *s = (*s & ~(1<<INV_FILTER_ENV)) | (data << INV_FILTER_ENV); break;
      case 124: *s = (*s & ~(1<<DEFINED_LENGTH)) | (data << DEFINED_LENGTH); break;
      case 125: *s = (*s & ~(1<<MONO_SCAN)) | (data << MONO_SCAN); break;
    }
    display_user();
  }
  else if(sscanf(msg+1, "%d", &addr) == 1) // set name
  {
    if(addr == -1) // instrument name
    {
      strncpy(u->name, msg+4, NAME_LEN);
      display_user();
    }
    else if(addr == -2) // bank name
    {
      if(syn.kbd_patch.list[syn.kbd_patch.cur].hi == 0)
        strncpy(syn.idat.bank[syn.idat.banks[syn.kbd_patch.list[syn.kbd_patch.cur].lo]-1].name, msg+4, NAME_LEN);
      else
        strncpy(syn.idat.bank[syn.idat.kits[syn.kbd_patch.list[syn.kbd_patch.cur].prg]-1].name, msg+4, NAME_LEN);
      display_user();
    }
    else if(addr == -3) // sound set name
    {
      strncpy(syn.idat.name, msg+4, 12);
      display_user();
    }
  }

  else
    return -PARAMETER_ERROR;

  return NO_ERROR_;
}
// =============================================================================


/*
 * calculate_tables
 * ----------------
 * Calculates the tone increment and filter cutoff increment tables.
 * that depend on the sample rate. This is necessary if the sample
 * rate is required to be a variable that can be changed after startup.
 */
/*
void calculate_tables(int sample_rate)
{
  #define HI ((1<<16)-1)
  int i;
  double x, y;
  for(i=0; i<NUM_NOTES; i++)
  {
    x = FREQ_A5 * exp((i - A5) * LN2 / 12); // frequency in Hz
    x /= sample_rate;
    y = x * (1<<(32 - GLIDE_SCALE));
    if(y > HI)
      y = HI;
    syn.tone_inc_table[i] = (int)(y + 0.5);
    y = 2 * sin(PI * x) * (1<<SCALE_BITS);
    if(y > HI)
      y = HI;
    syn.filter_table[i] = (int)(y + 0.5);
  }
  syn.sample_rate = sample_rate;
  midiPlayer_display(ITEM_RATE, (int *)&syn.sample_rate);
}
*/

/*
 * calculate_tables
 * ----------------
 * Calculates the tone increment and filter cutoff increment tables.
 * that depend on the sample rate. This is necessary if the sample
 * rate is required to be a variable that can be changed after startup.
 *
 *   x = FREQ_A5 * exp((note - A5) * LN2 / 12)  frequency in Hz
 *   w = x / sample_rate   normalised frequency, 0.5 = nyquist frequency
 *
 *   tone increment = w * 2^17 (fixed point scaling)
 *
 *   filter increment = 2 * sin(PI * w) * 2^15 (fixed point scaling)
 *
 * Code is a fixed point version of above as floating point caused problems
 * for the module version when compiled on the Pi4(RO 5.28) and run on the
 * RPCEmu(RO 3.7). note. I believe this is a known problem with GCCSDK
 */
void calculate_tables(int sample_rate)
{
  int i;
  unsigned int w, hz;
  for(i=0; i<NUM_NOTES; i++)
  {
    hz = FREQ_A5 * iexp(((i - A5) << 10) / 12); // frequency in Hz, Q15

    w = ((hz << 2) + (1<<15)) / sample_rate;
    if(w > ((1<<16)-1))
      w = ((1<<16)-1);
    syn.tone_inc_table[i] = w;

    w = hz / sample_rate; // Q15, 0.5 is the nyquist frequency = 1<<14

    // adjust for the sine_table increased resolution bands for small angles
    if(w < (1<<9))
      ; // do nothing
    else if(w < (1<<10))
      w = 512 + ((w - (1<<9)) >> 1);
    else if(w < (1<<11))
      w = 512+256 + ((w - (1<<10)) >> 2);
    else if(w < (1<<12))
      w = 512+2*256 + ((w - (1<<11)) >> 3);
    else if(w < (1<<13))
      w = 512+3*256 + ((w - (1<<12)) >> 4);
    else if(w < (1<<14))
      w = 512+4*256 + ((w - (1<<13)) >> 5);
    else
      w = 511+5*256;

    syn.filter_table[i] = sine_table[w];
  }

  syn.sample_rate = sample_rate;
  midiPlayer_display(ITEM_RATE, (int *)&syn.sample_rate);
}

/*
 * midiSynth_init
 * --------------
 * First time initialisation.
 */
int midiSynth_init(int sample_rate)
{
  memset(&syn, 0, sizeof(syn_t));
  calculate_tables(sample_rate); // set sample rate
  load_defaults(&syn.idat); // load default sound set

  // load sound set from file if possible, try the local app directory, then try the midisyth choices directory
  int err;
  if((err = load_file(&syn.idat, APP_DIR".SoundSet")) < NO_ERROR_)
    if((err = load_file(&syn.idat, "<MIDISynthChoices$Dir>.SoundSet")) == -PROBLEM_OPENING_FILE)
      err = NO_ERROR_; // if both fail use the default sound set
  myprintf("Sound set: %s\n", syn.idat.name);

  syn.num_gens = 32;        // number of generators, polyphony
  syn.master_volume = 1023; // 0dB
  syn.scale_factor = 100;   // glide time (portamento) scaling to suit the current MIDI spec (smaller = faster, larger = slower)
  syn.user = syn.idat.instrument[syn.idat.bank[syn.idat.banks[0]-1].ins[0]-1]; // user instrument
  syn.percussion_chan = PERCUSSION_CHAN - 1;
  syn.def_perc_chan = PERCUSSION_CHAN - 1;

  syn.m_out = (m_out_t){ KBD_CHAN_OFFSET, 127 }; // default keyboard and midi out, channel and velocity

  midiSynth_reset();
  display_user();
  init_kbd_display();
  return err;
}


/*
 * midiSynth_term
 * --------------
 * Terminates the synthesiser
 */
void midiSynth_term(void)
{
//  if(!&syn)
//    return;

  if(syn.idat.instrument)
    free(syn.idat.instrument);
  if(syn.idat.bank)
    free(syn.idat.bank);
  if(syn.idat.wtbl)
    free(syn.idat.wtbl);
  if(syn.kbd_patch.list)
    free(syn.kbd_patch.list);
  memset(&syn, 0, sizeof(syn_t));
}


/*
 * midiSynth_reset
 * ---------------
 * Initialises the generators, stack, and channels.
 * Will instantly mute all notes
 */
int midiSynth_reset(void)
{
  int i;
  gen_t *g;
  chan_t *c;

  memset(syn.keys, 0, sizeof(syn.keys)); // clear both current and previous key arrays
  syn.seed = 1; // start noise source
  syn.switches &= ~0x7f; // omni on, poly, mono voices reset

  // generators and stack
  for(i=0; i<syn.num_gens; i++)
  {
    g = &syn.gen[i];             // point to the generator structure.
    memset(g, 0, sizeof(gen_t)); // start by clearing everything, then load ...
    g->waveform1 = syn.idat.wtbl[0].wave; //   tone1 waveform pointer,
    g->waveform2 = syn.idat.wtbl[0].wave; //   tone2 waveform pointer,
    g->mod_wave = syn.idat.wtbl[0].wave;  //   modulation waveform pointer
    g->ins = &syn.idat.instrument[syn.idat.bank[syn.idat.banks[0]-1].ins[0]-1]; //   instrument pointer,
    g->filter_q = (1<<VLQ_BITS); //   filter resonance value for maximum damping.
    syn.stack[i] = i << GEN; // initialise stack with generator number.
  }

  // channels
  for(i=0; i < (NUM_BLKS*NUM_MIDI_CHANS); i++)
  {
    c = &syn.chan[i];
    *c = def_chan;

    // update channels window (first bank of 16 channels only)
    if(i < NUM_MIDI_CHANS)
    {
      int data[3];
      data[0] = i;
      data[1] = c->vol_expr;
      midiPlayer_display(ITEM_CHN_VOL, data);
      int prg = c->patch.prg;
      data[1] = prg;
      if(i == (PERCUSSION_CHAN-1))
        data[2] = (int)(syn.idat.bank[syn.idat.kits[0]-1].name); // show GM drum kit
      else
        data[2] = (int)(syn.idat.instrument[syn.idat.bank[syn.idat.banks[0]-1].ins[prg]-1].name); // show GM instruments
    midiPlayer_display(ITEM_CHN_PRG, data);
    }
  }

  clear_kbd_display();

  return NO_ERROR_;
}


/*
 * clear_history
 * -------------
 * Clears the synth generators filter history
 */
void clear_history(void)
{
  int *z;
  for(z = &syn.gen[0].z1;
      z < &syn.gen[syn.num_gens].z1;
      z += sizeof(gen_t)/sizeof(int))
    z[0] = z[1] = 0;
}


/*
 * cmd_reset
 * ---------
 * Complete synthesiser reset
 */
int cmd_reset(char *msg, int len)
{
  if(msg[0] == '?') // display help
    myprintf(" Complete synthesiser reset.\n"
           " ,1 to reset synth\n");

  else if((msg[0] == ',')&&(msg[1] == '1'))
  {
    midiSynth_reset();
    myprintf("Synthesiser reset\n");
  }

  else if((msg[0] == ',')&&((msg[1] == 'Z')||(msg[1] == 'z')))
  {
    clear_history();
    myprintf("Generator history cleared\n");
  }

  else
    return -PARAMETER_ERROR;

  return NO_ERROR_;
}


/*
 * cmd_poly
 * ---------
 * Sets, displays, and stores, the synth polyphony.
 */
int cmd_poly(char *msg, int len)
{
  unsigned int value;

  if(msg[0] == '?')
    myprintf(" Sets and displays the synth polyphony.\n"
           "  ,<value>  Set the polyphony to the value\n"
           "            min 4, max 128\n");

  else if(len == 0) // display status
    myprintf("Polyphony = %d\n", syn.num_gens);

  else if(msg[0] == '!') // report for controller
    myprintf("POLY,%d\n", syn.num_gens);

  else if(sscanf(msg+1, "%d", &value) != 1)
    return -PARAMETER_ERROR;

  else if((value < 4) || (value > NUM_GENS))
    return -OUT_OF_RANGE;

  else
  {
    syn.num_gens = value;
    midiSynth_reset();
  }

  return NO_ERROR_;
}


/*
 * reset_gates
 * -----------
 * Forces all notes on the channel to enter the RELEASE phase
 */
void reset_gates(int channel)
{
  int i;

  syn.chan[channel].switches &= ~(1<<HOLD_PEDAL); // ensure they are not held on

  for(i=0; i<syn.num_gens; i++)
    if(((syn.stack[i] >> CHANNEL) & CHAN_MASK) == channel)
      syn.stack[i] = (syn.stack[i] | (1<<TRIG)) & ~(1<<GATE);
}


/*
 * reset_all_gates
 * ----------------
 * Forces all notes assigned to a channel block with gates set, to enter the RELEASE phase.
 */
void reset_all_gates(int chan_blk)
{
  int i;
  int c = chan_blk * NUM_MIDI_CHANS; // ensure they are not held on

  for(i=c; i<(c + NUM_MIDI_CHANS); i++)
    syn.chan[i].switches &= ~(1<<HOLD_PEDAL);

  for(i=0; i<syn.num_gens; i++)
    if(((syn.stack[i] >> CHAN_EXTN) & EXTN_MASK) == chan_blk) // is generator assigned to the block ?
      syn.stack[i] = (syn.stack[i] | (1<<TRIG)) & ~(1<<GATE);    // if so, enter release phase
}


/*
 * reset_mono
 * ----------
 * Clears MONO flags for all notes
 */
void reset_mono(void)
{
  int i;

  for(i=0; i<syn.num_gens; i++)
    syn.stack[i] &= ~(1<<MONO);
}


/*
 * portamento_on_off
 * ---------------
 * For all generators on the channel with a key set:
 *   for on:
 *     sets MONO and RETUNE flags
 *   for off:
 *     clears MONO and RETUNE flags
 */
void portamento_on_off(int channel, int on)
{
  #define PORTO ((1<<MONO)|(1<<RETUNE))
  int i;

  if(mpg.debug & (1<<DEBUG_GLIDE))
    myprintf("ch %d portamento %s, gen", channel+1, offon[on]);
  for(i=0; i<syn.num_gens; i++)
    if(((syn.stack[i] >> CHANNEL) & CHAN_MASK) == channel)
      if(((syn.stack[i] >> KEY) & KEY_MASK) != 0)
      {
        if(on)
          syn.stack[i] |= PORTO;
        else
          syn.stack[i] &= ~PORTO;

        if(mpg.debug & (1<<DEBUG_GLIDE))
          myprintf(",%d", (syn.stack[i] >> GEN) & GEN_MASK);
      }
  if(mpg.debug & (1<<DEBUG_GLIDE))
    myprintf("\n");
}


/*
 * poly_action_key
 * ---------------
 * Called when a 'key' event occurs from the local keyboard, midi in, or player.
 * This updates the triggers and gates. Any changes are picked up by synth_control()
 * when it next runs.
 * This function is used for polyphonic keyboard modes and also for mono portamento
 * operation per channel whilst still supporting poly notes on that channel.
 */
// bit mask for channel and key
#define POLY_NOTE ((1<<MONO)|(CHAN_MASK<<CHANNEL)|(KEY_MASK<<KEY))
void poly_action_key(int key, int key_pressed, int channel, int velocity)
{
  int i, g, new_note = (channel<<CHANNEL) | (key<<KEY); // (mono flag always zero)

  int portamento =  syn.chan[channel].switches & (1<<PORTAMENTO);

  // is there a generator already assigned to this note ?
  for(i=0; i<syn.num_gens; i++)
    if((syn.stack[i] & POLY_NOTE) == new_note)
      break;
  if(i >= syn.num_gens)
    if(portamento) // for a portamento enabled channel ...
    { // first check for a mono generator on the note
      for(i=0; i<syn.num_gens; i++)
        if((syn.stack[i] & POLY_NOTE) == ((1<<MONO) | new_note))
          break;
      if(i >= syn.num_gens) // if not find the first mono generator to retune
        for(i=0; i<syn.num_gens; i++)
          if((syn.stack[i] & ((1<<MONO)|(CHAN_MASK<<CHANNEL))) == ((1<<MONO) | (channel<<CHANNEL)))
            break;
    }

  if(key_pressed)
  {
    if(i >= syn.num_gens)
    {
      // no assigned generator, all gates set ?
      for(i=0; i<syn.num_gens; i++)
        if(!(syn.stack[i] & (1<<GATE)))
          break;

      if(i >= syn.num_gens)
        i = 0; // all generators in use, use gen at stack bottom (oldest note).

      // assign generator, start attack at new pitch
      g = (syn.stack[i] & (GEN_MASK<<GEN)) | (1<<GATE) | (1<<TRIG) | (velocity<<VELOCITY) | new_note;
      if(portamento)
      {
        g |= (1<<MONO);
        if(mpg.debug & (1<<DEBUG_GLIDE))
          myprintf("ch %d, gen %d, attack %d\n", channel+1, (syn.stack[i] >> GEN) & GEN_MASK, key);
      }
//      else
//        if(mpg.debug & (1<<DEBUG_GLIDE))
//          myprintf("ch %d, gen %d, select %d\n", channel+1, (stack[i] >> GEN) & GEN_MASK, key);
    }
    else // generator assigned, restart attack, pitch unchanged
    {
      // start attack
      g = (syn.stack[i] & (GEN_MASK<<GEN)) | (1<<GATE) | (1<<TRIG) | (velocity<<VELOCITY) | new_note;
      if(portamento)
      {
        g |= (1<<MONO) | (1<<RETUNE);
        if(mpg.debug & (1<<DEBUG_GLIDE))
          myprintf("ch %d, gen %d, retune %d\n", channel+1, (syn.stack[i] >> GEN) & GEN_MASK, key);
      }
      else
        g |= (1<<RETRIGGER);
    }
  }
  else // key released
  {
    if(i >= syn.num_gens)
    {
//      if(mpg.debug & (1<<DEBUG_GLIDE))
//        myprintf("unassigned\n");
      return; // no assigned generator so ignore event
    }

    // start release
    if(!portamento)
      g = (syn.stack[i] & ~((1<<GATE) | (1<<RETUNE) | (1<<RETRIGGER))) | (1<<TRIG);
    else if((syn.stack[i] & ((CHAN_MASK<<CHANNEL)|(KEY_MASK<<KEY))) == ((channel<<CHANNEL) | (key<<KEY)))
    { // if portamento, only start release if the key matches
      g = (syn.stack[i] & ~(1<<GATE)) | (1<<TRIG);
      if(mpg.debug & (1<<DEBUG_GLIDE))
        myprintf("ch %d, gen %d, release %d\n", channel+1, syn.stack[i] & (GEN_MASK<<GEN), key);
    }
    else
    {
//      if(mpg.debug & (1<<DEBUG_GLIDE))
//        myprintf("ch %d, gen %d, in use %d\n", channel+1, syn.stack[i] & (GEN_MASK<<GEN), key);
      return; // do nothing, key had been retuned and is still in use
    }
  }

  // adjust stack, move selected gen to stack top, shift intervening gens down.
  for(; i<(syn.num_gens-1); i++)
    syn.stack[i] = syn.stack[i+1];
  syn.stack[i] = g; // selected gen to stack top

  if(mpg.debug & (1<<DEBUG_STACK))
  {
    myprintf("stack");
    for(i=0; i<syn.num_gens; i++)
      myprintf(",%d", (syn.stack[i] >> GEN) & GEN_MASK);
    myprintf("\n");
  }
}


/*
 * mono_action_key
 * ---------------
 * Called when a 'key' event occurs from the local keyboard or the midi in.
 * This updates the triggers and gates. Any changes are picked up by synth_control()
 * when it next runs.
 * This function is used for monophonic instruments.
 */
// bit mask for channel
#define MONO_NOTE ((1<<MONO)|(CHAN_MASK<<CHANNEL))
static void mono_action_key(int key, int key_pressed, int channel, int velocity)
{
  int i, g,
    // key is not checked because the same mono generator is used, no matter what
    // the key is. (that's the whole idea)
    new_note = (1<<MONO) | (channel<<CHANNEL);

  // is there a generator already assigned to this note ?
  for(i=0; i<syn.num_gens; i++)
    if((syn.stack[i] & MONO_NOTE) == new_note)
      break;

  if(key_pressed)
  {
    if(i >= syn.num_gens)
    {
      // no assigned generator, all gates set ?
      for(i=0; i<syn.num_gens; i++)
        if(!(syn.stack[i] & (1<<GATE)))
          break;

      if(i >= syn.num_gens)
        return; // all generators in use so ignore event

      // assign generator, start attack at new pitch
    }
    // else generator assigned, restart attack, pitch unchanged

    // start attack
    g = (syn.stack[i] & (GEN_MASK<<GEN)) | (1<<GATE) | (1<<TRIG) | (velocity<<VELOCITY) | (key<<KEY) | new_note;
  }
  else // key released
  {
    if(i >= syn.num_gens)
      return; // no assigned generator so ignore event

    // start release
    g = (syn.stack[i] & ~(1<<GATE)) | (1<<TRIG);
  }

  syn.stack[i] = g; // update selected gen
  // no need to adjust stack because we are only using a single fixed voice.
}


/*
 * cmd_note
 * --------
 * Cause a 'note' to be pressed and released.
 */
int cmd_note(char *msg, int len)
{
  int key_pressed, pitch;

  if(msg[0] == '?') // display help
    myprintf(" Cause a 'note' to be pressed and released.\n"
             "  ,<off-on>,<note>\n"
             "         <off-on>: 1 = pressed, 0 = released\n"
             "         <note> = MIDI note number %d to %d\n", C3, C8);

  else if(sscanf(msg+1, "%d,%d", &key_pressed, &pitch) != 2)
    return -PARAMETER_ERROR;

  else if((key_pressed != 0) && (key_pressed != 1))
    return -OUT_OF_RANGE;

  else if((pitch < C3) || (pitch > C8))
    return -OUT_OF_RANGE;

  else
    highlight_key(pitch, key_pressed + 2, syn.m_out.channel);

  return NO_ERROR_;
}


/*
 * key_state
 * ---------
 * Decides what position the key is in from the current NC and NO sense arrays and
 * creates key down or up events accordingly. Times the key down action to provide
 * an indication of key velocity. Handles switch debounce.
 * input: MIDI key number
 * outputs: key state, velocity
 *
 * Sequence for a key going down then up. (matrix type 2, 0 = no connection, 1 = connected)
 * -NC-  -NO-  <- Normaly Closed / Normaly Open
 * W  C  W  C  <- Was(previous) / Cur(current)
 * 1  1  0  0  key up
 * 1  0  0  0  key just left the normaly closed contact, note time t1
 * 0  0  0  0  key midway between key up and key down
 * 0  0  0  1  key just hit the normaly open contact, debounce, start attack phase, velocity = inverse of time from t1 to now
 * 0  0  1  1  key down
 * 0  0  1  0  key just left the normaly open contact
 * 0  0  0  0  key midway between key down and key up
 * 0  1  0  0  key just hit the normaly closed contact, debounce, start release phase
 */

// note: This is a simplified version for use with simple non velocity sensing systems. i.e. computers

// key states
enum
{
  K_UP,       // steady state key up
  K_PRESSED,  // key pressed event
  K_RELEASED, // key released event
  K_DOWN      // steady state key down
};

static int key_state(int key)
{
  unsigned int k = key;

  // create a 2bit number for the key state = [WAS].[CUR]
  int i = (k >> 5) & 3;
  int j = k & 31;
  int state = ( (syn.keys[CUR][i] >> j) & 1) |
              (((syn.keys[WAS][i] >> j) & 1) << 1);

  if(mpg.debug & (1<<DEBUG_KBD))
  {
    if(state == K_PRESSED)
      myprintf("key %d on\n",  key);
    else if(state == K_RELEASED)
      myprintf("key %d off\n", key);
  }

  return state;
}


/*
 * poly_kbd_scan
 * -------------
 * Scans the keyboard for key events, i.e. keys being pressed or released.
 */
static void poly_kbd_scan(int bottom_note, int top_note)
{
  int key;

  for(key=top_note; key>=bottom_note; key--)
  {
    int state = key_state(key);

    if(state == K_PRESSED)
      poly_action_key(key, TRUE, syn.m_out.channel, syn.m_out.velocity);
    else if(state == K_RELEASED)
      poly_action_key(key, FALSE, syn.m_out.channel, 0);
  }
}


/*
 * mono_kbd_scan
 * -------------
 * Scans the keyboard from top to bottom and stops at the first key pressed.
 */
static void mono_kbd_scan(int bottom_note, int top_note)
{
  int key;

  for(key=top_note; key>=bottom_note; key--)
  {
    int state = key_state(key);

    if(state == K_PRESSED)
    {
      mono_action_key(key, TRUE, syn.m_out.channel, syn.m_out.velocity);
      break; // stop at highest note pressed
    }
    else if(state == K_DOWN)
      break; // stop at highest note pressed
    else if(state == K_RELEASED)
    {
      mono_action_key(key, FALSE, syn.m_out.channel, 0);
      memset(syn.keys[WAS], 0, sizeof(syn.keys[WAS])); // clear previous keys to catch any note pressed below
    }
  }
}


/*
 * kbd_task
 * --------
 * Signalled from the key switch scan every KEYSCAN_PERIOD.
 * Selects the different scan modes, e.g. poly/mono/split etc.
 * Scans the keyboard, and issues key on and off commands as required.
 */
void kbd_task(void)
{

  if((syn.user.switches & (1<<MONO_SCAN)) || // user instrument control
     (syn.switches & (1<<POLY_MODE)))    // midi control, 0=poly, 1=mono
    mono_kbd_scan(BOTTOM_KEY, TOP_KEY);
  else
    poly_kbd_scan(BOTTOM_KEY, TOP_KEY);

  memcpy(syn.keys[WAS], syn.keys[CUR], sizeof(syn.keys[WAS])); // WAS = CUR
}



/*
 * envelope
 * --------
 * Action a single Delay-Attack-Hold-Decay-Sustain-Release envelope.
 * init_envelope(), scales the time constants for the pitch if required and starts
 * the envelope sequence.
 * envelope(), executes the sequence and returns the next value.
 * The filters used to produce the envelope are first order IIR, i.e. a simple RC time
 * constant with exponential rise and fall.
 */
#define Q 16 // time constant precision (data precision Q15)
#define NEAR_ENOUGH 100 // an exponential rise or fall never actually reaches its target

// initialise the envelope, scale the time constants and targets
static void init_envelope(envar_t *g, const env_t *i, int tc_scale, int track)
{
  g->scaled = *i; // start with a direct copy of the instrument envelope parameters

  if(i->attack_step == 0)
    g->state = INACTIVE;
  else
  {
    g->state = INIT;

    if(track) // scale the time constants
    {
      int temp;
      temp = (i->attack_step * tc_scale) >> ENV_SCALE_BITS;
      g->scaled.attack_step = (temp > 32767) ? 32767 : temp;
      temp = (i->decay_step * tc_scale) >> ENV_SCALE_BITS;
      g->scaled.decay_step = (temp > 32767) ? 32767 : temp;
      temp = (i->sustain_step * tc_scale) >> ENV_SCALE_BITS;
      g->scaled.sustain_step = (temp > 32767) ? 32767 : temp;
      temp = (i->release_step * tc_scale) >> ENV_SCALE_BITS;
      g->scaled.release_step = (temp > 32767) ? 32767 : temp;
      temp = (i->hold << ENV_SCALE_BITS) / tc_scale;
      g->scaled.hold = (temp > 32767) ? 32767 : temp;
      temp = (i->delay << ENV_SCALE_BITS) / tc_scale;
      g->scaled.delay = (temp > 32767) ? 32767 : temp;
    }
  }
}

// main envelope function, returns the next value.
static int envelope(envar_t *e, unsigned int switches, int retune)
{
  int delta;

  switch(e->state)
  {
    case INIT:
      if(!retune)
        e->enval = 0; // start from zero, causes a click if retuning
      e->state = DELAY;
      e->count = e->scaled.delay;
      // follow through to DELAY

    case DELAY:
      if(e->count--)
        break;
      e->state = ATTACK;
      e->k3 = (1<<Q) - e->scaled.release_step;
      // follow through to ATTACK

    case ATTACK:
      e->enval += (unsigned int)e->scaled.attack_step << Q;
      if((e->enval >> Q) >= e->scaled.attack_target)
      {
        e->enval = e->scaled.attack_target << Q;
        e->state = HOLD;
        e->count = e->scaled.hold;
      }
      break;

    case HOLD:
      if(!e->count--)
      {
        e->state = DECAY;
        e->k1 = e->scaled.decay_step * e->scaled.decay_target;
        e->k2 = (1<<Q) - e->scaled.decay_step;
      }
      break;

    case DECAY:
//      e->enval = ((e->k2 * (Uint64)e->enval) >> Q) + e->k1;
      e->enval = fmull48(e->k2, e->enval) + e->k1;
      delta = (e->enval >> Q) - e->scaled.decay_target;
      if((delta < NEAR_ENOUGH) && (delta > -NEAR_ENOUGH))
      {
        if(switches & (1<< DEFINED_LENGTH))
          e->state = RELEASE; // no sustain for defined length
        else
        {
          e->state = SUSTAIN;
          e->k2 = (1<<Q) - e->scaled.sustain_step;
        }
      }
      break;

    case SUSTAIN:
//      e->enval = (e->k2 * (Uint64)e->enval) >> Q;
      e->enval = fmull48(e->k2, e->enval);
      if((e->enval >> Q) <= NEAR_ENOUGH)
        e->state = INACTIVE;
      break;

    case RELEASE:
//      e->enval = (e->k3 * (Uint64)e->enval) >> Q;
      e->enval = fmull48(e->k3, e->enval);
      if((e->enval >> Q) <= NEAR_ENOUGH)
        e->state = INACTIVE;
      break;

    case INACTIVE:
    default:
      e->enval = 0;
  }

  return e->enval >> Q;
}


/*
 * assign_instrument
 * -----------------
 * Returns the address of an instrument structure if one exists.  Returns NULL if there
 * is no assigned instrument which will cause the key down event that called this
 * function to be ignored.
 */
static const ins_t *assign_instrument(int chan, chan_t *c, unsigned int key)
{
  int prg = c->patch.prg;
  int lo = c->patch.lo;
  int hi = c->patch.hi;
  int i, b = 0; // if all else fails, 0 will select the GM set

  // user instrument (direct from the editor, not via midi)
  if((chan >> 4) == KBD_CHAN)
    return &syn.user;

  // non-pitched or percussion instruments, sound effects etc, mapped to program-key
  if(((chan & 15) == syn.percussion_chan) || (hi == PERCUSSION_BANK))
  {
    if(syn.kit_override > 0)
      b = syn.idat.kits[syn.kit_override]; // force this bank
    else if(syn.switches & (1<<ALL_KITS))
      b = syn.idat.kits[prg]; // normal bank selection

    if(b > 0) // if bank exists
      if((i = syn.idat.bank[b-1].ins[key]) != 0) // and if instrument exists
        return &syn.idat.instrument[i-1]; // select it

    if((i = syn.idat.bank[syn.idat.kits[0]-1].ins[key]) != 0)
      return &syn.idat.instrument[i-1];  // fall back to GM set
  }

  // pitched or melodic instruments, mapped to bank-program
  else
  {
    if(key > B8)
      return &def_instrument[PURE_SINE]; // pure sinewave for very high notes (to reduce aliasing)

    if(syn.bank_override > 0)
      b = syn.idat.banks[syn.bank_override]; // force this bank
    else if(syn.switches & (1<<ALL_BANKS))
      b = syn.idat.banks[lo]; // normal bank selection

    if(b > 0) // if bank exists
      if((i = syn.idat.bank[b-1].ins[prg]) != 0) // and if instrument exists
        return &syn.idat.instrument[i-1]; // select it

    if((i = syn.idat.bank[syn.idat.banks[0]-1].ins[prg]) != 0)
      return &syn.idat.instrument[i-1]; // fall back to GM set
  }

  return NULL; // no instrument
}


/*
 * synth_control
 * -------------
 * Runs at the envelope rate. Initialises generators after key on and off events.
 * Controls the envelopes, volumes, and modulation.  It's main function is to load and adjust
 * parameters for the synthesiser interrupt running at the sample rate.  The parameters such
 * as pitch, volume, etc. should really be adjusted at the sample rate but there is not
 * enough time for that so anything that changes slowly at envelope rates is controlled here
 * at the slower envelope rate.  It is a compromise that most of the time is fine and is only
 * noticable for fast rates of change in pitch or amplitude. This is a task and so is interrupted
 * by the synth interrupt. Again this might cause slight clicks if a control is updated
 * across more than one sample period but it is never noticable.
 */
void synth_control(void)
{
  int n, j, mod, vol, ch;
  unsigned int key, sw, st;
  gen_t *g;
  chan_t *c;
  const ins_t *i, *new;

  for(n=0; n<syn.num_gens; n++)
  {
    st = syn.stack[n];                        // generator stack entry
    key = (st >> KEY) & KEY_MASK;             // pitch, midi key number
    g = &syn.gen[(st >> GEN) & GEN_MASK];     // generator structure
    ch = (st >> CHANNEL) & CHAN_MASK;         // channel number
    c = &syn.chan[ch];                        // channel structure
    i = g->ins;                               // instrument structure
    sw = i->switches;                         // instrument patch switches
    int vel = (st >> VELOCITY) & VEL_MASK;    // raw velocity
    vol = (c->vol_expr * vel * vel) >> 14;    // vol(Q14) = chan_vol_expr(Q14) * vel(Q7)^2

    // key up or down
    if(st & (1<<TRIG))
    {
      st &= ~(1<<TRIG);

      if(st & (1<<GATE)) // key down, trigger note, start ATTACK
      {
        new = assign_instrument(ch, c, key); // assign instrument
        if(new)
        {
          // set fixed parameters for the new assignment
          i = g->ins = new;
          if((i->wave[0].number >= 0) && (i->wave[0].number < syn.idat.num_waves) &&
             (i->wave[1].number >= 0) && (i->wave[1].number < syn.idat.num_waves) &&
             (i->mod_wave >= 0) && (i->mod_wave < syn.idat.num_waves))
          {
            sw = i->switches;
            g->switches =  sw | (1<<ACTIVE);
            if(!(st & ((1<<RETUNE)|(1<<RETRIGGER))))
            { // causes click when retuning or retriggerring
              g->tone1_pointer = 0; // start tone at a zero crossing
              g->tone2_pointer = 0; // start tone at a zero crossing
            }
            g->waveform1 = syn.idat.wtbl[i->wave[0].number].wave; // tone1 waveform
            g->waveform2 = syn.idat.wtbl[i->wave[1].number].wave; // tone2 waveform
            g->filter_q = (1<<VLQ_BITS) - i->filter_q;   // filter resonance
            g->fm_depth = i->fm_depth;              // FM depth
            g->tone1_glide = i->wave[0].glide;
            g->tone2_glide = i->wave[1].glide;
            // modulation oscillator
            g->mod_wave = syn.idat.wtbl[i->mod_wave].wave;
            g->mod_rate = i->mod_rate;
            g->mod_depth = i->mod_depth;
            g->mod_pntr = 1 << (32-2); // start at the peak (quarter cycle from the start for a sinewave)
          }

          if(c->switches & ((1<<PORTAMENTO)|(1<<PORTAM_CTRL))) // portamento enabled channel, or received a portamento control message
            g->tone1_glide = g->tone2_glide = c->glide; // use supplied portamento time

          unsigned int pitch;
          // wave1 pitch base
          j = i->wave[0].pitch;
          if(sw & (1<<PITCH_TRACK))
            j += key;
          LIMIT(0, j, NUM_NOTES-1);
          pitch = (syn.tone_inc_table[j] * ((1 << SCALE_BITS) + i->detune)) >> SCALE_BITS;
          g->new_pitch1 = ((1<<GLIDE_SCALE) - g->tone1_glide) * pitch; // target pitch
          if(i->wave[0].initial_pitch != 0)
          {
            j += i->wave[0].initial_pitch;
            LIMIT(0, j, NUM_NOTES-1);
            pitch = (syn.tone_inc_table[j] * ((1 << SCALE_BITS) + i->detune)) >> SCALE_BITS;
            g->tone1_inc_base = pitch << GLIDE_SCALE; // initial pitch
          }
          if((c->switches & (1<<PORTAM_CTRL)) && (sw & (1<<PITCH_TRACK))) // received a portamento control message
          {
            j = i->wave[0].pitch + c->portamento_ctrl;
            LIMIT(0, j, NUM_NOTES-1);
            pitch = (syn.tone_inc_table[j] * ((1 << SCALE_BITS) + i->detune)) >> SCALE_BITS;
            g->tone1_inc_base = pitch << GLIDE_SCALE; // initial pitch
          }

          // wave2 pitch base
          j = i->wave[1].pitch;
          if(sw & (1<<PITCH_TRACK))
            j += key;
          LIMIT(0, j, NUM_NOTES-1);
          pitch = (syn.tone_inc_table[j] * ((1 << SCALE_BITS) - i->detune)) >> SCALE_BITS;
          g->new_pitch2 = ((1<<GLIDE_SCALE) - g->tone2_glide) * pitch; // target pitch
          if(i->wave[1].initial_pitch != 0)
          {
            j += i->wave[1].initial_pitch;
            LIMIT(0, j, NUM_NOTES-1);
            pitch = (syn.tone_inc_table[j] * ((1 << SCALE_BITS) - i->detune)) >> SCALE_BITS;
            g->tone2_inc_base = pitch << GLIDE_SCALE; // initial pitch
          }
          if((c->switches & (1<<PORTAM_CTRL)) && (sw & (1<<PITCH_TRACK))) // received a portamento control message
          {
            j = i->wave[1].pitch + c->portamento_ctrl;
            LIMIT(0, j, NUM_NOTES-1);
            pitch = (syn.tone_inc_table[j] * ((1 << SCALE_BITS) - i->detune)) >> SCALE_BITS;
            g->tone2_inc_base = pitch << GLIDE_SCALE; // initial pitch
          }

          // filter pitch base
          j = i->filter_fc;
          if(sw & (1<<FILTER_TRACK))
            j += key;
          LIMIT(0, j, NUM_NOTES-1);
          g->new_filter_base = ((1<<GLIDE_SCALE) - g->tone2_glide) * syn.filter_table[j]; // target pitch
          if((c->switches & (1<<PORTAM_CTRL)) && (sw & (1<<FILTER_TRACK))) // received a portamento control message
          {
            j = i->filter_fc + c->portamento_ctrl;
            LIMIT(0, j, NUM_NOTES-1);
            g->filter_base = syn.filter_table[j] << GLIDE_SCALE;
          }

          c->switches &= ~(1<<PORTAM_CTRL); // reset the flag as we must only use portamento_ctrl data once

          // trigger envelopes
          {
            int tc_scale = env_scale_table[key]; // time constant scale, by key
            init_envelope(&g->tone1_env, &i->wave[0].env, tc_scale, (sw & (1<<WAVE_ENV_TRACK)));
            init_envelope(&g->tone2_env, &i->wave[1].env, tc_scale, (sw & (1<<WAVE_ENV_TRACK)));
            init_envelope(&g->noise_env, &i->noise_env,   tc_scale, (sw & (1<<NOISE_ENV_TRACK)));
            init_envelope(&g->filter_env, &i->filter_env, tc_scale, (sw & (1<<FILTER_ENV_TRACK)));
          }

          if(!(st & (1<<RETUNE)))
          {
            if(sw & (1<<DEFINED_LENGTH))
            {
              g->retrig = 0; // no retrigger for defined length
              st &= ~(1<<GATE); // note off not required, but will do no harm
            }
            else
              g->retrig = i->retrig; // retrigger time
          }
        }
      }

      else // key up, start RELEASE
      {
        if(!(sw & (1<<DEFINED_LENGTH))) // release is handled within envelope for defined length
          if(!(c->switches & (1 << HOLD_PEDAL))) // don't enter release state if held
          {
            g->tone1_env.state = RELEASE;
            g->tone2_env.state = RELEASE;
            g->noise_env.state = RELEASE;
            g->filter_env.state = RELEASE;
          }
        g->retrig = 0; // stop retrigger
      }

      syn.stack[n] = st;
    }

    else // key held up or held down
    {
      if(!(sw & (1<<DEFINED_LENGTH)))
        if(!(st & (1<<GATE)) && !(c->switches & (1 << HOLD_PEDAL))) // delayed release when hold is removed
        {
          g->tone1_env.state = RELEASE;
          g->tone2_env.state = RELEASE;
          g->noise_env.state = RELEASE;
          g->filter_env.state = RELEASE;
        }

/*
      // check if hold pedal has been pressed
      if(c->switches_delta & (1<<HOLD_PEDAL)) // there has been a change
      {
        c->switches_delta &= ~(1<<HOLD_PEDAL);
        printf("hold %d %s (key %s)\n", ch, offon[(c->switches >> HOLD_PEDAL) & 1], offon[(st >> GATE) & 1]);
      }
*/
      // envelope retrigger
      if(g->retrig)
        if(!--g->retrig)
        {
          g->retrig = i->retrig;
          if(sw & (1<<WAVE_RETRIGGER))
          {
            g->tone1_env.state = INIT;
            g->tone2_env.state = INIT;
          }
          if(sw & (1<<NOISE_RETRIGGER))
            g->noise_env.state = INIT;
          if(sw & (1<<FILTER_RETRIGGER))
            g->filter_env.state = INIT;
        }
    } // end of all key actions

    if(g->switches & (1<<ACTIVE))
    {
      // modulation oscillator
      j = g->mod_wave[g->mod_pntr >> FIX];
      mod = (j * g->mod_depth) >> SCALE_BITS;
      g->mod_pntr += g->mod_rate << 16;

      // filter cutoff
//      g->filter_base = ((g->tone2_glide * (Uint64)g->filter_base) >> GLIDE_SCALE) + g->new_filter_base; // glide
      g->filter_base = fmull47(g->tone2_glide, g->filter_base) + g->new_filter_base; // glide
      j = envelope(&g->filter_env, g->switches, (st & ((1<<RETUNE)|(1<<RETRIGGER))));
      if(sw & (1<<INV_FILTER_ENV))
        j = -j;
      j += g->filter_base >> GLIDE_SCALE;
      if(j < 0)
        j = 0;
      if(sw & (1<<FILTER_MOD))
        j += (j * mod) >> SCALE_BITS;    // cutoff modulation
      j >>= (SCALE_BITS-VLQ_BITS);
      // limit fc to stability limit, filter_fc < (2 - filter_q)
      int limit = (2<<VLQ_BITS) - g->filter_q;
      if(j >= limit)
        j = limit - 1;
      g->filter_fc = j;

      // noise amplitude
      j = envelope(&g->noise_env, g->switches, (st & ((1<<RETUNE)|(1<<RETRIGGER))));
      if(sw & (1<<NOISE_MOD))
        j += (j * mod) >> SCALE_BITS;    // amp modulation
      g->noise_volume = (j * vol) >> MIDI_PARAM_SCALE; // channel volume and velocity

      // wave1 amplitude
      j = envelope(&g->tone1_env, g->switches, (st & ((1<<RETUNE)|(1<<RETRIGGER))));
      if(sw & (1<<AMP1_MOD))
        j += (j * mod) >> SCALE_BITS;    // amp modulation (unsigned or DSB full carrier)
      if(sw & (1<<AMP1_RING))
        j = (j * mod) >> SCALE_BITS;     // amp modulation (signed or DSB suppressed carrier)
      g->tone1_volume = j;               // envelope and modulation (affects FM mod)
      g->tone1_vol_vel = vol;            // channel volume and velocity (doesn't affect FM mod)

      // wave1 pitch
//      g->tone1_inc_base = ((g->tone1_glide * (Uint64)g->tone1_inc_base) >> GLIDE_SCALE) + g->new_pitch1; // glide
      g->tone1_inc_base = fmull47(g->tone1_glide, g->tone1_inc_base) + g->new_pitch1; // glide
      j = g->tone1_inc_base;
      if(sw & (1<<PITCH1_MOD))
        j += (j >> 16) * mod;            // pitch modulation
      j = (j >> 13) * c->bender;         // channel pitch wheel
      g->tone1_inc = j;

      // wave2 amplitude
      j = envelope(&g->tone2_env, g->switches, (st & ((1<<RETUNE)|(1<<RETRIGGER))));
      if(sw & (1<<AMP2_MOD))
        j += (j * mod) >> SCALE_BITS;    // amp modulation (unsigned or DSB full carrier)
      if(sw & (1<<AMP2_RING))
        j = (j * mod) >> SCALE_BITS;     // amp modulation (signed or DSB suppressed carrier)
      g->tone2_volume = (j * vol) >> MIDI_PARAM_SCALE; // channel volume and velocity

      // wave2 pitch
//      g->tone2_inc_base = ((g->tone2_glide * (Uint64)g->tone2_inc_base) >> GLIDE_SCALE) + g->new_pitch2; // glide
      g->tone2_inc_base = fmull47(g->tone2_glide, g->tone2_inc_base) + g->new_pitch2; // glide
      j = g->tone2_inc_base;
      if(sw & (1<<PITCH2_MOD))
        j += (j >> 16) * mod;            // pitch modulation
      j = (j >> 13) * c->bender;         // channel pitch wheel
      g->tone2_inc = j;

      // pan / balance / gain
      g->left_vol  = (c->left_vol * i->gain) >> 10;  // instrument gain: 0dB = 1024 (Q10)
      g->right_vol = (c->right_vol * i->gain) >> 10;

      // Check if generator still active. If the master_env is not set, all volume envelopes must be INACTIVE to
      // clear the ACTIVE flag. If mester_env is set then that envelope alone clears the ACTIVE flag.
      int active = TRUE;
      switch(i->master_env)
      {
        default: // unset
          if((g->tone1_env.state == INACTIVE) &&
             (g->tone2_env.state == INACTIVE) &&
             (g->noise_env.state == INACTIVE))
            active = FALSE;
          break;

        case 1: // tone1 is master
          if(g->tone1_env.state == INACTIVE)
            active = FALSE;
          break;

        case 2: // tone2 is master
          if(g->tone2_env.state == INACTIVE)
            active = FALSE;
          break;

        case 3: // filter is master
          if(g->filter_env.state == INACTIVE)
            active = FALSE;
          break;

        case 4: // noise is master
          if(g->noise_env.state == INACTIVE)
            active = FALSE;
          break;
      }
      if(!active)
      {
        g->switches &= ~(1<<ACTIVE);
        st &= ~(1<<GATE);
        g->tone1_env.state = INACTIVE;
        g->tone1_env.enval = 0;
        g->tone2_env.state = INACTIVE;
        g->tone2_env.enval = 0;
        g->filter_env.state = INACTIVE;
        g->filter_env.enval = 0;
        g->noise_env.state = INACTIVE;
        g->noise_env.enval = 0;
      }
    } // end of generator active
  } // end of generator loop
}


/*
 * midiPlayer_sample
 * -----------------
 * This should be called for every sample. i.e. at the sample rate in real time
 * Returns a pointer to the stereo sample. 2 signed shorts packed into an unsigned 32 bit int.
 *
 *   The following notes also apply to this Risc OS port
 * In this Windows port, this routine is called when an audio buffer needs filling, so it is
 * called in a tight loop to quickly provide the required number of samples. This works fine
 * for all internally generated messages as the timers are all within this function. The keyboard
 * is also ok as it is not intended to be as responsive as a real keyboard. However when an
 * external MIDI out device sends messages in real time, they will not be actioned immediately
 * and some get lost if sent too rapidly. This means that operation from a another MIDI player
 * i.e. Winamp etc. is not good. For the same reason, sending MIDI from this player to another
 * synth will not work well either.
 *
 * In the embedded/standalone version of this synth, all timing is driven by interrupt and is exact.
 * The sample interrupt drives the synth generators and audio output so a single sample is produced
 * and sent directly to the hardware. This gives almost zero latency which can never happen with Windows.
 */
unsigned int *midiPlayer_sample(void)
{
  #define KBD_RATE 100 // Hz (10ms period)
  static unsigned int sample;
//  if(&syn)
  {
    int spkr[2] = {0,0}; // left and right

    synth_generators(&syn, spkr); // main synth generators, sample rate code

    // 500Hz timer, synthesiser envelope rate code
    if((syn.timer_syn += ENV_RATE) >= syn.sample_rate)
    {
      syn.timer_syn -= syn.sample_rate;
      synth_control();
    }

    // 10ms timer, key array scan
    if((syn.timer_kbd += KBD_RATE) >= syn.sample_rate)
    {
      syn.timer_kbd -= syn.sample_rate;
      kbd_task();
    }

    // master volume control
    spkr[0] = (syn.master_volume * spkr[0]) >> VLQ_BITS;
    spkr[1] = (syn.master_volume * spkr[1]) >> VLQ_BITS;

    LIMIT(-0x8000, spkr[0], 0x7fff); // limit to signed 16 bit
    LIMIT(-0x8000, spkr[1], 0x7fff);

    effects(spkr); // filters

    int left = spkr[0], right = spkr[1];

    // stereo / mono
    if(syn.switches & (1<<MONO_AUDIO))
      left = right = (left + right) / 2;

    // left / right swap
    else if(syn.switches & (1<<L_R_SWAP))
    {
      left ^= right;
      right ^= left;
      left ^= right;
    }

    // balance
    left = (left * syn.lpan) >> 14; // pan/balance table is Q14
    right = (right * syn.rpan) >> 14; // pan/balance table is Q14

    // these contain their own timing
    midi_file_player();
    key_highlight_timer();

    sample = (left << 16) | (right & 0xffff);
  }
  return &sample;
}



