mididec.h、mididec.c

/*************************************************/
/* mididec.h : MIDI decoder                      */
/*             for ATtiny10                      */
/*                                               */
/* 2012/01/16 : Created by pcm1723               */
/*************************************************/

#ifndef _MIDIDEC_H_
#define _MIDIDEC_H_

#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

// MIDI receive channel ( 0 origin )
#define MIDI_rcv_ch (0)

typedef union tag_u16_u8_t {
  uint16_t u16;
  uint8_t  u8[2];
} u16_u8_t;

typedef struct {
  uint8_t  on_cnt; // key on count
  int16_t  gate_que;
#if (0)
  uint8_t  gate;   // key on/off 
#endif
} unit_prop_t, *unit_prop_p;

typedef struct {
  uint8_t  MD_note;       // MIDI note number (0..127)
  uint8_t  MD_bend[2];    // MIDI pitch bend
  uint8_t  MD_bend_range; // MIDI RPN#1 pitch bend range (1..127)
  uint8_t  MD_RPN_MLB;    // MIDI RPN MSB and LSB in a byte
#if (0)
  uint8_t  MD_progno;     // MIDI program number (0..127)
  uint8_t  MD_modulation; // MIDI CC#1  modulation (0..127)
  uint8_t  MD_volume;     // MIDI CC#7  ch volume (0..127)
  uint8_t  MD_expression; // MIDI CC#11 expression (0..127)
  uint8_t  MD_dent_MSB;   // MIDI CC#6  data entry MSB (0..127)
  uint8_t  MD_dent_LSB;   // MIDI CC#38 data entry LSB (0..127)
  int16_t  MD_RPN_ML;     // MIDI RPN MSB and LSB (0x0000..0x7f7f)
  int16_t  bend_f;        // pitch bend value b15..b8:int, b7..b0:frac
#endif
} ch_prop_t, *ch_prop_p;

extern ch_prop_t   ch_prop[1];
extern unit_prop_t unit_prop[1];

extern void mididec(uint8_t data);
extern int8_t md_data_byte( void );
extern int8_t md_cc_func(/* ch_prop_t *c_p */);

extern uint8_t MD_data;
extern uint8_t MD_ch;
extern uint8_t MD_2nd;
extern uint8_t MD_3rd;
extern uint8_t MS_run_stat;
extern int8_t  MD_bcnt;
//extern uint8_t sysex_cnt;
//extern uint8_t MIDI_rcv_ch;

// generator polynomial for CRC-8
// g(x) = x^8 + x^7 + x^6 + x^4 + x^2 + 1
#define CRC8_GX (0xD5)

// CRC result for GM reset (excluding 0xF0 and 0xF7)
// GM System ON = (0xF7) 0x7E 0x7F 0x09 0x01 (0xF7)
#define GM_RESET_CRC (0xF0)

#endif
/*************************************************/
/* mididec.c : MIDI decoder                      */
/*             for ATtiny10                      */
/*                                               */
/* 2012/01/16 : Created by pcm1723               */
/*************************************************/

#include "mididec.h"
#include "midifunc.h"

uint8_t MD_data;
uint8_t MD_ch;
uint8_t MD_2nd;
uint8_t MD_3rd;
uint8_t MS_run_stat;
 int8_t MD_bcnt;
//uint8_t sysex_cnt;
//uint8_t MIDI_rcv_ch;

ch_prop_t ch_prop[1];
unit_prop_t unit_prop[1];

#if (0)
uint8_t crc_sr; 

static inline void update_crc8(uint8_t d)
{
  uint8_t i;
  crc_sr ^= d;
  for (i = 0; i < 8; i++) { // for each bit 
    if (0x80 & crc_sr) { // feedback
      crc_sr <<= 1; 
      crc_sr ^= CRC8_GX; // polynomial pattern
    } else { // shift only
      crc_sr <<= 1;
    } // if (0x80 & crc_sr) ...
  } // for (i = ... 
} // void update_crc8()
#endif


