/*
  MidiSynth, MIDI synthesiser, a repacement for the Acorn MIDI module

  midi.c - MIDI functions.

  created  16/11/085
  1.0      14/06/14
*/

#include "main.h"
#include "kbd.h"

//#define PROGRAM_UPDATES_BANKS // bank messages take effect on the next program change

// syn.m_in.count data counter values when accumulating 14bit values
#define LSB 2
#define MSB 1


// default midi channel parameters (single channel)
const chan_t def_chan =
{
   {0,0,0},   // patch: bank hi, bank lo, program
   {0,0,0},   // patch (temp): bank hi, bank lo, program
         0,   // channel pressure
    0x2000,   // pitch wheel (mid)
// controllers
         0,   // mod wheel
    0x2000,   // breath
    0x2000,   // foot pedal
         0,   // portamento time (min)
    0x3fff,   // volume (max)
    0x2000,   // balance (mid)
    0x2000,   // pan position (mid)
    0x3fff,   // expression (max)
      0x40,   // vibrato_rate,  (mid no change)
      0x40,   // vibrato_depth, (mid no change)
      0x40,   // vibrato_delay, (mid no change)
         0,   // portamento ctrl (min)
         0,   // switches (all off)
         0,   // switches delta
// parameters
      NULL,   // *param ptr        pointer to current parameter (unassigned)
    0x3fff,   // reg param         parameter number (unassigned)
    0x0100,   // pitch bend range  parameter[0], = 02/00 to give +-2 semitones
    0x0040,   // mod depth range   parameter[5], = 00/40 to give +-50 cents (01/00 = +-1 semitone)
// derived controls
    0x2000,   // bender            scaled pitch wheel (mid)
         0,   // mod               scaled pitch modulation (min)
         0,   // glide             scaled portamento time (min)
    0x3fff,   // volume * expression, square law (max)
    0x2D41,   // left volume  = pan * balance in mid position
    0x2D41    // right volume = pan * balance in mid position
};


const char note[][4] = {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};

// pan/balance law = sin(0..PI/2)*(1<<Q), Q=14, only uses MSB of data
const unsigned short int pantab[MIDI_DATA_RANGE] =
{
      0,  202,  405,  607,  810, 1012, 1214, 1416, 1618, 1820, 2021, 2222, 2422, 2623, 2822, 3022,
   3221, 3419, 3617, 3814, 4011, 4207, 4403, 4598, 4792, 4985, 5178, 5370, 5561, 5751, 5940, 6129,
   6316, 6503, 6688, 6873, 7056, 7238, 7420, 7600, 7779, 7956, 8133, 8308, 8482, 8655, 8826, 8996,
   9165, 9332, 9498, 9663, 9825, 9987,10147,10305,10462,10617,10770,10922,11073,11221,11368,11513,
  11656,11798,11937,12075,12211,12345,12478,12608,12737,12863,12988,13110,13231,13349,13466,13580,
  13692,13802,13911,14017,14120,14222,14322,14419,14514,14607,14698,14786,14872,14956,15038,15117,
  15194,15268,15341,15411,15478,15544,15606,15667,15725,15781,15834,15885,15933,15979,16023,16064,
  16102,16138,16172,16203,16232,16258,16282,16303,16322,16338,16352,16363,16372,16378,16382,16383
};

// portamento rate table in cents/second, only uses MSB of data, from MIDI level 2 spec.
// glide_tc = (1<<Q) - (((1<<Q) * port_rate_table[CC05]) / (scale_factor * 1000)), Q=15
//          = 32768 - ((32768 * port_rate_table[CC05]) / (scale_factor * 1000))
//          = 32768 - ((32 * port_rate_table[CC05]) / scale_factor    (approximation)
static const unsigned int port_rate_table[MIDI_DATA_RANGE] =
{
  552942,267335,157703,104660, 76089, 58063, 46065, 37817,
   31664, 27518, 23892, 21167, 19117, 17182, 15929, 14791,
   13878, 13222, 12600, 12045, 11599, 11152, 10547, 10192,
    9665,  9278,  8928,  8558,  8130,  7788,  7419,  7140,
    6878,  6493,  6267,  5969,  5701,  5497,  5300,  5033,
    4831,  4578,  4397,  4232,  4053,  3857,  3723,  3514,
    3384,  3260,  3109,  2970,  2867,  2701,  2607,  2512,
    2384,  2290,  2206,  2078,  2006,  1935,  1830,  1764,
    1665,  1601,  1545,  1491,  1405,  1359,  1280,  1235,
    1190,  1129,  1081,  1045,   985,   951,   909,   866,
     834,   803,   758,   732,   706,   666,   644,   617,
     584,   564,   544,   512,   495,   466,   450,   434,
     410,   394,   380,   359,   347,   334,   315,   303,
     292,   277,   267,   257,   242,   234,   224,   213,
     203,   194,   184,   170,   158,   144,   129,   115,
     101,    86,    72,    58,    45,    35,    25,    16
};


