MIDI interpreter using mbed

Dependencies:   MIDI TextLCD mbed

Committer:
kayekss
Date:
Fri Jun 14 12:41:54 2013 +0000
Revision:
1:af9dd50ffbc2
Parent:
0:93868ff6d1b1
Fixed pitchbend byte order

Who changed what in which revision?

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