/* MIDI Control Change and mode message (status byte == 0xBn) */
int8_t md_cc_func(/* ch_prop_t *c_p */)
{
//  int i;
  switch (MD_2nd) { // switch by control number
#if (0)
    case 0x01 :  // MODULATION (1)
      c_p->MD_modulation = MD_3rd;
      break;
    case 0x07 :  // VOLUME (7)
      c_p->MD_volume = MD_3rd;
      calc_vol_exp(c_p);
      break;
    case 0x0a :  // PAN (10)
      c_p->MD_pan = MD_3rd;
      break;
    case 0x0b :  // EXPRESSION (11)
      c_p->MD_expression = MD_3rd;
      calc_vol_exp(c_p);
      break;
    case 0x5b :  // REVERB SEND LEVEL (91)
      c_p->MD_rev_send = MD_3rd;
      break;
    case 0x7e :  // MONO MODE ON  (126)
    case 0x7f :  // POLY MODE ON  (127)
      if (0x7e == MD_2nd) c_p->MD_legato = 127; // set legato if mono mode
      else                c_p->MD_legato = 0;   // set non-legato if poly mode
      all_note_off(c_p);
/*
      demoflag = 0;
*/
      break;
#endif
    case 0x78 :  // ALL SOUND OFF (120)
    case 0x7a :  // LOCAL ON/OFF  (122)
    case 0x7b :  // ALL NOTE OFF  (123)
    case 0x7c :  // OMNI MODE OFF (124)
    case 0x7d :  // OMNI MODE ON  (125)
      all_note_off(/* c_p */);
/*
      demoflag = 0;
*/
      break;
#if (0)
    case 0x79 :  // RESET ALL CONTROLLERS (121)
/*
      reset_all_controllers(c_p);
      demoflag = 0;
*/
      break;
#endif
#if (1)
    case 0x06 :  // DATA ENTRY MSB (6)
      if (0x00 == ch_prop[0].MD_RPN_MLB) { // RPN#0000 
// Pitch bend sensitibity
        ch_prop[0].MD_bend_range = MD_3rd;
        return(1);
      } // if 
//      ch_prop[0].MD_dent_MSB = MD_3rd;
//      decode_rpn (c_p, c_p->MD_RPN_ML,  0x100); // for MSB 
//      decode_nrpn(c_p, c_p->MD_NRPN_ML, 0x100); // for MSB 
      break;
#endif
#if (0)
    case 0x26 :  // DATA ENTRY LSB (38)
      c_p->MD_dent_LSB = MD_3rd;
//      decode_rpn (c_p, c_p->MD_RPN_ML,  0); // for LSB 
//      decode_nrpn(c_p, c_p->MD_NRPN_ML, 0); // for LSB 
      break;
    case 0x60 :  // DATA INCREMENT (96)
/*
      decode_rpn (c_p, c_p->MD_RPN_ML,  1); // for data increment
*/
      break;
    case 0x61 :  // DATA DECREMENT (97)
/*
      decode_rpn (c_p, c_p->MD_RPN_ML, -1); // for data decremant
*/
      break;
#endif
    case 0x62 :  // NRPN LSB (98)

//      c_p->MD_NRPN_ML = MD_3rd | (0x7f00 & c_p->MD_NRPN_ML);
      ch_prop[0].MD_RPN_MLB  = 0x7f; // cancel RPN
      break;
    case 0x63 :  // NRPN MSB (99)

//      c_p->MD_NRPN_ML = (MD_3rd <<8) | (0x7f & c_p->MD_NRPN_ML);
      ch_prop[0].MD_RPN_MLB  = 0x7f; // cancel RPN

      break;
    case 0x64 :  // RPN LSB (100)
      ch_prop[0].MD_RPN_MLB = (0x0f & MD_3rd) | (0xf0 & ch_prop[0].MD_RPN_MLB);
//      c_p->MD_NRPN_ML = 0x7f7f; // cancel NRPN
      break;
    case 0x65 :  // RPN MSB (101)
      ch_prop[0].MD_RPN_MLB = ((0x0f & MD_3rd) << 4) | (0x0f & ch_prop[0].MD_RPN_MLB);
//      c_p->MD_NRPN_ML = 0x7f7f; // cancel NRPN
      break;
#if (0)
    case 0x40 :  // HOLD1/DAMPER (64)
    case 0x42 :  // SOSTENUTO    (66)
    case 0x43 :  // SOFT         (67)
//      pedal_sw(c_p, MD_2nd, MD_3rd);
      break;
    case 0x44 :  // LEGATO SW    (68)
//      c_p->MD_legato = MD_3rd;
      break;
    case 0x05 :  // PORTAMENTO TIME (5)
/*
      c_p->MD_porta_time = MD_3rd;
      calc_porta_time(c_p, MD_3rd);
*/
      break;
    case 0x41 :  // PORTAMENT ON/OFF (65)
//      c_p->MD_porta_sw = MD_3rd;
      break;
    case 0x54 :  // PORTAMENT CONTROL (84)
//      c_p->MD_porta_src = MD_3rd;
      break;
    case 0x47 :  // TIMBRE/HARMONIC CONTENT (71)
//      c_p->MD_timbre = MD_3rd - 0x40;
      break;
    case 0x4a :  // BRIGHTNESS (74)
//      c_p->MD_brightness = MD_3rd - 0x40;
      break;
    case 0x48 :  // ENVELOPE RELEASE (72)
    case 0x49 :  // ENVELOPE ATTACK  (73)
    case 0x4b :  // ENVELOPE DECAY   (75)
//      edit_voice(c_p, MD_2nd, MD_3rd);
      break;
    case 0x4c :  // VIBRATO RATE (76)
/*
      c_p->MD_vib_rate = MD_3rd - 0x40;
      calc_vibrato(c_p);
*/
      break;
    case 0x4d :  // VIBRATO DEPTH (77)
/*
      c_p->MD_vib_depth = MD_3rd - 0x40;
      calc_vibrato(c_p);
*/
      break;
    case 0x4e :  // VIBRATO DELAY (78)
/*
      c_p->MD_vib_delay = MD_3rd - 0x40;
      calc_vibrato(c_p);
*/
      break;
#endif
    default: break;
  } // switch (MD_2nd)
  return(0);
} // int8_t md_cc_func()