/*
 * iexp
 * ----
 * provides a 2 to the power x function
 * input Q10, output Q15
 */
extern const unsigned short int exp_table[1<<EXP_BITS]; // 0..1 in (Q10, 0..0x400), 1..2 out (Q15, 0x8000..0x10000)
int iexp(int x)
{
  int e = exp_table[x & ((1<<EXP_BITS)-1)];
  int i = x >> EXP_BITS;

  if(x >= 0)
    return e << i;
  else
    return e >> -i;
}


/*
 * calc_vol_expr
 * -------------
 * Calculates the actual channel volume from the provided
 * volume and expression values.
 * channel volume = (volume * expression) squared
 */
static void calc_vol_expr(chan_t *c)
{
  int vol = (c->volume * c->expression) >> MIDI_PARAM_SCALE;
  c->vol_expr = (vol * vol) >> MIDI_PARAM_SCALE;
}


/*
 * calc_pan_bal
 * ------------
 * Calculates the actual left and right channel volume from the provided
 * pan position and balance values.
 * Both pan and balance are midi 14 bit parameters having a range of 0 to 0x3fff.
 */
static void calc_pan_bal(chan_t *c)
{
  // first calculate left and right volumes due to pan positions
  int pan = c->pan_posn >> 7;
  int left = pantab[0x7f - pan];
  int right = pantab[pan];
  // then modify the volumes due to balance
  int bal = c->balance >> 7;
  c->left_vol = (left * pantab[0x7f - bal]) >> MIDI_PARAM_SCALE;
  c->right_vol = (right * pantab[bal]) >> MIDI_PARAM_SCALE;
}


/*
 * calc_pitch_bend
 * ---------------
 * Calculates the scaled pitch bend.
 * iexp i/p Q10 o/p Q15, pitch_wheel Q13, range cents, /8 = Q13 to Q10. >>2 = Q15 to Q13, /1200 = octave in cents
 */
static void calc_pitch_bend(chan_t *c)
{
  int range = 100 * (c->pitch_bend_range >> 7) + (c->pitch_bend_range & 0x7f); // in cents
  c->bender = iexp(((c->pitch_wheel - 0x2000) * range) / (8*1200)) >> 2; // scale and convert to linear
}


/*
 * calc_mod_wheel
 * --------------
 * mod_depth_range is in units of 100/128 cents
 * Other pitch mod parameters are vibrato_rate,
 */
static void calc_mod_wheel(chan_t *c)
{
  int range = (100 * c->mod_depth_range) >> 7; // in cents
  c->mod = iexp(((c->mod_wheel - 0x2000) * range) / (8*1200)) >> 2; // scale and convert to linear (incorrect)
}


/*
 * calc_glide
 * ----------
 * glide = 1 - (rate / 1000)   scaled to Q15 and by scale_factor
 * The 1000 is for sec to ms conversion. Formulae has been simplified in the code.
 */
void calc_glide(chan_t *c)
{
  int prt = port_rate_table[c->portamento_time >> 7]; // only use MSB
  int div = syn.scale_factor;

  c->glide = (prt >= (div * 1024)) ? 0 : 32768 - ((32 * prt) / div);
}


/*
 * select_rpn
 * ----------
 * Selects the registered parameter to control.
 */
static void select_rpn(chan_t *c)
{
  switch(c->param_idx)
  {
    case 0: c->param_ptr = &c->pitch_bend_range; break;
    case 5: c->param_ptr = &c->mod_depth_range; break;

    default: c->param_ptr = NULL;
  }
}


/*
 * reset_controllers
 * -----------------
 * Sets the controllers of a single channel to their default values.
 */
static void reset_controllers(chan_t *c)
{
  c->mod_wheel = def_chan.mod_wheel;
  c->expression = def_chan.expression;
  c->switches &= ~((1<<HOLD_PEDAL)|(1<<PORTAMENTO)|(1<<SUSTENUTO_PEDAL)|(1<<SOFT_PEDAL));
  c->switches_delta = 0;
  c->param_ptr = NULL;
  c->param_idx = 0x3fff;
  c->pitch_wheel = def_chan.pitch_wheel;
  c->pressure = def_chan.pressure;
}


