mbed USBHostMIDI improved. function pointer initialization and null checking
Embed:
(wiki syntax)
Show/hide line numbers
USBHostMIDI.cpp
00001 /* Copyright (c) 2014 mbed.org, MIT License 00002 * 00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00004 * and associated documentation files (the "Software"), to deal in the Software without 00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish, 00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 00007 * Software is furnished to do so, subject to the following conditions: 00008 * 00009 * The above copyright notice and this permission notice shall be included in all copies or 00010 * substantial portions of the Software. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00017 */ 00018 00019 #include "USBHostMIDI.h" 00020 00021 #if USBHOST_MIDI 00022 00023 #include "dbg.h" 00024 00025 #define SET_LINE_CODING 0x20 00026 00027 USBHostMIDI::USBHostMIDI() : 00028 miscellaneousFunctionCode(NULL), 00029 cableEvent(NULL), 00030 systemCommonTwoBytes(NULL), 00031 systemCommonThreeBytes(NULL), 00032 systemExclusive(NULL), 00033 noteOff(NULL), 00034 noteOn(NULL), 00035 polyKeyPress(NULL), 00036 controlChange(NULL), 00037 programChange(NULL), 00038 channelPressure(NULL), 00039 pitchBend(NULL), 00040 singleByte(NULL) { 00041 host = USBHost::getHostInst(); 00042 size_bulk_in = 0; 00043 size_bulk_out = 0; 00044 init(); 00045 } 00046 00047 void USBHostMIDI::init() { 00048 dev = NULL; 00049 bulk_in = NULL; 00050 bulk_out = NULL; 00051 dev_connected = false; 00052 midi_intf = -1; 00053 midi_device_found = false; 00054 sysExBufferPos = 0; 00055 } 00056 00057 bool USBHostMIDI::connected() { 00058 return dev_connected; 00059 } 00060 00061 bool USBHostMIDI::connect() { 00062 if (dev_connected) { 00063 return true; 00064 } 00065 00066 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00067 if ((dev = host->getDevice(i)) != NULL) { 00068 00069 USB_DBG("Trying to connect MIDI device\r\n"); 00070 00071 if (host->enumerate(dev, this)) { 00072 break; 00073 } 00074 00075 if (midi_device_found) { 00076 bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN); 00077 bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT); 00078 00079 if (!bulk_in || !bulk_out) { 00080 break; 00081 } 00082 00083 USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf); 00084 dev->setName("MIDI", midi_intf); 00085 host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init); 00086 00087 size_bulk_in = bulk_in->getSize(); 00088 size_bulk_out = bulk_out->getSize(); 00089 00090 bulk_in->attach(this, &USBHostMIDI::rxHandler); 00091 00092 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); 00093 dev_connected = true; 00094 return true; 00095 } 00096 } 00097 } 00098 00099 init(); 00100 return false; 00101 } 00102 00103 void USBHostMIDI::rxHandler() { 00104 uint8_t *midi; 00105 if (bulk_in) { 00106 int length = bulk_in->getLengthTransferred(); 00107 if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) { 00108 // MIDI event handling 00109 for (int i = 0; i < length; i += 4) { 00110 if (i + 4 > length) { 00111 // length shortage, ignored. 00112 break; 00113 } 00114 00115 // read each four bytes 00116 midi = &buf[i]; 00117 // process MIDI message 00118 // switch by code index number 00119 switch (midi[0] & 0xf) { 00120 case 0: // miscellaneous function codes 00121 if (miscellaneousFunctionCode) { 00122 miscellaneousFunctionCode(midi[1], midi[2], midi[3]); 00123 } 00124 break; 00125 case 1: // cable events 00126 if (cableEvent) { 00127 cableEvent(midi[1], midi[2], midi[3]); 00128 } 00129 break; 00130 case 2: // two bytes system common messages 00131 if (systemCommonTwoBytes) { 00132 systemCommonTwoBytes(midi[1], midi[2]); 00133 } 00134 break; 00135 case 3: // three bytes system common messages 00136 if (systemCommonThreeBytes) { 00137 systemCommonThreeBytes(midi[1], midi[2], midi[3]); 00138 } 00139 break; 00140 case 4: // SysEx starts or continues 00141 sysExBuffer[sysExBufferPos++] = midi[1]; 00142 if (sysExBufferPos >= 64) { 00143 if (systemExclusive) { 00144 systemExclusive(sysExBuffer, sysExBufferPos, true); 00145 } 00146 sysExBufferPos = 0; 00147 } 00148 sysExBuffer[sysExBufferPos++] = midi[2]; 00149 if (sysExBufferPos >= 64) { 00150 if (systemExclusive) { 00151 systemExclusive(sysExBuffer, sysExBufferPos, true); 00152 } 00153 sysExBufferPos = 0; 00154 } 00155 sysExBuffer[sysExBufferPos++] = midi[3]; 00156 // SysEx continues. don't send 00157 break; 00158 case 5: // SysEx ends with single byte 00159 sysExBuffer[sysExBufferPos++] = midi[1]; 00160 if (systemExclusive) { 00161 systemExclusive(sysExBuffer, sysExBufferPos, false); 00162 } 00163 sysExBufferPos = 0; 00164 break; 00165 case 6: // SysEx ends with two bytes 00166 sysExBuffer[sysExBufferPos++] = midi[1]; 00167 if (sysExBufferPos >= 64) { 00168 if (systemExclusive) { 00169 systemExclusive(sysExBuffer, sysExBufferPos, true); 00170 } 00171 sysExBufferPos = 0; 00172 } 00173 sysExBuffer[sysExBufferPos++] = midi[2]; 00174 00175 if (systemExclusive) { 00176 systemExclusive(sysExBuffer, sysExBufferPos, false); 00177 } 00178 sysExBufferPos = 0; 00179 break; 00180 case 7: // SysEx ends with three bytes 00181 sysExBuffer[sysExBufferPos++] = midi[1]; 00182 if (sysExBufferPos >= 64) { 00183 if (systemExclusive) { 00184 systemExclusive(sysExBuffer, sysExBufferPos, true); 00185 } 00186 sysExBufferPos = 0; 00187 } 00188 sysExBuffer[sysExBufferPos++] = midi[2]; 00189 if (sysExBufferPos >= 64) { 00190 if (systemExclusive) { 00191 systemExclusive(sysExBuffer, sysExBufferPos, true); 00192 } 00193 sysExBufferPos = 0; 00194 } 00195 sysExBuffer[sysExBufferPos++] = midi[3]; 00196 00197 if (systemExclusive) { 00198 systemExclusive(sysExBuffer, sysExBufferPos, false); 00199 } 00200 sysExBufferPos = 0; 00201 break; 00202 case 8: 00203 if (noteOff) { 00204 noteOff(midi[1] & 0xf, midi[2], midi[3]); 00205 } 00206 break; 00207 case 9: 00208 if (midi[3]) { 00209 if (noteOn) { 00210 noteOn(midi[1] & 0xf, midi[2], midi[3]); 00211 } 00212 } else { 00213 if (noteOff) { 00214 noteOff(midi[1] & 0xf, midi[2], midi[3]); 00215 } 00216 } 00217 break; 00218 case 10: 00219 if (polyKeyPress) { 00220 polyKeyPress(midi[1] & 0xf, midi[2], midi[3]); 00221 } 00222 break; 00223 case 11: 00224 if (controlChange) { 00225 controlChange(midi[1] & 0xf, midi[2], midi[3]); 00226 } 00227 break; 00228 case 12: 00229 if (programChange) { 00230 programChange(midi[1] & 0xf, midi[2]); 00231 } 00232 break; 00233 case 13: 00234 if (channelPressure) { 00235 channelPressure(midi[1] & 0xf, midi[2]); 00236 } 00237 break; 00238 case 14: 00239 if (pitchBend) { 00240 pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7)); 00241 } 00242 break; 00243 case 15: 00244 if (singleByte) { 00245 singleByte(midi[1]); 00246 } 00247 break; 00248 } 00249 } 00250 00251 // read another message 00252 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); 00253 } 00254 } 00255 } 00256 00257 bool USBHostMIDI::sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) { 00258 if (bulk_out) { 00259 uint8_t midi[4]; 00260 00261 midi[0] = data0; 00262 midi[1] = data1; 00263 midi[2] = data2; 00264 midi[3] = data3; 00265 if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { 00266 return true; 00267 } 00268 } 00269 return false; 00270 } 00271 00272 bool USBHostMIDI::sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3) { 00273 return sendMidiBuffer(0, data1, data2, data3); 00274 } 00275 00276 bool USBHostMIDI::sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3) { 00277 return sendMidiBuffer(1, data1, data2, data3); 00278 } 00279 00280 bool USBHostMIDI::sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2) { 00281 return sendMidiBuffer(2, data1, data2, 0); 00282 } 00283 00284 bool USBHostMIDI::sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3) { 00285 return sendMidiBuffer(3, data1, data2, 0); 00286 } 00287 00288 bool USBHostMIDI::sendSystemExclusive(uint8_t *buffer, int length) { 00289 uint8_t midi[64]; 00290 int midiLength; 00291 int midiPos; 00292 if (bulk_out) { 00293 for (int i = 0; i < length; i += 48) { 00294 if (i + 48 >= length) { 00295 // contains last data 00296 midiLength = (((length - i) + 2) / 3) * 4; 00297 for (int pos = i; pos < length; pos += 3) { 00298 midiPos = (pos + 2) / 3 * 4; 00299 if (pos + 3 >= length) { 00300 // last data 00301 switch (pos % 3) { 00302 case 0: 00303 midi[midiPos ] = 7; 00304 midi[midiPos + 1] = buffer[pos ]; 00305 midi[midiPos + 2] = buffer[pos + 1]; 00306 midi[midiPos + 3] = buffer[pos + 2]; 00307 break; 00308 case 1: 00309 midi[midiPos ] = 5; 00310 midi[midiPos + 1] = buffer[pos ]; 00311 midi[midiPos + 2] = 0; 00312 midi[midiPos + 3] = 0; 00313 break; 00314 case 2: 00315 midi[midiPos ] = 6; 00316 midi[midiPos + 1] = buffer[pos ]; 00317 midi[midiPos + 2] = buffer[pos + 1]; 00318 midi[midiPos + 3] = 0; 00319 break; 00320 } 00321 } else { 00322 // has more data 00323 midi[midiPos ] = 4; 00324 midi[midiPos + 1] = buffer[pos ]; 00325 midi[midiPos + 2] = buffer[pos + 1]; 00326 midi[midiPos + 3] = buffer[pos + 2]; 00327 } 00328 } 00329 } else { 00330 // has more data 00331 midiLength = 64; 00332 for (int pos = i; pos < length; pos += 3) { 00333 midiPos = (pos + 2) / 3 * 4; 00334 midi[midiPos ] = 4; 00335 midi[midiPos + 1] = buffer[pos ]; 00336 midi[midiPos + 2] = buffer[pos + 1]; 00337 midi[midiPos + 3] = buffer[pos + 2]; 00338 } 00339 } 00340 00341 if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, midiLength) != USB_TYPE_OK) { 00342 return false; 00343 } 00344 } 00345 return true; 00346 } 00347 return false; 00348 } 00349 00350 bool USBHostMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) { 00351 return sendMidiBuffer(8, channel & 0xf | 0x80, note & 0x7f, velocity & 0x7f); 00352 } 00353 00354 bool USBHostMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { 00355 return sendMidiBuffer(9, channel & 0xf | 0x90, note & 0x7f, velocity & 0x7f); 00356 } 00357 00358 bool USBHostMIDI::sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure) { 00359 return sendMidiBuffer(10, channel & 0xf | 0xa0, note & 0x7f, pressure & 0x7f); 00360 } 00361 00362 bool USBHostMIDI::sendControlChange(uint8_t channel, uint8_t key, uint8_t value) { 00363 return sendMidiBuffer(11, channel & 0xf | 0xb0, key & 0x7f, value & 0x7f); 00364 } 00365 00366 bool USBHostMIDI::sendProgramChange(uint8_t channel, uint8_t program) { 00367 return sendMidiBuffer(12, channel & 0xf | 0xc0, program & 0x7f, 0); 00368 } 00369 00370 bool USBHostMIDI::sendChannelPressure(uint8_t channel, uint8_t pressure) { 00371 return sendMidiBuffer(13, channel & 0xf | 0xd0, pressure & 0x7f, 0); 00372 } 00373 00374 bool USBHostMIDI::sendPitchBend(uint8_t channel, uint16_t value) { 00375 return sendMidiBuffer(14, channel & 0xf | 0xe0, value & 0x7f, (value >> 7) & 0x7f); 00376 } 00377 00378 bool USBHostMIDI::sendSingleByte(uint8_t data) { 00379 return sendMidiBuffer(15, data, 0, 0); 00380 } 00381 00382 /*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid) 00383 { 00384 // we don't check VID/PID for this driver 00385 } 00386 00387 /*virtual*/ bool USBHostMIDI::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed 00388 { 00389 // USB MIDI class/subclass 00390 if ((midi_intf == -1) && 00391 (intf_class == AUDIO_CLASS) && 00392 (intf_subclass == 0x03)) { 00393 midi_intf = intf_nb; 00394 return true; 00395 } 00396 00397 // vendor specific device 00398 if ((midi_intf == -1) && 00399 (intf_class == 0xff) && 00400 (intf_subclass == 0x03)) { 00401 midi_intf = intf_nb; 00402 return true; 00403 } 00404 00405 return false; 00406 } 00407 00408 /*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used 00409 { 00410 if (intf_nb == midi_intf) { 00411 if (type == BULK_ENDPOINT) { 00412 midi_device_found = true; 00413 return true; 00414 } 00415 } 00416 return false; 00417 } 00418 00419 #endif
Generated on Thu Jul 14 2022 01:07:34 by
1.7.2