/* process data byte part of MIDI message */
int8_t md_data_byte(void)
{
  uint8_t mrs; // masked MIDI running status
  if (0 > MD_bcnt) {
#if (0)
    update_crc8(MD_data);
#endif
    return(0); // MD_bcnt is negative? exit if so
  } // if (0 > MD_bcnt) { ...
#if (0)
  if (0 < sysex_cnt) { // SysEx 
    sysex_cnt++;
  } // if (0 < sysex_cnt) ...
  else 
#endif
  { // other message 
    if (0 == MD_bcnt) { // status omitted, default to running status  
      MD_bcnt++;  // modify byte count and fall into MD_bcnt==1 
    }
    if (1 == MD_bcnt) { // 2nd byte of the message
      MD_2nd = MD_data; // note number 
      mrs = (0xf0 & MS_run_stat); // check for 2-byte message
      if (0xc0 == mrs) {  // Program Change
        if (MIDI_rcv_ch == MD_ch) { // supported channel
#if (0)
          ch_prop_t *c_p = &(ch_prop[0]);
          c_p->MD_progno = MD_2nd;
/*
              setup_voice(c_p, MD_2nd);
#ifdef LCD
              mon_pc_disp(c_p, MD_2nd);
#endif
*/
#endif
        } // if (MIDI_rcv_ch == MD_ch)
        MD_bcnt = 0; // wait for status byte 
      }
	  else if (0xd0 == mrs) {   // Channel key pressure
        if (MIDI_rcv_ch == MD_ch) { // supported channel
#if (0)
              ch_prop_t *c_p = &(ch_prop[0]);
              c_p->MD_modulation = MD_2nd; // route to modulation

//#ifdef LCD
//              mon_cc_bend_disp(c_p, 'A', MD_2nd, -1);
//#endif

#endif
        } // if (MIDI_rcv_ch == MD_ch)
        MD_bcnt = 0; // wait for status byte 
      }
      else {  
        if (0xf1 == MS_run_stat) { // MTC quater frame
           MD_bcnt = 0; // ignore, wait for next status
        }
        else if (0xf3 == MS_run_stat) { // Song select
//                seq_songsel(MD_2nd); // 
          MD_bcnt = 0; // wait for next status
        }
        else { // other 3-byte message (0x8n, 0x9n, 0xAn, 0xBn, 0xEn)
           MD_bcnt++; // wait for verocity 
        } // else
      } // else 
    }
    else if (2 == MD_bcnt) {  // 3rd byte of the message
      MD_bcnt = 0; // wait for next MIDI message 
      if (MIDI_rcv_ch == MD_ch) { // supported channel
//        ch_prop_t *c_p = &(ch_prop[0]);
        MD_3rd = MD_data; // verocity 
        mrs = (0xF0 & MS_run_stat);
        if (0x90 == mrs) {  // MIDI NOTE-ON message 
          if (0 == MD_3rd) { // (vel == 0) stands for NOTE-OFF 
            midi_note_off(/* c_p, */ MD_2nd);
          }  // if (0 == MD_3rd)
          else { // NOTE-ON with velocity
            midi_note_on(/* c_p, */ MD_2nd, MD_3rd);
          } // else 
        } // if (0x90 ==
        else if (0x80 == mrs) {  // NOTE-OFF message 
          midi_note_off(/* c_p, */ MD_2nd);
        } // else if (0x80 ==
        else if (0xb0 == mrs) {  // CONTROL-CHANGE
           return(1);
//              md_cc_func(/* c_p */);
/*
#ifdef LCD
              mon_cc_bend_disp(c_p, 'C', MD_2nd, MD_3rd);
#endif
*/
        } // else if (0xb0 ==
        else if (0xe0 == mrs) {  // PITCH BEND message 
#if (1)
//          int16_t b; // vendor linear value
//          b = ((((int16_t)MD_3rd) << 7) | MD_2nd) - 0x2000;
          ch_prop[0].MD_bend[1] = (MD_3rd-0x40);
          ch_prop[0].MD_bend[0] = (MD_2nd << 1);
          pitch_bend(/* c_p, b*/);
/*
#ifdef LCD
              mon_cc_bend_disp(c_p, 'B', MD_2nd, MD_3rd);
#endif
*/
#endif
        } // else if (0xe0 ==
        else { // ignore other message (0xf2: song position pointer, etc.)
          MD_bcnt = 0; // wait for next message
        } // else 
      } // if (MAXMIDICH < MD_ch) ...
    }
    else  MD_bcnt = 0;
  } // if (0 < sysex_cnt) {} else ...
  return(0);
} // int8_t md_data_byte()