/*
 * interpret_sys_ex
 * ----------------
 * Interprets the system exclusive message buffer. The first character of the sysex
 * message (0xf0) is not in the buffer. Sysex device ID is ignored.
 */
static void interpret_sys_ex(unsigned char *msg)
{
  int n;

//  if(msg[1] != 0x7f) return; // device ID (ignore)

  switch(msg[0]) // ID
  {
    case REAL_TIME_ID:
      switch(msg[2]) // Sub-ID1
      {
        case 4: // device control
          switch(msg[3]) // Sub-ID2
          {
            case 1: // master volume
              syn.master_volume = (msg[4] | (msg[5] << 7)) >> 4; // scaled for 10 bit
//              if(mod.debug & (1<<DBG_MSG))
//                if(mod.log)fprintf(mod.log, "master volume = %d\n", syn.master_volume);
              break;

            case 2: // master balance
              syn.master_balance = (msg[4] | (msg[5] << 7)) >> 4; // scaled for 10 bit
//              if(mod.debug & (1<<DBG_MSG))
//                if(mod.log)fprintf(mod.log, "master balance = %d\n", syn.master_balance);
              break;

            // master tuning as a single number is a signed binary number in semitones with 13 fractional bits
            // range is +-64 semitones
            // note. syn.master_tuning is currently not used, the coarse and fine parts of it are used separately.

            case 3: // master fine tuning, +- 1 semitone, the fractional part
              n = (msg[4] | (msg[5] << 7)) - 0x2000;
              syn.master_fine = n;
              syn.master_tuning = (syn.master_coarse << 13) + n;
//              if(mod.debug & (1<<DBG_MSG))
//                if(mod.log)fprintf(mod.log, "master fine tuning = %d\n", syn.master_fine);
              break;

            case 4: // master coarse tuning, lsb unused, 100 cents (1 semitone) per step, the integer part
              n = msg[5] - 0x40;
              syn.master_coarse = n;
              syn.master_tuning = syn.master_fine + (n << 13);
//              if(mod.debug & (1<<DBG_MSG))
//                if(mod.log)fprintf(mod.log, "master coarse tuning = %d\n", syn.master_coarse);
              break;

          }
          break;
      }
      break;

    case NON_REAL_TIME_ID:
      switch(msg[2]) // Sub-ID1
      {
        case 9: // GM control
          switch(msg[3]) // Sub-ID2
          {
            case 1: // GM1 system on
              midiSynth_reset();
//              if(mod.debug & (1<<DBG_MSG))
//                if(mod.log)fprintf(mod.log, "GM Reset\n");
              break;

//            case 2: // GM system off
//            case 3: // GM2 system on
          }
          break;
      }
      break;
  }
}


/*
 * load_14bit_value
 * ----------------
 * Midi data is only 7 bits per byte. This accumulates 2 bytes into a 14 bit value.
 * Data is sent lsb first, msb second, as determined by the data count.  It doesn't
 * actually matter which order the data comes, and sometimes only the MSB is sent.
 */
static void load_14bit_value(unsigned short *param, int data, int byte)
{
  if(!param) // unassigned
    return;

  if(byte == LSB)
    *param = (*param & ~0x7f) | data;
  else // msb
    *param = (*param & ~(0x7f << 7)) | (data << 7);
}


/*
 * midiSynth_midi_in
 * -----------------
 * This is the main synth remote control input, it interprets data from midi input ports.
 * Most changes to synth parameters will be picked up automatically by the regular synth
 * task and audio output interrupt.
 */
