KAMUI MIDI-CV Example

Dependencies:   TextLCD mbed

Files at this revision

API Documentation at this revision

Comitter:
radiojunkbox
Date:
Sat May 05 11:35:41 2012 +0000
Commit message:
Rev. 1.0

Changed in this revision

TextLCD.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
midi_parser.c Show annotated file Show diff for this revision Revisions of this file
midi_parser.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 25a282f1141a TextLCD.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD.lib	Sat May 05 11:35:41 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/TextLCD/#44f34c09bd37
diff -r 000000000000 -r 25a282f1141a main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat May 05 11:35:41 2012 +0000
@@ -0,0 +1,512 @@
+//-------------------------------------------------------------
+// KAMUI MIDI-CV Exapmple
+// Copyright (C) 2012 RJB RadioJunkBox
+// Released under the MIT License: http://mbed.org/license/mit
+//-------------------------------------------------------------
+
+#include "mbed.h"
+#include "TextLCD.h"
+#include <stdlib.h>
+#include <math.h>
+
+//-------------------------------------------------------------
+// Define
+
+#define AD5551                      // 14bitDAC
+
+#define SPI_RATE            1000000 // 1Mbps
+#define MIDI_RATE           31250   // 31.25kbps
+#define BEEP_FREQ           1760.0  // 1760Hz
+#define UPDATE_INTERVAL     100     // 100us
+#define SW_WATCH_INTERVAL   (25000/UPDATE_INTERVAL) // 25ms
+#define PARAM_GLIDE         6554.0
+#define PARAM_DP            6912.0  // UPDATE_INTERVAL = 100us
+//#define PARAM_DP            8192.0  // UPDATE_INTERVAL = 50us
+
+#define UPDATE_MODE0        0       // Update Interval CV ch1-6 1200us, ch7,8 400us
+#define UPDATE_MODE1        1       // Update Interval CV ch1-6 N/A,    ch7,8 200us
+
+#define GATE1               0x01
+#define GATE2               0x02
+#define GATE3               0x04
+#define GATE4               0x08
+
+#define SYNC1CLK            0x01
+#define SYNC1RUN            0x02
+#define SYNC2CLK            0x04
+#define SYNC2RUN            0x08
+
+#define MODE_CV             0x00
+#define MODE_GATE           0x40
+#define MODE_SYNC           0x80
+#define MODE_SET_SYNC       0xC0
+
+#define SW1                 0x01
+#define SW2                 0x02
+#define SW3                 0x04
+#define SW4                 0x08
+#define SYNC1CLK_IN         0x10
+#define SYNC1RUN_IN         0x20
+#define SYNC2CLK_IN         0x40
+#define GATE_IN             0x80
+
+#define _ENABLE             0
+#define _DISABLE            1
+
+#define BUFSIZE             32  // size of ring buffer (ex 4,8,16,32...)
+#define LFO_WF_TRI          0
+#define LFO_WF_SQR          1
+#define LFO_WF_SAW          2
+#define LFO_WF_NONE         3
+#define MINIMUMNOTE         12
+#define SYNC_TURN_TIME      (5000/UPDATE_INTERVAL)  // 5ms          
+
+//-------------------------------------------------------------
+// Functions
+
+void            InitKamui(void);
+void            UpdateCV(void);
+unsigned char   CheckSW(unsigned char);
+
+void            RcvMIDI(void);
+void            MidiCV(void);
+void            CalcHzVTbl(void);
+unsigned short  OctVtoHzV(unsigned short);
+void            DinSync(void);
+extern void     MIDI_Parser(unsigned char);
+
+//-------------------------------------------------------------
+// Global Variables
+
+int gUpdateMode;
+unsigned short gCV[8];
+unsigned char  gGATE;
+unsigned char  gSYNC;
+unsigned char  gSW;
+
+union {
+    unsigned short    WORD;    
+    struct {
+        unsigned char L;
+        unsigned char H; 
+    } BYTE;
+} gDAC;
+
+int             gPtr_buf_in, gPtr_buf_out;
+unsigned char   gRxBuf[BUFSIZE];
+
+float           gGLIDE[4];
+unsigned short  gLFO_DP[4];
+unsigned char   gLFO_FORM[4];
+unsigned char   gMIDI_CH[4];
+short           gTblHzV[3072];
+
+extern unsigned char    gPlayNoteBuf[];
+extern unsigned char    gGateBuf[];
+extern unsigned char    gPitchBendBuf[];
+extern unsigned char    gModWheelBuf[];
+extern unsigned char    gMIDISYNC_CLK;
+extern unsigned char    gMIDISYNC_RUN;
+
+//-------------------------------------------------------------
+// mbed Functions
+
+// TextLCD
+TextLCD gLCD(p23, p24, p25, p26, p29, p30); // rs, e, d4-d7
+
+// SPI
+SPI gSPI(p11,p12,p13);
+DigitalOut gCSA(p14);
+DigitalOut gCSB(p22);
+
+// Sirial MIDI
+Serial gMIDI(p9,p10);
+
+// AnalogIn
+AnalogIn    gAIN1(p15);   // VR1
+AnalogIn    gAIN2(p16);   // VR2
+AnalogIn    gAIN3(p17);   // VR3
+AnalogIn    gAIN4(p18);   // VR4
+AnalogIn    gAIN5(p19);   // IN1
+AnalogIn    gAIN6(p20);   // IN2
+
+// BEEP
+PwmOut gBEEP(p21);
+
+// LED
+DigitalOut gLED1(LED1);
+DigitalOut gLED2(LED2);
+DigitalOut gLED3(LED3);
+DigitalOut gLED4(LED4);
+BusOut gLEDS(LED1,LED2,LED3,LED4);
+
+// Ticker
+Ticker gTICKER;
+
+//-------------------------------------------------------------
+// main
+
+int main() {
+
+    int i;
+    int pot[4],_pot[4];
+    unsigned char rb;
+    unsigned char ch = 0;
+    unsigned char mode = 7; // for Intialize
+    unsigned char edit[4];
+    int val[2][4] = { 0, 0, 0, 0, 50, 50, 50, 50 };
+    char *wave[4] = { "TR","SQ","SW","--" };
+
+    // Initialize
+    gPtr_buf_in = gPtr_buf_out = 0;
+    for( i=0; i<4; i++) {
+        pot[i] = _pot[i] = 0;
+        edit[i] = 0;
+        gGLIDE[i] = 1.0 / expf(val[0][i]*656.0/PARAM_GLIDE);
+        gLFO_DP[i] = expf(val[1][i]*656.0/PARAM_DP); 
+        gLFO_FORM[i] = LFO_WF_TRI;
+        gMIDI_CH[i] = i; 
+    }
+    
+    for( i=0; i<16; i++) {  // MIDI Data Buffers
+        gPlayNoteBuf[i] =24;
+        gGateBuf[i] = 0;
+        gPitchBendBuf[i] = 0x40;
+        gModWheelBuf[i] = 0;        
+    }
+    
+    gSW = 1; // for Intialize
+    
+    CalcHzVTbl();
+    InitKamui();        
+
+    // loop
+    while(1) {
+
+        // ring buffer empty?
+        if(gPtr_buf_in != gPtr_buf_out) {
+
+            // get 1byte from ring buffer
+            gPtr_buf_out++;
+            gPtr_buf_out &= (BUFSIZE - 1);
+            rb = gRxBuf[gPtr_buf_out];
+            MIDI_Parser(rb);
+            continue;
+        }        
+
+        // Read pot
+        pot[0] =  gAIN1.read_u16();
+        pot[1] =  gAIN2.read_u16();
+        pot[2] =  gAIN3.read_u16();
+        pot[3] =  gAIN4.read_u16();
+        
+        // change pot amount?
+        if(abs(pot[ch] - _pot[ch]) > 0x2000) edit[ch] = 1;
+
+        if(edit[ch]) {
+            switch(mode) {
+                case 0:
+                    gGLIDE[ch] = 1.0 / expf(pot[ch]/PARAM_GLIDE);
+                    val[0][ch] = pot[ch] / 656;
+                    break;
+                case 1:
+                    gLFO_DP[ch] = expf(pot[ch]/PARAM_DP);
+                    val[1][ch] = pot[ch] / 656;
+                    break;
+                case 2:
+                    gLFO_FORM[ch] = pot[ch] / 0x4000;
+                    break;
+                case 3:
+                    gMIDI_CH[ch] = pot[ch] / 0x1000;
+                    break;
+                default:
+                    break;
+            }
+        }
+        
+        // Push Mode SW
+        if(gSW & SW1) {
+            mode++;
+            mode &= 0x03;                      
+            for( i=0; i<4; i++) {
+                _pot[i] = pot[i];
+                edit[i] = 0;
+            }
+        }
+        gSW = 0;
+
+        // LCD Display
+        gLCD.locate( 0, 1 );
+        switch(mode) {
+            case 0:
+                gLCD.printf("GLID %02d %02d %02d %02d",
+                    val[0][0], val[0][1], val[0][2], val[0][3]);
+                break;
+            case 1:
+                gLCD.printf("FREQ %02d %02d %02d %02d",
+                    val[1][0], val[1][1], val[1][2], val[1][3]);
+                break;
+            case 2:
+                gLCD.printf("FORM %s %s %s %s",
+                    wave[gLFO_FORM[0]], wave[gLFO_FORM[1]],
+                    wave[gLFO_FORM[2]], wave[gLFO_FORM[3]]); 
+                break;
+            case 3:
+                gLCD.printf("MIDI %02d %02d %02d %02d",
+                    gMIDI_CH[0]+1, gMIDI_CH[1]+1,
+                    gMIDI_CH[2]+1, gMIDI_CH[3]+1);
+                break;
+        }
+
+        ch++;
+        ch &= 0x03;
+    }
+}
+
+//-------------------------------------------------------------
+// Initialize KAMUI
+
+void InitKamui()
+{
+    // Init. Variables
+    for( int i=0; i<8; i++) {
+        gCV[i] = 0x8000;
+    }
+    gGATE = 0;
+    gSYNC = 0;
+
+    gUpdateMode = UPDATE_MODE0;
+  
+    // Init. SPI
+    gCSA = _DISABLE;
+    gCSB = _DISABLE;
+    gSPI.format(8,0);
+    gSPI.frequency(SPI_RATE);
+
+    // Init. Serial MIDI
+    gMIDI.baud(MIDI_RATE);
+    
+    // Ticker
+    gTICKER.attach_us(&UpdateCV, UPDATE_INTERVAL);
+
+    // Beep
+    gBEEP.period(1.0/BEEP_FREQ);
+    gBEEP.write(0.5);
+    wait(0.2);
+    gBEEP.write(0.0);
+
+    // Init Display
+    gLCD.locate( 0, 0 );
+              // 123456789ABCDEF
+    gLCD.printf("MIDI-CV Example");
+}
+
+//-------------------------------------------------------------
+// Update CV, GATE, SYNC
+
+void UpdateCV()
+{ 
+    unsigned char rcv,ch;
+    unsigned char ptn[] = { 0,1,6,7,2,3,6,7,4,5,6,7 };
+    const int numptn = (sizeof ptn / sizeof ptn[0]) - 1;
+    static unsigned char  cnt;
+
+    // SET DAC 
+    ch = ptn[cnt];
+    if(gUpdateMode) ch |= 0x06;
+
+#ifdef AD5551 // 14bitDAC
+    gDAC.WORD = gCV[ch] >> 2;
+#else
+    gDAC.WORD = gCV[ch];    
+#endif
+    
+    gCSA = _ENABLE;
+    gSPI.write(gDAC.BYTE.H);
+    gSPI.write(gDAC.BYTE.L);
+    gCSA = _DISABLE;        
+
+    // GATE or SYNC OUT
+    if(cnt & 0x01) {
+        // GATE OUT
+        gCSB = _ENABLE;
+        rcv = gSPI.write(gGATE | MODE_GATE) & 0x0F;
+        gCSB = _DISABLE;
+    }
+    else {
+        // SYNC OUT
+        gCSB = _ENABLE;
+        rcv = gSPI.write(gSYNC | MODE_SYNC);
+        gCSB = _DISABLE;
+    }
+
+    // SEL CV CHANNEL
+    gCSB = _ENABLE;
+    gSPI.write(ch);
+    gCSB = _DISABLE;
+
+    cnt < numptn ? cnt++ : cnt = 0;
+
+    gSW |= CheckSW(rcv);
+    RcvMIDI();
+    DinSync();
+    MidiCV();
+}
+
+//-------------------------------------------------------------
+// Check SW
+
+unsigned char CheckSW(unsigned char c) {
+
+    static unsigned char  swbuf[2];
+    static unsigned int   cntsw;
+    unsigned char ret = 0;
+
+    if(cntsw > SW_WATCH_INTERVAL) {
+        if(c &= 0x0F) {
+            if(!swbuf[1]) {
+                if( swbuf[0] == c) {
+                    swbuf[1] = c;
+                    ret = c;
+                }
+                else {
+                    swbuf[0] = c;
+                }
+            }
+        }
+        else {
+            swbuf[1] = 0;
+            swbuf[0] = 0;
+        }
+        cntsw = 0;
+    }
+    cntsw++;
+    return ret;
+}
+
+//-------------------------------------------------------------
+// Receive MIDI Data & Store Ring Buffer
+
+void RcvMIDI() {
+
+    if(!gMIDI.readable()) return;
+
+    gPtr_buf_in++;
+    gPtr_buf_in &= (BUFSIZE - 1);
+    gRxBuf[gPtr_buf_in] = gMIDI.getc();
+}
+
+//-------------------------------------------------------------
+// MIDI Data to CV, GATE
+
+void MidiCV()
+{
+    static unsigned char ch;
+    static unsigned short phase[4];
+    static float cvf[4];
+    int lfo,mod;
+    unsigned char midi_ch;
+    unsigned int cv;
+    unsigned int note;
+    
+    midi_ch = gMIDI_CH[ch];
+
+    note = gPlayNoteBuf[midi_ch];
+    if( note < MINIMUMNOTE) note = MINIMUMNOTE;
+    note -= MINIMUMNOTE;
+
+    // DDS Phase
+    phase[ch] += gLFO_DP[ch];
+
+    // LFO DDS Genelator
+    switch(gLFO_FORM[ch]) {
+        case    LFO_WF_TRI:
+            if(phase[ch] < 32738)  lfo = phase[ch] - 16384;
+            else                   lfo = (16383 + 32768) - phase[ch];
+            break;
+        case    LFO_WF_SQR:
+            if(phase[ch] < 32738)  lfo = 32767;
+            else                   lfo = 0;
+            break;
+        case    LFO_WF_SAW:
+            lfo = phase[ch] / 2 - 16384;
+            break;
+        default :
+            lfo = 0;
+            break;
+    }
+
+    // Modulation amount
+    mod = lfo * gModWheelBuf[midi_ch] >> 7;                
+
+    // Calculate CV
+    cvf[ch]  = ((float)(note << 8) - cvf[ch]) * gGLIDE[ch] + cvf[ch];       
+    cv = (unsigned int)cvf[ch] + (0x8000 - (0x0040 << 3))
+            + (gPitchBendBuf[midi_ch] << 2) + mod;
+    if(cv > 0xFFFF) cv = 0xFFFF;
+    gCV[ch] = (unsigned short)cv;
+    gCV[ch+4] = OctVtoHzV(gCV[ch]);
+
+    // GATE
+    gGateBuf[midi_ch] ? gGATE |= (1<<ch) : gGATE &= ~(1<<ch);
+
+    ch++;
+    ch &= 0x03;
+}
+
+//-------------------------------------------------------------
+// Oct/V to Hz/V Converter
+
+void CalcHzVTbl() // Calc Conv. Table
+{
+    int i;
+    float v;
+
+    for( i=0; i<3072; i++) {
+        v = 24576.0 * pow(2.0,(i/3072.0));
+        gTblHzV[i] = (unsigned short)v;
+    }
+}
+
+unsigned short OctVtoHzV( unsigned short vin)
+{
+    int oct,res;
+    unsigned short vout;
+
+    if(vin > 0xE400) vin = 0xE400;  // Maximum Note E8   Vin = 10.794V
+    if(vin < 0x6800) vin = 0x6800;  // Minimum Note C-2  Vin = -2.000V
+    vin -= 0x6800;
+
+    oct = vin / 0xC00; // 0xC00 : 3072 
+    res = vin % 0xC00;
+
+    vout = ((unsigned short)gTblHzV[res] >> (10 - oct)) + 0x8000;
+    return vout;
+} 
+
+//-------------------------------------------------------------
+// DIN SYNC Control
+
+void DinSync()
+{
+    static unsigned int  cnt;
+    static unsigned int  cnt24 = 10;
+
+    if(gMIDISYNC_RUN) gSYNC |= (SYNC1RUN | SYNC2RUN);
+    else gSYNC &= ~(SYNC1RUN | SYNC2RUN);
+
+    if(cnt >= SYNC_TURN_TIME) gSYNC &= ~(SYNC1CLK | SYNC2CLK);
+
+    if(gMIDISYNC_CLK) {
+        gSYNC |= (SYNC1CLK | SYNC2CLK);
+        gMIDISYNC_CLK = 0;
+        cnt = 0;
+        cnt24++;
+    }
+    if(cnt24 >= 24) cnt24 = 0;
+
+    gLED3 = gSYNC & SYNC1RUN ? 1 : 0;
+    gLED4 = cnt24 < 4 ? 1 : 0;
+    
+    cnt++;
+}
\ No newline at end of file
diff -r 000000000000 -r 25a282f1141a mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat May 05 11:35:41 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/737756e0b479
diff -r 000000000000 -r 25a282f1141a midi_parser.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/midi_parser.c	Sat May 05 11:35:41 2012 +0000
@@ -0,0 +1,259 @@
+//-------------------------------------------------------------
+// KAMUI MIDI-CV Exapmle
+// file : midi_parser.c
+// Copyright (C) 2012 RJB RadioJunkBox
+// Released under the MIT License: http://mbed.org/license/mit
+//-------------------------------------------------------------
+
+#include "mbed.h"
+#include "midi_parser.h"
+
+//-------------------------------------------------------------
+// MIDI Parser
+
+void MIDI_Parser(unsigned char mididata)
+{
+    RxByte = mididata;
+
+    if(MIDI_SystemMessage()) {
+        MIDI_ChannelMessage();
+    }
+}
+
+//-------------------------------------------------------------
+// MIDI System Meassage
+
+int MIDI_SystemMessage(void)
+{
+    if(SysEx){
+        if(RxByte == MIDI_EndSysEx){
+            SysEx = FALSE;
+        }
+    }
+    else{
+        if(RxByte < 0xF8){
+            if(RxByte > 0x7F){
+                if(RxByte == MIDI_StartSysEx){
+                    SysEx = TRUE;
+                }
+                else{
+                    MidiCh = RxByte & 0x0F;
+                }
+                PC = 0;
+             }
+            else{
+                MByte[PC & 0x01] = RxByte;
+            }
+            return TRUE;
+        }
+        else {
+            MIDI_SystemRealtimeMessage();
+        }
+    }
+    return FALSE;
+}
+
+//-------------------------------------------------------------
+// MIDI System Realtime Message
+
+void MIDI_SystemRealtimeMessage(void)
+{
+    switch(RxByte) {
+        case MIDI_TimingClock:
+            gMIDISYNC_CLK |= 0x01;
+            break;
+        case MIDI_Start:
+            gMIDISYNC_RUN = 0x01;
+            break;
+        case MIDI_Continue:
+            gMIDISYNC_RUN = 0x01;
+            break;
+        case MIDI_Stop:
+            gMIDISYNC_RUN = 0x00;
+            break;
+        case MIDI_ActiveSensing:
+            break;
+        case MIDI_SystemReset:
+            break;
+    }
+}
+
+//-------------------------------------------------------------
+// MIDI Channel Message
+
+void MIDI_ChannelMessage(void)
+{
+    switch(PC){
+        case 0:
+            switch(RxByte & 0xF0){
+            case MIDI_NoteOff:
+                PC = 2;
+                break;
+            case MIDI_NoteOn:
+                PC = 4;
+                break;
+            case MIDI_PolykeyPressure:
+                PC = 6;
+                break;
+            case MIDI_ProgramChange:
+                PC = 8;
+                break;
+            case MIDI_ControlChange:
+                PC = 10;
+                break;
+            case MIDI_ChannelPressure:
+                PC = 12;
+                break;
+            case MIDI_PitchBend:
+                PC = 14;
+                break;
+            } break;
+
+        // Note OFF
+        case 2:
+            PC = 3;
+            break;
+        case 3:
+            PC = 2;
+            NoteOFF();
+            break;
+
+        // Note ON
+        case 4:
+            PC = 5;
+            break;
+        case 5:
+            PC = 4;
+            if( MByte[1] == 0){
+                NoteOFF();
+            }
+            else{
+                NoteON();
+            }
+            break;
+
+        // Polyphonic Key Pressure
+        case 6:
+            PC = 7;
+            break;
+        case 7:
+            PC = 6;
+            break;
+
+        // Program Change
+        case 8:
+            break;
+
+        // Control Change
+        case 10: PC = 11; break;
+        case 11:
+            switch(MByte[0]) {
+                case MIDI_CC_Moduration:
+                    gModWheelBuf[MidiCh] = MByte[1] >> 2;
+                    break;
+                case MIDI_CC_DataEntry:
+                    break;
+                case MIDI_CC_RPN_LSB:
+                    break;
+                case MIDI_CC_RPN_MSB:
+                    break;
+                case MIDI_MM_AllSoundOff:
+                    break;
+                case MIDI_MM_ResetAllControl:
+                    break;
+                case MIDI_MM_AllNoteOff:
+                    break;
+            }
+            break;
+
+        // Channel Pressure
+        case 12:
+            break;
+
+        // Pitch Bend
+        case 14:
+            PC = 15;
+            break;
+            
+        case 15:
+            PC = 14;
+            gPitchBendBuf[MidiCh] = (MByte[1] << 1) | (MByte[0] >> 6);
+            break;
+
+        default:
+            break;
+    }
+}
+
+//-------------------------------------------------------------
+// Note ON Message Processing
+
+void NoteON(void)
+{
+    unsigned char i;
+    unsigned char h = 0; // higheest note
+
+    // ignore note if registed buffer
+    for(i = 0; i < NoteCnt[MidiCh]; i++) {
+        if(NoteBuf[MidiCh][i] == MByte[0]) {
+            return;
+        }
+    }
+
+    // full note buffer?
+    if(NoteCnt[MidiCh] == MAX_NOTE_CNT) {
+        for(i = 0; i < (MAX_NOTE_CNT - 1); i++) {
+            NoteBuf[MidiCh][i] = NoteBuf[MidiCh][i+1];
+        }
+        NoteBuf[MidiCh][MAX_NOTE_CNT - 1] = MByte[0];
+    }
+    else {
+        NoteBuf[MidiCh][NoteCnt[MidiCh]] = MByte[0];
+        NoteCnt[MidiCh]++;
+    }
+
+    // set highest note
+    for(i = 0; i < NoteCnt[MidiCh]; i++) {
+        if(h < NoteBuf[MidiCh][i]) {
+            h = NoteBuf[MidiCh][i];
+        }
+    }
+    gPlayNoteBuf[MidiCh] = h;
+    gGateBuf[MidiCh] = ON;
+}
+
+//-------------------------------------------------------------
+// Note OFF Message Processing
+
+void NoteOFF(void)
+{
+    unsigned char i;
+    unsigned char h = 0; // highest note
+    int flg = FALSE;
+
+    // Delete Note If Registed Buffer
+    for(i = 0; i < NoteCnt[MidiCh]; i++) {
+        if(flg) {
+            NoteBuf[MidiCh][i-1] = NoteBuf[MidiCh][i];
+        }
+        if(NoteBuf[MidiCh][i] == MByte[0]) {
+            flg = TRUE;
+        }
+    }
+    if(flg) NoteCnt[MidiCh]--;
+
+    if(NoteCnt[MidiCh] == 0) {
+        // Empty Buffer then Gate OFF
+        gGateBuf[MidiCh] = OFF;
+    }
+    else {
+        // Highest Note
+        for(i = 0; i < NoteCnt[MidiCh]; i++) {
+            if( h < NoteBuf[MidiCh][i]) {
+                h = NoteBuf[MidiCh][i];
+            }
+        }
+        gPlayNoteBuf[MidiCh] = h;
+    }
+}
+
diff -r 000000000000 -r 25a282f1141a midi_parser.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/midi_parser.h	Sat May 05 11:35:41 2012 +0000
@@ -0,0 +1,80 @@
+//-------------------------------------------------------------
+// KAMUI MIDI-CV Example
+// file : midi_parser.h
+// Copyright (C) 2012 RJB RadioJunkBox
+// Released under the MIT License: http://mbed.org/license/mit
+//-------------------------------------------------------------
+
+#ifndef MBED_MIDI_PARSER_H
+#define MBED_MIDI_PARSER_H
+
+//-------------------------------------------------------------
+// Define
+
+#define TRUE                    1
+#define FALSE                   0
+#define ON                      1
+#define OFF                     0
+
+#define MAX_CH                  16
+#define MAX_NOTE_CNT            16
+
+// MIDI Massage
+#define MIDI_NoteOff            0x80
+#define MIDI_NoteOn             0x90
+#define MIDI_PolykeyPressure    0xA0
+#define MIDI_ControlChange      0xB0
+#define MIDI_ProgramChange      0xC0
+#define MIDI_ChannelPressure    0xD0
+#define MIDI_PitchBend          0xE0
+
+#define MIDI_StartSysEx         0xF0
+#define MIDI_TuneRequest        0xF6
+#define MIDI_EndSysEx           0xF7
+
+#define MIDI_TimingClock        0xF8
+#define MIDI_Start              0xFA
+#define MIDI_Continue           0xFB
+#define MIDI_Stop               0xFC
+#define MIDI_ActiveSensing      0xFE
+#define MIDI_SystemReset        0xFF
+
+#define MIDI_CC_Moduration      0x01
+#define MIDI_CC_DataEntry       0x06
+#define MIDI_CC_RPN_LSB         0x64
+#define MIDI_CC_RPN_MSB         0x65
+
+#define MIDI_MM_AllSoundOff     0x78
+#define MIDI_MM_ResetAllControl 0x79
+#define MIDI_MM_AllNoteOff      0x7B
+
+//-------------------------------------------------------------
+// Global variables
+
+unsigned char    gPlayNoteBuf[MAX_CH];
+unsigned char    gGateBuf[MAX_CH];
+unsigned char    gPitchBendBuf[MAX_CH];
+unsigned char    gModWheelBuf[MAX_CH];
+unsigned char    gMIDISYNC_CLK;
+unsigned char    gMIDISYNC_RUN;
+
+unsigned char    NoteCnt[MAX_CH];
+unsigned char    NoteBuf[MAX_CH][MAX_NOTE_CNT];
+
+unsigned char    RxByte;
+unsigned char    SysEx;
+unsigned char    MidiCh;
+unsigned char    PC;
+unsigned char    MByte[2];
+
+//-------------------------------------------------------------
+// Functions
+
+void MIDI_Parser(unsigned char);
+int  MIDI_SystemMessage(void);
+void MIDI_SystemRealtimeMessage(void);
+void MIDI_ChannelMessage(void);
+void NoteON(void);
+void NoteOFF(void);
+
+#endif