MIDI interpreter using mbed
Dependencies: MIDI TextLCD mbed
Diff: parser.cpp
- Revision:
- 0:93868ff6d1b1
- Child:
- 1:af9dd50ffbc2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parser.cpp Fri Jun 14 09:25:58 2013 +0000 @@ -0,0 +1,233 @@ +#include "mbed.h" + +#include "define.h" +#include "RingBuffer.h" +#include "events.h" +#include "parser.h" + +extern BusOut obLeds; +#ifdef USE_PC_SERIAL +extern Serial pc; +#endif + +char const sysExGmSystemOn[6] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 }; +char const sysExGsReset[11] = { 0xf0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7 }; +char const sysExXgSystemOn[9] = { 0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7 }; + + +void parseMessage(RingBuffer<char>& buffer) { + static char lastStatusByte; + char c; + char dataBytes[2]; + char sysExBuffer[SYSEX_BUFFER_LENGTH]; + bool runningStatus = false; + + c = *buffer.peek(); + + // Running status + if (!(c & 0x80)) { + runningStatus = true; + // Restore previous status byte + c = lastStatusByte; + } + + switch (c & 0xf0) { + case 0x80: /* Note off */ + if (buffer.items() >= 3 - runningStatus) { + if (!runningStatus) buffer.read(); + for (uint8_t i = 0; i < 2; i++) { + dataBytes[i] = *buffer.read(); + } + #ifdef USE_PC_SERIAL + pc.printf("%-19s %c%02X %02X %02Xh\r\n", + "Note off", runningStatus ? '*' : ' ', + c, dataBytes[0], dataBytes[1]); + #endif + + dispatchNoteOff(c, dataBytes[0]); + lastStatusByte = c; + } + break; + case 0x90: /* Note on */ + if (buffer.items() >= 3 - runningStatus) { + if (!runningStatus) buffer.read(); + for (uint8_t i = 0; i < 2; i++) { + dataBytes[i] = *buffer.read(); + } + #ifdef USE_PC_SERIAL + pc.printf("%-19s %c%02X %02X %02Xh\r\n", + "Note on", runningStatus ? '*' : ' ', + c, dataBytes[0], dataBytes[1]); + #endif + + if (dataBytes[1] == 0x00) { + dispatchNoteOff(c, dataBytes[0]); + } else { + dispatchNoteOn(c, dataBytes[0], dataBytes[1]); + } + lastStatusByte = c; + } + break; + case 0xa0: /* Polyphonic pressure */ + // Not supported + if (buffer.items() >= 3 - runningStatus) { + if (!runningStatus) buffer.read(); + for (uint8_t i = 0; i < 2; i++) { + dataBytes[i] = *buffer.read(); + } + #ifdef USE_PC_SERIAL + pc.printf("%-19s %c%02X %02X %02Xh\r\n", + "Poly pressure", runningStatus ? '*' : ' ', + c, dataBytes[0], dataBytes[1]); + #endif + lastStatusByte = c; + } + break; + case 0xb0: /* Control change */ + if (buffer.items() >= 3 - runningStatus) { + if (!runningStatus) buffer.read(); + for (uint8_t i = 0; i < 2; i++) { + dataBytes[i] = *buffer.read(); + } + #ifdef USE_PC_SERIAL + pc.printf("%-19s %c%02X %02X %02Xh\r\n", + "Control change", runningStatus ? '*' : ' ', + c, dataBytes[0], dataBytes[1]); + #endif + setControlChange(c, dataBytes[0], dataBytes[1]); + lastStatusByte = c; + } + break; + case 0xc0: /* Program change */ + if (buffer.items() >= 3 - runningStatus) { + if (!runningStatus) buffer.read(); + for (uint8_t i = 0; i < 2; i++) { + dataBytes[i] = *buffer.read(); + } + #ifdef USE_PC_SERIAL + pc.printf("%-19s %c%02X %02X __h\r\n", + "Program change", runningStatus ? '*' : ' ', + c, dataBytes[0]); + #endif + setProgramChange(c, dataBytes[0]); + lastStatusByte = c; + } + break; + case 0xd0: /* Channel pressure */ + // Not supported + if (buffer.items() >= 3 - runningStatus) { + if (!runningStatus) buffer.read(); + for (uint8_t i = 0; i < 2; i++) { + dataBytes[i] = *buffer.read(); + } + #ifdef USE_PC_SERIAL + pc.printf("%-19s %c%02X %02X __h\r\n", + "Ch pressure", runningStatus ? '*' : ' ', + c, dataBytes[0]); + #endif + lastStatusByte = c; + } + break; + case 0xe0: /* Pitch bend */ + if (buffer.items() >= 3 - runningStatus) { + if (!runningStatus) buffer.read(); + for (uint8_t i = 0; i < 2; i++) { + dataBytes[i] = *buffer.read(); + } + #ifdef USE_PC_SERIAL + pc.printf("%-19s %c%02X %02X %02Xh\r\n", + "Pitch bend", runningStatus ? '*' : ' ', + c, dataBytes[0], dataBytes[1]); + #endif + setPitchBend(c, dataBytes[0] << 7 | dataBytes[1]); + lastStatusByte = c; + } + break; + case 0xf0: + switch (c) { + case 0xf0: /* SysEx message */ + if (buffer.find(0xf7) == -1) { + break; + } + + extractSysExMessage(buffer, sysExBuffer); + if (strncmp(sysExBuffer, sysExGmSystemOn, 6) == 0) { + // Matches "GM System On" SysEx message + #ifdef USE_PC_SERIAL + pc.printf("SysEx message: GM System On\r\n"); + #endif + obLeds = 0x1; + } else if (strncmp(sysExBuffer, sysExGsReset, 11) == 0) { + // Matches "GS Reset" SysEx message + #ifdef USE_PC_SERIAL + pc.printf("SysEx message: GS Reset\r\n"); + #endif + obLeds = 0x2; + } else if (strncmp(sysExBuffer, sysExXgSystemOn, 9) == 0) { + // Matches "XG System On" SysEx message + #ifdef USE_PC_SERIAL + pc.printf("SysEx message: XG System On\r\n"); + #endif + obLeds = 0x2; + } else { + #ifdef USE_PC_SERIAL + pc.printf("Unsupported SysEx message\r\n"); + #endif + } + break; + case 0xf1: /* MTC quarter frame */ + case 0xf3: /* Song select */ + // Not supported + buffer.read(); + buffer.read(); + obLeds = 0x0; + break; + case 0xf2: /* Song position */ + // Not supported + buffer.read(); + buffer.read(); + buffer.read(); + obLeds = 0x0; + break; + case 0xf4: case 0xf5: case 0xf9: case 0xfd: /* Undefined */ + case 0xf6: /* Tune request */ + case 0xfa: /* Start */ + case 0xfb: /* Continue */ + case 0xfc: /* Stop */ + buffer.read(); + obLeds = 0x0; + break; + case 0xfe: /* Active sensing */ + break; + case 0xff: /* System reset */ + // Discard message (@todo) + buffer.read(); + obLeds = 0x0; + } + } +} + +uint32_t extractSysExMessage(RingBuffer<char>& buffer, char* msg) { + uint32_t extractedLength; + char* c = NULL; + + // Check if the first byte matches SysEx start byte (0xf0) + c = buffer.read(); + if (!c) return 0; + if (*c != 0xf0) { + return 0; + } else { + msg[0] = *c; + } + + // Read buffer until reaching SysEx end byte (0xf7) + extractedLength = 1; + while (extractedLength < SYSEX_BUFFER_LENGTH) { + c = buffer.read(); + if (!c) break; + + msg[extractedLength++] = *c; + if (*c == 0xf7) return extractedLength; + } + return 0; +}