MIDI interpreter using mbed

Dependencies:   MIDI TextLCD mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers parser.cpp Source File

parser.cpp

00001 #include "mbed.h"
00002 
00003 #include "define.h"
00004 #include "RingBuffer.h"
00005 #include "events.h"
00006 #include "parser.h"
00007 
00008 extern BusOut obLeds;
00009 #ifdef USE_PC_SERIAL
00010 extern Serial pc;
00011 #endif
00012 
00013 char const sysExGmSystemOn[6] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 };
00014 char const sysExGsReset[11]   = { 0xf0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7 };
00015 char const sysExXgSystemOn[9] = { 0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7 };
00016 
00017 
00018 void parseMessage(RingBuffer<char>& buffer) {
00019     static char lastStatusByte;
00020     char c;
00021     char dataBytes[2];
00022     char sysExBuffer[SYSEX_BUFFER_LENGTH];
00023     bool runningStatus = false;
00024     
00025     c = *buffer.peek();
00026     
00027     // Running status
00028     if (!(c & 0x80)) {
00029         runningStatus = true;
00030         // Restore previous status byte
00031         c = lastStatusByte;
00032     }
00033     
00034     switch (c & 0xf0) {
00035     case 0x80:  /* Note off */
00036         if (buffer.items() >= 3 - runningStatus) {
00037             if (!runningStatus) buffer.read();
00038             for (uint8_t i = 0; i < 2; i++) {
00039                 dataBytes[i] = *buffer.read();
00040             }
00041             #ifdef USE_PC_SERIAL
00042             pc.printf("%-19s %c%02X %02X %02Xh\r\n",
00043                       "Note off", runningStatus ? '*' : ' ',
00044                       c, dataBytes[0], dataBytes[1]);
00045             #endif
00046             
00047             dispatchNoteOff(c, dataBytes[0]);
00048             lastStatusByte = c;
00049         }
00050         break;
00051     case 0x90:  /* Note on */
00052         if (buffer.items() >= 3 - runningStatus) {
00053             if (!runningStatus) buffer.read();
00054             for (uint8_t i = 0; i < 2; i++) {
00055                 dataBytes[i] = *buffer.read();
00056             }
00057             #ifdef USE_PC_SERIAL
00058             pc.printf("%-19s %c%02X %02X %02Xh\r\n",
00059                       "Note on", runningStatus ? '*' : ' ',
00060                       c, dataBytes[0], dataBytes[1]);
00061             #endif
00062             
00063             if (dataBytes[1] == 0x00) {
00064                 dispatchNoteOff(c, dataBytes[0]);
00065             } else {
00066                 dispatchNoteOn(c, dataBytes[0], dataBytes[1]);
00067             }
00068             lastStatusByte = c;
00069         }
00070         break;
00071     case 0xa0:  /* Polyphonic pressure */
00072         // Not supported
00073         if (buffer.items() >= 3 - runningStatus) {
00074             if (!runningStatus) buffer.read();
00075             for (uint8_t i = 0; i < 2; i++) {
00076                 dataBytes[i] = *buffer.read();
00077             }
00078             #ifdef USE_PC_SERIAL
00079             pc.printf("%-19s %c%02X %02X %02Xh\r\n",
00080                       "Poly pressure", runningStatus ? '*' : ' ',
00081                       c, dataBytes[0], dataBytes[1]);
00082             #endif
00083             lastStatusByte = c;
00084         }
00085         break;
00086     case 0xb0:  /* Control change */
00087         if (buffer.items() >= 3 - runningStatus) {
00088             if (!runningStatus) buffer.read();
00089             for (uint8_t i = 0; i < 2; i++) {
00090                 dataBytes[i] = *buffer.read();
00091             }
00092             #ifdef USE_PC_SERIAL
00093             pc.printf("%-19s %c%02X %02X %02Xh\r\n",
00094                       "Control change", runningStatus ? '*' : ' ',
00095                       c, dataBytes[0], dataBytes[1]);
00096             #endif
00097             setControlChange(c, dataBytes[0], dataBytes[1]);
00098             lastStatusByte = c;
00099         }
00100         break;
00101     case 0xc0:  /* Program change */
00102         if (buffer.items() >= 3 - runningStatus) {
00103             if (!runningStatus) buffer.read();
00104             for (uint8_t i = 0; i < 2; i++) {
00105                 dataBytes[i] = *buffer.read();
00106             }
00107             #ifdef USE_PC_SERIAL
00108             pc.printf("%-19s %c%02X %02X __h\r\n",
00109                       "Program change", runningStatus ? '*' : ' ',
00110                       c, dataBytes[0]);
00111             #endif
00112             setProgramChange(c, dataBytes[0]);
00113             lastStatusByte = c;
00114         }
00115         break;
00116     case 0xd0:  /* Channel pressure */
00117         // Not supported
00118         if (buffer.items() >= 3 - runningStatus) {
00119             if (!runningStatus) buffer.read();
00120             for (uint8_t i = 0; i < 2; i++) {
00121                 dataBytes[i] = *buffer.read();
00122             }
00123             #ifdef USE_PC_SERIAL
00124             pc.printf("%-19s %c%02X %02X __h\r\n",
00125                       "Ch pressure", runningStatus ? '*' : ' ',
00126                       c, dataBytes[0]);
00127             #endif
00128             lastStatusByte = c;
00129         }
00130         break;
00131     case 0xe0:  /* Pitch bend */
00132         if (buffer.items() >= 3 - runningStatus) {
00133             if (!runningStatus) buffer.read();
00134             for (uint8_t i = 0; i < 2; i++) {
00135                 dataBytes[i] = *buffer.read();
00136             }
00137             #ifdef USE_PC_SERIAL
00138             pc.printf("%-19s %c%02X %02X %02Xh\r\n",
00139                       "Pitch bend", runningStatus ? '*' : ' ',
00140                       c, dataBytes[0], dataBytes[1]);
00141             #endif
00142             setPitchBend(c, dataBytes[1] << 7 | dataBytes[0]);
00143             lastStatusByte = c;
00144         }
00145         break;
00146     case 0xf0:
00147         switch (c) {
00148         case 0xf0:  /* SysEx message */
00149             if (buffer.find(0xf7) == -1) {
00150                 break;
00151             }
00152             
00153             extractSysExMessage(buffer, sysExBuffer);
00154             if (strncmp(sysExBuffer, sysExGmSystemOn, 6) == 0) {
00155                 // Matches "GM System On" SysEx message
00156                 #ifdef USE_PC_SERIAL
00157                 pc.printf("SysEx message: GM System On\r\n");
00158                 #endif
00159                 obLeds = 0x1;
00160             } else if (strncmp(sysExBuffer, sysExGsReset, 11) == 0) {
00161                 // Matches "GS Reset" SysEx message
00162                 #ifdef USE_PC_SERIAL
00163                 pc.printf("SysEx message: GS Reset\r\n");
00164                 #endif
00165                 obLeds = 0x2;
00166             } else if (strncmp(sysExBuffer, sysExXgSystemOn, 9) == 0) {
00167                 // Matches "XG System On" SysEx message
00168                 #ifdef USE_PC_SERIAL
00169                 pc.printf("SysEx message: XG System On\r\n");
00170                 #endif
00171                 obLeds = 0x2;
00172             } else {
00173                 #ifdef USE_PC_SERIAL
00174                 pc.printf("Unsupported SysEx message\r\n");
00175                 #endif
00176             }
00177             break;
00178         case 0xf1:  /* MTC quarter frame */
00179         case 0xf3:  /* Song select */
00180             // Not supported
00181             buffer.read();
00182             buffer.read();
00183             obLeds = 0x0;
00184             break;
00185         case 0xf2:  /* Song position */
00186             // Not supported
00187             buffer.read();
00188             buffer.read();
00189             buffer.read();
00190             obLeds = 0x0;
00191             break;
00192         case 0xf4: case 0xf5: case 0xf9: case 0xfd:  /* Undefined */
00193         case 0xf6:  /* Tune request */
00194         case 0xfa:  /* Start */
00195         case 0xfb:  /* Continue */
00196         case 0xfc:  /* Stop */
00197             buffer.read();
00198             obLeds = 0x0;
00199             break;
00200         case 0xfe:  /* Active sensing */
00201             break;
00202         case 0xff:  /* System reset */
00203             // Discard message (@todo)
00204             buffer.read();
00205             obLeds = 0x0;
00206         }
00207     }
00208 }
00209 
00210 uint32_t extractSysExMessage(RingBuffer<char>& buffer, char* msg) {
00211     uint32_t extractedLength;
00212     char* c = NULL;
00213     
00214     // Check if the first byte matches SysEx start byte (0xf0)
00215     c = buffer.read();
00216     if (!c) return 0;
00217     if (*c != 0xf0) {
00218         return 0;
00219     } else {
00220         msg[0] = *c;
00221     }
00222     
00223     // Read buffer until reaching SysEx end byte (0xf7)
00224     extractedLength = 1;
00225     while (extractedLength < SYSEX_BUFFER_LENGTH) {
00226         c = buffer.read();
00227         if (!c) break;
00228         
00229         msg[extractedLength++] = *c;
00230         if (*c == 0xf7) return extractedLength;
00231     }
00232     return 0;
00233 }