void midiSynth_midi_in(int data)
{
  int real_time, on;
  chan_t *c;

  if (data & 0x80)
  {
    // status byte

    real_time = 0;

    if (data < 0xf0)
    {
      // voice messages
      syn.m_in.type    = data & 0xf0;
      syn.m_in.channel = data & 0x0f;

      // set message lengths
      switch (syn.m_in.type)
      {
        case NOTE_OFF:
        case NOTE_ON:
        case KEY_PRESSURE:
        case CONTROL:
        case PITCH_WHEEL:
          syn.m_in.count = 2;
          break;

        case PROGRAM:
        case CHAN_PRESSURE:
          syn.m_in.count = 1;
          break;
      }
    }
    else
    {
      // system messages
      switch (data)
      {
        // system common commands

        case SYSTEM_EXCLUSIVE: // variable length until terminated by an EOX or any status byte
          syn.m_in.type = data;
          syn.sysex.ix = 0;
          break;

        case SONG_POSITION:
          syn.m_in.type = data;
          syn.m_in.count = 2;
          break;

        case SONG_SELECT:
          syn.m_in.type = data;
          syn.m_in.count = 1;
          break;

        case TUNE_REQUEST:
          // no associated data
          break;

        case EOX: // system exclusive terminator
          // no need to do anything here, it will be picked up after the switch
          break;

        // real time (no associated data)
        case TIMING_CLOCK:
        case START:
        case CONTINUE:
        case STOP:
        case ACTIVE_SENSING:
          real_time = 1;
          break;

        case SYSTEM_RESET:
          real_time = 1;
          midiSynth_reset(); // reset synth
          break;
      }
    }

    // check for an unterminated system exclusive message
    if(!real_time && (syn.sysex.ix > 0))
    {
      syn.sysex.buff[syn.sysex.ix] = EOX;
      interpret_sys_ex(syn.sysex.buff);
      syn.sysex.ix = 0;
    }
  }
  else
  {
    // data byte
    c = &syn.chan[syn.m_in.channel]; // point to the current channel (not always needed)
    on = data >> 6; // for on/off controls (not always needed)

    switch (syn.m_in.type)
    {
      case SYSTEM_EXCLUSIVE:
        if(syn.sysex.ix < SYS_LEN) // discard data if the buffer is full
          syn.sysex.buff[syn.sysex.ix++] = data;
        break;

      case SONG_SELECT:
        syn.m_in.song = data;
        break;

      case SONG_POSITION:
        load_14bit_value(&syn.m_in.position, data, syn.m_in.count);
        break;

      case NOTE_OFF:
        if(syn.m_in.count == 2) // pitch
          syn.m_in.pitch = data;
        else // velocity
        {
          syn.m_in.velocity = data;
          poly_action_key(syn.m_in.pitch, FALSE, syn.m_in.channel, syn.m_in.velocity);
        }
        break;

      case NOTE_ON:
        if(syn.m_in.count == 2) // pitch
          syn.m_in.pitch = data;
        else // velocity
        {
          syn.m_in.velocity = data;
          poly_action_key(syn.m_in.pitch, (data != 0), syn.m_in.channel, syn.m_in.velocity); // note off if data == 0
        }
        break;

      case KEY_PRESSURE:
        if(syn.m_in.count == 2) // pitch
          syn.m_in.pitch = data;
        else // pressure
          syn.m_in.pressure = data;
        break;

      case CONTROL:
        if(syn.m_in.count == 2)
        {
          syn.m_in.controller = data; // controller number
          // channel mode messages with no associated data
          switch(syn.m_in.controller)
          {
            case ALL_SOUND_OFF:
              reset_gates(syn.m_in.channel);
              break;

            case ALL_CONTROLLERS_OFF:
              reset_controllers(c);
              break;

            case LOCAL_KEYBOARD_on:
              break;

            case ALL_NOTES_OFF:
              reset_gates(syn.m_in.channel);
              break;

            case OMNI_MODE_OFF:
              syn.switches |= (1<<OMNI_MODE);
              break;

            case OMNI_MODE_ON:
              syn.switches &= ~(1<<OMNI_MODE);
              break;

            case POLY_OPERATION:
              syn.switches &= ~(1<<POLY_MODE);
              break;
          }
        }
        else // setting
        {
          int hi_lo = (syn.m_in.controller >> 5) + 1; // 1=MSB, 2=LSB
          switch (syn.m_in.controller)
          {
#ifdef PROGRAM_UPDATES_BANKS
            case BANK_hi: c->temp.hi = data; break;
            case BANK_lo: c->temp.lo = data; break;
#else
            case BANK_hi: c->patch.hi = data; break;
            case BANK_lo: c->patch.lo = data; break;
#endif

            case MOD_WHEEL_hi:
            case MOD_WHEEL_lo:
              load_14bit_value(&c->mod_wheel, data, hi_lo);
              calc_mod_wheel(c);
              break;

            case BREATH_CTRL_hi:
            case BREATH_CTRL_lo:
              load_14bit_value(&c->breath_ctrl, data, hi_lo);
              break;

            case FOOT_PEDAL_hi:
            case FOOT_PEDAL_lo:
              load_14bit_value(&c->foot_pedal, data, hi_lo);
              break;

            case PORTAMENTO_TIME_hi:
            case PORTAMENTO_TIME_lo:
              load_14bit_value(&c->portamento_time, data, hi_lo);
              calc_glide(c);
              break;

            case DATA_ENTRY_hi:
            case DATA_ENTRY_lo:
              load_14bit_value(c->param_ptr, data, hi_lo);
              break;

            case VOLUME_hi:
            case VOLUME_lo:
              load_14bit_value(&c->volume, data, hi_lo);
              calc_vol_expr(c);
              break;

            case BALANCE_hi:
            case BALANCE_lo:
              load_14bit_value(&c->balance, data, hi_lo);
              calc_pan_bal(c);
              break;

            case PAN_POSN_hi:
            case PAN_POSN_lo:
              load_14bit_value(&c->pan_posn, data, hi_lo);
              calc_pan_bal(c);
              break;

            case EXPRESSION_hi:
            case EXPRESSION_lo:
              load_14bit_value(&c->expression, data, hi_lo);
              calc_vol_expr(c);
              break;

            case PORTAMENTO_CTRL:
              c->portamento_ctrl = data;
              if(data > 0)
                c->switches |= (1<<PORTAM_CTRL);
              break;

            case SOUND_VIBRATO_RATE:  c->vibrato_rate  = data; break;
            case SOUND_VIBRATO_DEPTH: c->vibrato_depth = data; break;
            case SOUND_VIBRATO_DELAY: c->vibrato_delay = data; break;

            case HOLD_PEDAL_on:
              c->switches = (c->switches & ~(1<<HOLD_PEDAL)) | (on << HOLD_PEDAL);
              c->switches_delta |= (1<<HOLD_PEDAL);
              break;

            case PORTAMENTO_on:
              c->switches = (c->switches & ~(1<<PORTAMENTO)) | (on << PORTAMENTO);
              c->switches_delta |= (1<<PORTAMENTO);
              portamento_on_off(syn.m_in.channel, on);
              break;

            case SUSTENUTO_PEDAL_on:
              c->switches = (c->switches & ~(1<<SUSTENUTO_PEDAL)) | (on << SUSTENUTO_PEDAL);
              c->switches_delta |= (1<<SUSTENUTO_PEDAL);
              break;

            case SOFT_PEDAL_on:
              c->switches = (c->switches & ~(1<<SOFT_PEDAL)) | (on << SOFT_PEDAL);
              c->switches_delta |= (1<<SOFT_PEDAL);
              break;

            case LEGATO_PEDAL_on:
              c->switches = (c->switches & ~(1<<LEGATO_PEDAL)) | (on << LEGATO_PEDAL);
              c->switches_delta |= (1<<LEGATO_PEDAL);
              break;

            case HOLD_2_PEDAL_on:
              c->switches = (c->switches & ~(1<<HOLD_2_PEDAL)) | (on << HOLD_2_PEDAL);
              c->switches_delta |= (1<<HOLD_2_PEDAL);
              break;

            case DATA_BUTTON_INC: if(c->param_ptr)(*c->param_ptr)++; break;
            case DATA_BUTTON_DEC: if(c->param_ptr)(*c->param_ptr)--; break;

            case REG_PARM_hi:
            case NON_REG_PARM_hi: load_14bit_value(&c->param_idx, data, MSB); select_rpn(c); break;

            case REG_PARM_lo:
            case NON_REG_PARM_lo: load_14bit_value(&c->param_idx, data, LSB); select_rpn(c); break;

            case MONO_OPERATION:
              // data = number of monophonic voices
              syn.switches = (syn.switches & ~(MONO_MASK<<MONO_VOICES)) | (1<<POLY_MODE) | (data<<MONO_VOICES);
              break;
          }
        }
        break;

      case PROGRAM:
        c->patch.prg = data;
#ifdef PROGRAM_UPDATES_BANKS
        c->patch.hi = c->temp.hi;
        c->patch.lo = c->temp.lo;
#endif
        break;

      case CHAN_PRESSURE:
        c->pressure = data;
        break;

      case PITCH_WHEEL:
        load_14bit_value(&c->pitch_wheel, data, syn.m_in.count);
        calc_pitch_bend(c);
        break;
    }

    syn.m_in.count ^= 3; // toggle between 1 and 2 (MSB and LSB for 14 bit values)
  }
}