void mididec(uint8_t data)
{
  uint8_t mdd;
  MD_data = data; // received data
  if (0x80 & MD_data) { // is status byte ?
    if (0xf8 != (0xf8 & MD_data)) { // if system realtime message, do not affect running status
      MS_run_stat = MD_data;        // set running status 
      MD_ch       = 0x0F & MD_data; // extract MIDI channel 
    } // if (0xf8 ... 
    mdd = (0xf8 & MD_data);
    if (0xf0 == mdd) { // System exclusive message
        if (0xf0 == MD_data) { // start of SysEx message
#if (0)
          sysex_cnt = 0; // point to top of SysEx buffer
          MD_bcnt   = 1;
#else
          MD_bcnt   = -1; // skip data bytes
//          crc_sr = 0; // reset CRC calc
#endif
//          sysex_buf[sysex_cnt++] = MD_data; // copy the first 'F0' byte
        } // if (0xf0 == ...
        else if (0xf7 == MD_data) { // end of SysEx message
//          if (0 <= MD_bcnt) { // data successfully copied
//            sysex_buf[sysex_cnt++] = MD_data; // copy the last 'F7' byte
#if (0)
            if (GM_RESET_CRC == crc_sr) {
              GM_reset();
            } // if (GM_RESET_CRC == crc_sr) ...
#endif
            MD_bcnt = 0; // wait for next status
//            sysex_dec(sysex_cnt);
//            sysex_cnt = 0; // exit SysEx mode
//          } // if (0 <= 
        } // else if
    }
    else if (0xf8 == mdd) {  // System realtime message
	}  // ignore
    else {  // Note ON/OFF, CC, PC, Pitch Bend, etc.
        MD_bcnt = 1; // wait for next byte 
    } // if () ... 
  } // if (0x80 & MD_data) ... 
  else { // parameter byte 
    md_data_byte();
  } // if (0 == MIDI_bcnt) ...
} // void mididec()