12-polyphonic "chiptune" MIDI synthesizer for LPC1768 (Standalone version)
Dependencies: ClockControl PowerControl mbed
parser.cpp@6:cda45a5e723e, 2014-12-23 (annotated)
- Committer:
- kayekss
- Date:
- Tue Dec 23 21:50:53 2014 +0000
- Revision:
- 6:cda45a5e723e
- Parent:
- 5:7bc917d03bd6
Supports "Panic on offline" feature when using MIDI-port input
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kayekss | 0:727737138ac5 | 1 | #include <stdarg.h> |
kayekss | 0:727737138ac5 | 2 | #include "mbed.h" |
kayekss | 0:727737138ac5 | 3 | #include "defs.h" |
kayekss | 0:727737138ac5 | 4 | #include "RingBuffer.h" |
kayekss | 0:727737138ac5 | 5 | #include "debug.h" |
kayekss | 0:727737138ac5 | 6 | #include "events.h" |
kayekss | 0:727737138ac5 | 7 | #include "parser.h" |
kayekss | 0:727737138ac5 | 8 | |
kayekss | 0:727737138ac5 | 9 | extern Serial console; |
kayekss | 0:727737138ac5 | 10 | extern bool serSource; |
kayekss | 0:727737138ac5 | 11 | extern dumpmode_t dumpMode; |
kayekss | 0:727737138ac5 | 12 | char const sysExGmSystemOn[6] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 }; |
kayekss | 0:727737138ac5 | 13 | char const sysExGsReset[11] = { 0xf0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7 }; |
kayekss | 0:727737138ac5 | 14 | char const sysExXgSystemOn[9] = { 0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7 }; |
kayekss | 0:727737138ac5 | 15 | |
kayekss | 0:727737138ac5 | 16 | void parseMessage(RingBuffer<char>& buffer) { |
kayekss | 0:727737138ac5 | 17 | static char lastStatusByte; |
kayekss | 0:727737138ac5 | 18 | char c; |
kayekss | 0:727737138ac5 | 19 | char messageBytes[3]; |
kayekss | 0:727737138ac5 | 20 | char sysExBuffer[SYSEX_BUFFER_LENGTH]; |
kayekss | 0:727737138ac5 | 21 | bool runningStatus = false; |
kayekss | 0:727737138ac5 | 22 | |
kayekss | 0:727737138ac5 | 23 | c = *buffer.peek(); |
kayekss | 0:727737138ac5 | 24 | |
kayekss | 0:727737138ac5 | 25 | // Running status |
kayekss | 0:727737138ac5 | 26 | if (!(c & 0x80)) { |
kayekss | 0:727737138ac5 | 27 | runningStatus = true; |
kayekss | 0:727737138ac5 | 28 | // Restore previous status byte |
kayekss | 0:727737138ac5 | 29 | c = lastStatusByte; |
kayekss | 0:727737138ac5 | 30 | } |
kayekss | 0:727737138ac5 | 31 | |
kayekss | 0:727737138ac5 | 32 | switch (c & 0xf0) { |
kayekss | 0:727737138ac5 | 33 | case 0x80: // Note off |
kayekss | 0:727737138ac5 | 34 | if (buffer.getItemCount() >= 3 - runningStatus) { |
kayekss | 0:727737138ac5 | 35 | messageBytes[0] = runningStatus ? c : *buffer.read(); |
kayekss | 0:727737138ac5 | 36 | for (uint8_t i = 1; i < 3; i++) { |
kayekss | 0:727737138ac5 | 37 | messageBytes[i] = *buffer.read(); |
kayekss | 0:727737138ac5 | 38 | } |
kayekss | 0:727737138ac5 | 39 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 40 | console.printf("%-19s %c%02X %02X %02Xh\r\n", |
kayekss | 0:727737138ac5 | 41 | "Note off", runningStatus ? '*' : ' ', |
kayekss | 0:727737138ac5 | 42 | messageBytes[0], messageBytes[1], messageBytes[2]); |
kayekss | 0:727737138ac5 | 43 | } |
kayekss | 0:727737138ac5 | 44 | dispatchNoteOff(messageBytes); |
kayekss | 0:727737138ac5 | 45 | lastStatusByte = c; |
kayekss | 0:727737138ac5 | 46 | } |
kayekss | 0:727737138ac5 | 47 | break; |
kayekss | 0:727737138ac5 | 48 | case 0x90: // Note on |
kayekss | 0:727737138ac5 | 49 | if (buffer.getItemCount() >= 3 - runningStatus) { |
kayekss | 0:727737138ac5 | 50 | messageBytes[0] = runningStatus ? c : *buffer.read(); |
kayekss | 0:727737138ac5 | 51 | for (uint8_t i = 1; i < 3; i++) { |
kayekss | 0:727737138ac5 | 52 | messageBytes[i] = *buffer.read(); |
kayekss | 0:727737138ac5 | 53 | } |
kayekss | 0:727737138ac5 | 54 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 55 | console.printf("%-19s %c%02X %02X %02Xh\r\n", |
kayekss | 0:727737138ac5 | 56 | "Note on", runningStatus ? '*' : ' ', |
kayekss | 0:727737138ac5 | 57 | messageBytes[0], messageBytes[1], messageBytes[2]); |
kayekss | 0:727737138ac5 | 58 | } |
kayekss | 0:727737138ac5 | 59 | if (messageBytes[2] == 0x00) { |
kayekss | 0:727737138ac5 | 60 | dispatchNoteOff(messageBytes); |
kayekss | 0:727737138ac5 | 61 | } else { |
kayekss | 0:727737138ac5 | 62 | dispatchNoteOn(messageBytes); |
kayekss | 0:727737138ac5 | 63 | } |
kayekss | 0:727737138ac5 | 64 | lastStatusByte = c; |
kayekss | 0:727737138ac5 | 65 | } |
kayekss | 0:727737138ac5 | 66 | break; |
kayekss | 0:727737138ac5 | 67 | case 0xa0: // Polyphonic pressure |
kayekss | 0:727737138ac5 | 68 | // Not supported |
kayekss | 0:727737138ac5 | 69 | if (buffer.getItemCount() >= 3 - runningStatus) { |
kayekss | 0:727737138ac5 | 70 | messageBytes[0] = runningStatus ? c : *buffer.read(); |
kayekss | 0:727737138ac5 | 71 | for (uint8_t i = 1; i < 3; i++) { |
kayekss | 0:727737138ac5 | 72 | messageBytes[i] = *buffer.read(); |
kayekss | 0:727737138ac5 | 73 | } |
kayekss | 0:727737138ac5 | 74 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 75 | console.printf("%-19s %c%02X %02X %02Xh\r\n", |
kayekss | 0:727737138ac5 | 76 | "Poly pressure", runningStatus ? '*' : ' ', |
kayekss | 0:727737138ac5 | 77 | messageBytes[0], messageBytes[1], messageBytes[2]); |
kayekss | 0:727737138ac5 | 78 | } |
kayekss | 0:727737138ac5 | 79 | lastStatusByte = c; |
kayekss | 0:727737138ac5 | 80 | } |
kayekss | 0:727737138ac5 | 81 | break; |
kayekss | 0:727737138ac5 | 82 | case 0xb0: // Control change |
kayekss | 0:727737138ac5 | 83 | if (buffer.getItemCount() >= 3 - runningStatus) { |
kayekss | 0:727737138ac5 | 84 | messageBytes[0] = runningStatus ? c : *buffer.read(); |
kayekss | 0:727737138ac5 | 85 | for (uint8_t i = 1; i < 3; i++) { |
kayekss | 0:727737138ac5 | 86 | messageBytes[i] = *buffer.read(); |
kayekss | 0:727737138ac5 | 87 | } |
kayekss | 0:727737138ac5 | 88 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 89 | console.printf("%-19s %c%02X %02X %02Xh\r\n", |
kayekss | 0:727737138ac5 | 90 | "Control change", runningStatus ? '*' : ' ', |
kayekss | 0:727737138ac5 | 91 | messageBytes[0], messageBytes[1], messageBytes[2]); |
kayekss | 0:727737138ac5 | 92 | } |
kayekss | 0:727737138ac5 | 93 | switch (messageBytes[1]) { |
kayekss | 0:727737138ac5 | 94 | case 0x78: // All sound off |
kayekss | 0:727737138ac5 | 95 | case 0x7b: // All note off |
kayekss | 0:727737138ac5 | 96 | allNoteOff(messageBytes); |
kayekss | 0:727737138ac5 | 97 | break; |
kayekss | 5:7bc917d03bd6 | 98 | case 0x79: // Reset all controllers |
kayekss | 5:7bc917d03bd6 | 99 | resetAllControllers(messageBytes); |
kayekss | 5:7bc917d03bd6 | 100 | break; |
kayekss | 0:727737138ac5 | 101 | default: |
kayekss | 0:727737138ac5 | 102 | sendControlChange(messageBytes); |
kayekss | 0:727737138ac5 | 103 | break; |
kayekss | 0:727737138ac5 | 104 | } |
kayekss | 0:727737138ac5 | 105 | lastStatusByte = c; |
kayekss | 0:727737138ac5 | 106 | } |
kayekss | 0:727737138ac5 | 107 | break; |
kayekss | 0:727737138ac5 | 108 | case 0xc0: // Program change |
kayekss | 0:727737138ac5 | 109 | if (buffer.getItemCount() >= 2 - runningStatus) { |
kayekss | 0:727737138ac5 | 110 | messageBytes[0] = runningStatus ? c : *buffer.read(); |
kayekss | 0:727737138ac5 | 111 | for (uint8_t i = 1; i < 2; i++) { |
kayekss | 0:727737138ac5 | 112 | messageBytes[i] = *buffer.read(); |
kayekss | 0:727737138ac5 | 113 | } |
kayekss | 0:727737138ac5 | 114 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 115 | console.printf("%-19s %c%02X %02X __h\r\n", |
kayekss | 0:727737138ac5 | 116 | "Program change", runningStatus ? '*' : ' ', |
kayekss | 0:727737138ac5 | 117 | messageBytes[0], messageBytes[1]); |
kayekss | 0:727737138ac5 | 118 | } |
kayekss | 0:727737138ac5 | 119 | sendProgramChange(messageBytes); |
kayekss | 0:727737138ac5 | 120 | lastStatusByte = c; |
kayekss | 0:727737138ac5 | 121 | } |
kayekss | 0:727737138ac5 | 122 | break; |
kayekss | 0:727737138ac5 | 123 | case 0xd0: // Channel pressure |
kayekss | 0:727737138ac5 | 124 | // Not supported |
kayekss | 0:727737138ac5 | 125 | if (buffer.getItemCount() >= 2 - runningStatus) { |
kayekss | 0:727737138ac5 | 126 | messageBytes[0] = runningStatus ? c : *buffer.read(); |
kayekss | 0:727737138ac5 | 127 | for (uint8_t i = 1; i < 2; i++) { |
kayekss | 0:727737138ac5 | 128 | messageBytes[i] = *buffer.read(); |
kayekss | 0:727737138ac5 | 129 | } |
kayekss | 0:727737138ac5 | 130 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 131 | console.printf("%-19s %c%02X %02X __h\r\n", |
kayekss | 0:727737138ac5 | 132 | "Ch pressure", runningStatus ? '*' : ' ', |
kayekss | 0:727737138ac5 | 133 | messageBytes[0], messageBytes[1]); |
kayekss | 0:727737138ac5 | 134 | } |
kayekss | 0:727737138ac5 | 135 | lastStatusByte = c; |
kayekss | 0:727737138ac5 | 136 | } |
kayekss | 0:727737138ac5 | 137 | break; |
kayekss | 0:727737138ac5 | 138 | case 0xe0: // Pitch bend |
kayekss | 0:727737138ac5 | 139 | if (buffer.getItemCount() >= 3 - runningStatus) { |
kayekss | 0:727737138ac5 | 140 | messageBytes[0] = runningStatus ? c : *buffer.read(); |
kayekss | 0:727737138ac5 | 141 | for (uint8_t i = 1; i < 3; i++) { |
kayekss | 0:727737138ac5 | 142 | messageBytes[i] = *buffer.read(); |
kayekss | 0:727737138ac5 | 143 | } |
kayekss | 0:727737138ac5 | 144 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 145 | console.printf("%-19s %c%02X %02X %02Xh\r\n", |
kayekss | 0:727737138ac5 | 146 | "Pitch bend", runningStatus ? '*' : ' ', |
kayekss | 0:727737138ac5 | 147 | messageBytes[0], messageBytes[1], messageBytes[2]); |
kayekss | 0:727737138ac5 | 148 | } |
kayekss | 0:727737138ac5 | 149 | sendPitchBend(messageBytes); |
kayekss | 0:727737138ac5 | 150 | lastStatusByte = c; |
kayekss | 0:727737138ac5 | 151 | } |
kayekss | 0:727737138ac5 | 152 | break; |
kayekss | 0:727737138ac5 | 153 | case 0xf0: |
kayekss | 0:727737138ac5 | 154 | switch (c) { |
kayekss | 0:727737138ac5 | 155 | case 0xf0: // SysEx message |
kayekss | 0:727737138ac5 | 156 | if (buffer.find(0xf7) == -1) { |
kayekss | 0:727737138ac5 | 157 | break; |
kayekss | 0:727737138ac5 | 158 | } |
kayekss | 0:727737138ac5 | 159 | |
kayekss | 0:727737138ac5 | 160 | // Extract "F0 ** F7h" message block from buffer |
kayekss | 0:727737138ac5 | 161 | extractSysExMessage(buffer, sysExBuffer); |
kayekss | 0:727737138ac5 | 162 | if (strncmp(sysExBuffer, sysExGmSystemOn, 6) == 0) { |
kayekss | 0:727737138ac5 | 163 | // Matches "GM System On" SysEx message |
kayekss | 0:727737138ac5 | 164 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 165 | console.printf("SysEx message: GM System On\r\n"); |
kayekss | 0:727737138ac5 | 166 | } |
kayekss | 0:727737138ac5 | 167 | sendSystemReset(); |
kayekss | 0:727737138ac5 | 168 | } else if (strncmp(sysExBuffer, sysExGsReset, 11) == 0) { |
kayekss | 0:727737138ac5 | 169 | // Matches "GS Reset" SysEx message |
kayekss | 0:727737138ac5 | 170 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 171 | console.printf("SysEx message: GS Reset\r\n"); |
kayekss | 0:727737138ac5 | 172 | } |
kayekss | 0:727737138ac5 | 173 | sendSystemReset(); |
kayekss | 0:727737138ac5 | 174 | } else if (strncmp(sysExBuffer, sysExXgSystemOn, 9) == 0) { |
kayekss | 0:727737138ac5 | 175 | // Matches "XG System On" SysEx message |
kayekss | 0:727737138ac5 | 176 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 177 | console.printf("SysEx message: XG System On\r\n"); |
kayekss | 0:727737138ac5 | 178 | } |
kayekss | 0:727737138ac5 | 179 | sendSystemReset(); |
kayekss | 0:727737138ac5 | 180 | } else { |
kayekss | 0:727737138ac5 | 181 | if (dumpMode == DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 182 | console.printf("Unsupported SysEx message\r\n"); |
kayekss | 0:727737138ac5 | 183 | } |
kayekss | 0:727737138ac5 | 184 | } |
kayekss | 0:727737138ac5 | 185 | break; |
kayekss | 0:727737138ac5 | 186 | case 0xf1: // MTC quarter frame |
kayekss | 0:727737138ac5 | 187 | case 0xf3: // Song select |
kayekss | 0:727737138ac5 | 188 | // Not supported |
kayekss | 0:727737138ac5 | 189 | buffer.read(); |
kayekss | 0:727737138ac5 | 190 | buffer.read(); |
kayekss | 0:727737138ac5 | 191 | break; |
kayekss | 0:727737138ac5 | 192 | case 0xf2: // Song position |
kayekss | 0:727737138ac5 | 193 | // Not supported |
kayekss | 0:727737138ac5 | 194 | buffer.read(); |
kayekss | 0:727737138ac5 | 195 | buffer.read(); |
kayekss | 0:727737138ac5 | 196 | buffer.read(); |
kayekss | 0:727737138ac5 | 197 | break; |
kayekss | 0:727737138ac5 | 198 | case 0xf4: case 0xf5: case 0xf9: case 0xfd: // Undefined |
kayekss | 0:727737138ac5 | 199 | case 0xf6: // Tune request |
kayekss | 0:727737138ac5 | 200 | case 0xfa: // Start |
kayekss | 0:727737138ac5 | 201 | case 0xfb: // Continue |
kayekss | 0:727737138ac5 | 202 | case 0xfc: // Stop |
kayekss | 0:727737138ac5 | 203 | buffer.read(); |
kayekss | 0:727737138ac5 | 204 | break; |
kayekss | 0:727737138ac5 | 205 | case 0xfe: // Active sensing |
kayekss | 0:727737138ac5 | 206 | buffer.read(); |
kayekss | 0:727737138ac5 | 207 | break; |
kayekss | 0:727737138ac5 | 208 | case 0xff: // System reset |
kayekss | 1:5f0c89bffec1 | 209 | // Discard message |
kayekss | 0:727737138ac5 | 210 | buffer.read(); |
kayekss | 0:727737138ac5 | 211 | sendSystemReset(); |
kayekss | 0:727737138ac5 | 212 | } |
kayekss | 0:727737138ac5 | 213 | } |
kayekss | 0:727737138ac5 | 214 | } |
kayekss | 0:727737138ac5 | 215 | |
kayekss | 0:727737138ac5 | 216 | uint32_t extractSysExMessage(RingBuffer<char>& buffer, char* msg) { |
kayekss | 0:727737138ac5 | 217 | uint32_t extractedLength; |
kayekss | 0:727737138ac5 | 218 | char* c = NULL; |
kayekss | 0:727737138ac5 | 219 | |
kayekss | 0:727737138ac5 | 220 | // Check if the first byte matches SysEx start byte (0xf0) |
kayekss | 0:727737138ac5 | 221 | c = buffer.read(); |
kayekss | 0:727737138ac5 | 222 | if (!c) return 0; |
kayekss | 0:727737138ac5 | 223 | if (*c != 0xf0) { |
kayekss | 0:727737138ac5 | 224 | return 0; |
kayekss | 0:727737138ac5 | 225 | } else { |
kayekss | 0:727737138ac5 | 226 | msg[0] = *c; |
kayekss | 0:727737138ac5 | 227 | } |
kayekss | 0:727737138ac5 | 228 | |
kayekss | 0:727737138ac5 | 229 | // Read buffer until reaching SysEx end byte (0xf7) |
kayekss | 0:727737138ac5 | 230 | extractedLength = 1; |
kayekss | 0:727737138ac5 | 231 | while (extractedLength < SYSEX_BUFFER_LENGTH) { |
kayekss | 0:727737138ac5 | 232 | c = buffer.read(); |
kayekss | 0:727737138ac5 | 233 | if (!c) break; |
kayekss | 0:727737138ac5 | 234 | |
kayekss | 0:727737138ac5 | 235 | msg[extractedLength++] = *c; |
kayekss | 0:727737138ac5 | 236 | if (*c == 0xf7) return extractedLength; |
kayekss | 0:727737138ac5 | 237 | } |
kayekss | 0:727737138ac5 | 238 | return 0; |
kayekss | 0:727737138ac5 | 239 | } |