12-polyphonic "chiptune" MIDI synthesizer for LPC1768 (Standalone version)
Dependencies: ClockControl PowerControl mbed
Diff: parser.cpp
- Revision:
- 0:727737138ac5
- Child:
- 1:5f0c89bffec1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parser.cpp Sun Nov 09 08:00:33 2014 +0000 @@ -0,0 +1,236 @@ +#include <stdarg.h> +#include "mbed.h" +#include "defs.h" +#include "RingBuffer.h" +#include "debug.h" +#include "events.h" +#include "parser.h" + +extern Serial console; +extern bool serSource; +extern dumpmode_t dumpMode; +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 messageBytes[3]; + 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.getItemCount() >= 3 - runningStatus) { + messageBytes[0] = runningStatus ? c : *buffer.read(); + for (uint8_t i = 1; i < 3; i++) { + messageBytes[i] = *buffer.read(); + } + if (dumpMode == DUMP_EVENTS) { + console.printf("%-19s %c%02X %02X %02Xh\r\n", + "Note off", runningStatus ? '*' : ' ', + messageBytes[0], messageBytes[1], messageBytes[2]); + } + dispatchNoteOff(messageBytes); + lastStatusByte = c; + } + break; + case 0x90: // Note on + if (buffer.getItemCount() >= 3 - runningStatus) { + messageBytes[0] = runningStatus ? c : *buffer.read(); + for (uint8_t i = 1; i < 3; i++) { + messageBytes[i] = *buffer.read(); + } + if (dumpMode == DUMP_EVENTS) { + console.printf("%-19s %c%02X %02X %02Xh\r\n", + "Note on", runningStatus ? '*' : ' ', + messageBytes[0], messageBytes[1], messageBytes[2]); + } + if (messageBytes[2] == 0x00) { + dispatchNoteOff(messageBytes); + } else { + dispatchNoteOn(messageBytes); + } + lastStatusByte = c; + } + break; + case 0xa0: // Polyphonic pressure + // Not supported + if (buffer.getItemCount() >= 3 - runningStatus) { + messageBytes[0] = runningStatus ? c : *buffer.read(); + for (uint8_t i = 1; i < 3; i++) { + messageBytes[i] = *buffer.read(); + } + if (dumpMode == DUMP_EVENTS) { + console.printf("%-19s %c%02X %02X %02Xh\r\n", + "Poly pressure", runningStatus ? '*' : ' ', + messageBytes[0], messageBytes[1], messageBytes[2]); + } + lastStatusByte = c; + } + break; + case 0xb0: // Control change + if (buffer.getItemCount() >= 3 - runningStatus) { + messageBytes[0] = runningStatus ? c : *buffer.read(); + for (uint8_t i = 1; i < 3; i++) { + messageBytes[i] = *buffer.read(); + } + if (dumpMode == DUMP_EVENTS) { + console.printf("%-19s %c%02X %02X %02Xh\r\n", + "Control change", runningStatus ? '*' : ' ', + messageBytes[0], messageBytes[1], messageBytes[2]); + } + switch (messageBytes[1]) { + case 0x78: // All sound off + case 0x7b: // All note off + allNoteOff(messageBytes); + break; + default: + sendControlChange(messageBytes); + break; + } + lastStatusByte = c; + } + break; + case 0xc0: // Program change + if (buffer.getItemCount() >= 2 - runningStatus) { + messageBytes[0] = runningStatus ? c : *buffer.read(); + for (uint8_t i = 1; i < 2; i++) { + messageBytes[i] = *buffer.read(); + } + if (dumpMode == DUMP_EVENTS) { + console.printf("%-19s %c%02X %02X __h\r\n", + "Program change", runningStatus ? '*' : ' ', + messageBytes[0], messageBytes[1]); + } + sendProgramChange(messageBytes); + lastStatusByte = c; + } + break; + case 0xd0: // Channel pressure + // Not supported + if (buffer.getItemCount() >= 2 - runningStatus) { + messageBytes[0] = runningStatus ? c : *buffer.read(); + for (uint8_t i = 1; i < 2; i++) { + messageBytes[i] = *buffer.read(); + } + if (dumpMode == DUMP_EVENTS) { + console.printf("%-19s %c%02X %02X __h\r\n", + "Ch pressure", runningStatus ? '*' : ' ', + messageBytes[0], messageBytes[1]); + } + lastStatusByte = c; + } + break; + case 0xe0: // Pitch bend + if (buffer.getItemCount() >= 3 - runningStatus) { + messageBytes[0] = runningStatus ? c : *buffer.read(); + for (uint8_t i = 1; i < 3; i++) { + messageBytes[i] = *buffer.read(); + } + if (dumpMode == DUMP_EVENTS) { + console.printf("%-19s %c%02X %02X %02Xh\r\n", + "Pitch bend", runningStatus ? '*' : ' ', + messageBytes[0], messageBytes[1], messageBytes[2]); + } + sendPitchBend(messageBytes); + lastStatusByte = c; + } + break; + case 0xf0: + switch (c) { + case 0xf0: // SysEx message + if (buffer.find(0xf7) == -1) { + break; + } + + // Extract "F0 ** F7h" message block from buffer + extractSysExMessage(buffer, sysExBuffer); + if (strncmp(sysExBuffer, sysExGmSystemOn, 6) == 0) { + // Matches "GM System On" SysEx message + if (dumpMode == DUMP_EVENTS) { + console.printf("SysEx message: GM System On\r\n"); + } + sendSystemReset(); + } else if (strncmp(sysExBuffer, sysExGsReset, 11) == 0) { + // Matches "GS Reset" SysEx message + if (dumpMode == DUMP_EVENTS) { + console.printf("SysEx message: GS Reset\r\n"); + } + sendSystemReset(); + } else if (strncmp(sysExBuffer, sysExXgSystemOn, 9) == 0) { + // Matches "XG System On" SysEx message + if (dumpMode == DUMP_EVENTS) { + console.printf("SysEx message: XG System On\r\n"); + } + sendSystemReset(); + } else { + if (dumpMode == DUMP_EVENTS) { + console.printf("Unsupported SysEx message\r\n"); + } + } + break; + case 0xf1: // MTC quarter frame + case 0xf3: // Song select + // Not supported + buffer.read(); + buffer.read(); + break; + case 0xf2: // Song position + // Not supported + buffer.read(); + buffer.read(); + buffer.read(); + 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(); + break; + case 0xfe: // Active sensing + buffer.read(); + break; + case 0xff: // System reset + // Discard message (@todo) + buffer.read(); + sendSystemReset(); + } + } +} + +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; +}