Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: F401RE-USBHostMIDI_RecieveExample
Fork of F401RE-USBHost by
USBHostMIDI.cpp
00001 /* USBHostMidi library 00002 * Originaled by k.shoji 00003 * porting by Takuya Urakawa 00004 */ 00005 00006 /* mbed USBHost Library 00007 * Copyright (c) 2006-2013 ARM Limited 00008 * 00009 * Licensed under the Apache License, Version 2.0 (the "License"); 00010 * you may not use this file except in compliance with the License. 00011 * You may obtain a copy of the License at 00012 * 00013 * http://www.apache.org/licenses/LICENSE-2.0 00014 * 00015 * Unless required by applicable law or agreed to in writing, software 00016 * distributed under the License is distributed on an "AS IS" BASIS, 00017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00018 * See the License for the specific language governing permissions and 00019 * limitations under the License. 00020 */ 00021 00022 #include "USBHostMIDI.h" 00023 00024 #if USBHOST_MIDI 00025 00026 #include "dbg.h" 00027 00028 #define SET_LINE_CODING 0x20 00029 00030 USBHostMIDI::USBHostMIDI() { 00031 host = USBHost::getHostInst(); 00032 size_bulk_in = 0; 00033 size_bulk_out = 0; 00034 init(); 00035 } 00036 00037 void USBHostMIDI::init() { 00038 dev = NULL; 00039 bulk_in = NULL; 00040 bulk_out = NULL; 00041 dev_connected = false; 00042 midi_intf = -1; 00043 midi_device_found = false; 00044 sysExBufferPos = 0; 00045 00046 // init callback functions 00047 00048 miscellaneousFunctionCode = &callbackDummy3Bytes; 00049 cableEvent = callbackDummy3Bytes; 00050 systemCommonTwoBytes = &callbackDummy2Bytes; 00051 systemCommonThreeBytes = &callbackDummy3Bytes; 00052 systemExclusive = &callbackDummysystemExclusive; 00053 noteOff = &callbackDummy3Bytes; 00054 noteOn = &callbackDummy3Bytes; 00055 polyKeyPress = &callbackDummy3Bytes; 00056 controlChange = &callbackDummy3Bytes; 00057 programChange = &callbackDummy2Bytes; 00058 channelPressure = &callbackDummy2Bytes; 00059 pitchBend = &callbackDummypitchBend; 00060 singleByte = &callbackDummysingleByte; 00061 00062 } 00063 00064 bool USBHostMIDI::connected() 00065 { 00066 return dev_connected; 00067 } 00068 00069 bool USBHostMIDI::connect() { 00070 00071 if (dev_connected) { 00072 return true; 00073 } 00074 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00075 if ((dev = host->getDevice(i)) != NULL) { 00076 00077 USB_DBG("Trying to connect MIDI device\r\n"); 00078 00079 if(host->enumerate(dev, this)) 00080 break; 00081 00082 if (midi_device_found) { 00083 bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN); 00084 bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT); 00085 00086 if (!bulk_in || !bulk_out) 00087 break; 00088 00089 USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf); 00090 dev->setName("MIDI", midi_intf); 00091 host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init); 00092 00093 size_bulk_in = bulk_in->getSize(); 00094 size_bulk_out = bulk_out->getSize(); 00095 00096 bulk_in->attach(this, &USBHostMIDI::rxHandler); 00097 00098 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); 00099 dev_connected = true; 00100 return true; 00101 } 00102 } 00103 } 00104 init(); 00105 return false; 00106 } 00107 00108 void USBHostMIDI::rxHandler() { 00109 uint8_t *midi; 00110 if (bulk_in) { 00111 00112 int length = bulk_in->getLengthTransferred(); // why does this method always return 64? 00113 if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) { 00114 // MIDI event handling 00115 for (int i = 0; i < length; i += 4) { 00116 if (i + 4 > length) { 00117 // length shortage, ignored. 00118 break; 00119 } 00120 00121 // read each four bytes 00122 midi = &buf[i]; 00123 00124 // process MIDI message 00125 if (midi[0] == 0 && midi[1] == 0) { 00126 // {0,0,0,0} may be not collect data 00127 continue; 00128 } 00129 00130 USB_DBG("raw: %d, %d, %d, %d", midi[0]&0xf, midi[1], midi[2], midi[3]); 00131 // switch by code index number 00132 switch (midi[0] & 0xf) { 00133 case 0: // miscellaneous function codes 00134 if(midi[1] == 0) break; 00135 miscellaneousFunctionCode(midi[1], midi[2], midi[3]); 00136 break; 00137 case 1: // cable events 00138 cableEvent(midi[1], midi[2], midi[3]); 00139 break; 00140 case 2: // two bytes system common messages 00141 systemCommonTwoBytes(midi[1], midi[2]); 00142 break; 00143 case 3: // three bytes system common messages 00144 systemCommonThreeBytes(midi[1], midi[2], midi[3]); 00145 break; 00146 case 4: // SysEx starts or continues 00147 sysExBuffer[sysExBufferPos++] = midi[1]; 00148 if (sysExBufferPos >= 64) { 00149 systemExclusive(sysExBuffer, sysExBufferPos, true); 00150 sysExBufferPos = 0; 00151 } 00152 sysExBuffer[sysExBufferPos++] = midi[2]; 00153 if (sysExBufferPos >= 64) { 00154 systemExclusive(sysExBuffer, sysExBufferPos, true); 00155 sysExBufferPos = 0; 00156 } 00157 sysExBuffer[sysExBufferPos++] = midi[3]; 00158 // SysEx continues. don't send 00159 break; 00160 case 5: // SysEx ends with single byte 00161 sysExBuffer[sysExBufferPos++] = midi[1]; 00162 systemExclusive(sysExBuffer, sysExBufferPos, false); 00163 sysExBufferPos = 0; 00164 break; 00165 case 6: // SysEx ends with two bytes 00166 sysExBuffer[sysExBufferPos++] = midi[1]; 00167 if (sysExBufferPos >= 64) { 00168 systemExclusive(sysExBuffer, sysExBufferPos, true); 00169 sysExBufferPos = 0; 00170 } 00171 sysExBuffer[sysExBufferPos++] = midi[2]; 00172 systemExclusive(sysExBuffer, sysExBufferPos, false); 00173 sysExBufferPos = 0; 00174 break; 00175 case 7: // SysEx ends with three bytes 00176 sysExBuffer[sysExBufferPos++] = midi[1]; 00177 if (sysExBufferPos >= 64) { 00178 systemExclusive(sysExBuffer, sysExBufferPos, true); 00179 sysExBufferPos = 0; 00180 } 00181 sysExBuffer[sysExBufferPos++] = midi[2]; 00182 if (sysExBufferPos >= 64) { 00183 systemExclusive(sysExBuffer, sysExBufferPos, true); 00184 sysExBufferPos = 0; 00185 } 00186 sysExBuffer[sysExBufferPos++] = midi[3]; 00187 systemExclusive(sysExBuffer, sysExBufferPos, false); 00188 sysExBufferPos = 0; 00189 break; 00190 case 8: 00191 noteOff(midi[1] & 0xf, midi[2], midi[3]); 00192 break; 00193 case 9: 00194 if (midi[3]) { 00195 noteOn(midi[1] & 0xf, midi[2], midi[3]); 00196 } else { 00197 noteOff(midi[1] & 0xf, midi[2], midi[3]); 00198 } 00199 break; 00200 case 10: 00201 polyKeyPress(midi[1] & 0xf, midi[2], midi[3]); 00202 break; 00203 case 11: 00204 controlChange(midi[1] & 0xf, midi[2], midi[3]); 00205 break; 00206 case 12: 00207 programChange(midi[1] & 0xf, midi[2]); 00208 break; 00209 case 13: 00210 channelPressure(midi[1] & 0xf, midi[2]); 00211 break; 00212 case 14: 00213 pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7)); 00214 break; 00215 case 15: 00216 singleByte(midi[1]); 00217 break; 00218 default: break; 00219 } 00220 } 00221 00222 // read another message 00223 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); 00224 } 00225 } 00226 } 00227 00228 bool USBHostMIDI::sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) { 00229 if (bulk_out) { 00230 uint8_t midi[4]; 00231 00232 midi[0] = data0; 00233 midi[1] = data1; 00234 midi[2] = data2; 00235 midi[3] = data3; 00236 if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { 00237 return true; 00238 } 00239 } 00240 return false; 00241 } 00242 00243 bool USBHostMIDI::sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3) { 00244 return sendMidiBuffer(0, data1, data2, data3); 00245 } 00246 00247 bool USBHostMIDI::sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3) { 00248 return sendMidiBuffer(1, data1, data2, data3); 00249 } 00250 00251 bool USBHostMIDI::sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2) { 00252 return sendMidiBuffer(2, data1, data2, 0); 00253 } 00254 00255 bool USBHostMIDI::sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3) { 00256 return sendMidiBuffer(3, data1, data2, 0); 00257 } 00258 00259 bool USBHostMIDI::sendSystemExclusive(uint8_t *buffer, int length) { 00260 uint8_t midi[64]; 00261 int midiLength; 00262 int midiPos; 00263 if (bulk_out) { 00264 for (int i = 0; i < length; i += 48) { 00265 if (i + 48 >= length) { 00266 // contains last data 00267 midiLength = (((length - i) + 2) / 3) * 4; 00268 for (int pos = i; pos < length; pos += 3) { 00269 midiPos = (pos + 2) / 3 * 4; 00270 if (pos + 3 >= length) { 00271 // last data 00272 switch (pos % 3) { 00273 case 0: 00274 midi[midiPos ] = 7; 00275 midi[midiPos + 1] = buffer[pos ]; 00276 midi[midiPos + 2] = buffer[pos + 1]; 00277 midi[midiPos + 3] = buffer[pos + 2]; 00278 break; 00279 case 1: 00280 midi[midiPos ] = 5; 00281 midi[midiPos + 1] = buffer[pos ]; 00282 midi[midiPos + 2] = 0; 00283 midi[midiPos + 3] = 0; 00284 break; 00285 case 2: 00286 midi[midiPos ] = 6; 00287 midi[midiPos + 1] = buffer[pos ]; 00288 midi[midiPos + 2] = buffer[pos + 1]; 00289 midi[midiPos + 3] = 0; 00290 break; 00291 } 00292 } else { 00293 // has more data 00294 midi[midiPos ] = 4; 00295 midi[midiPos + 1] = buffer[pos ]; 00296 midi[midiPos + 2] = buffer[pos + 1]; 00297 midi[midiPos + 3] = buffer[pos + 2]; 00298 } 00299 } 00300 } else { 00301 // has more data 00302 midiLength = 64; 00303 for (int pos = i; pos < length; pos += 3) { 00304 midiPos = (pos + 2) / 3 * 4; 00305 midi[midiPos ] = 4; 00306 midi[midiPos + 1] = buffer[pos ]; 00307 midi[midiPos + 2] = buffer[pos + 1]; 00308 midi[midiPos + 3] = buffer[pos + 2]; 00309 } 00310 } 00311 00312 if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, midiLength) != USB_TYPE_OK) { 00313 return false; 00314 } 00315 } 00316 return true; 00317 } 00318 return false; 00319 } 00320 00321 bool USBHostMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) { 00322 return sendMidiBuffer(8, channel & 0xf | 0x80, note & 0x7f, velocity & 0x7f); 00323 } 00324 00325 bool USBHostMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { 00326 return sendMidiBuffer(9, channel & 0xf | 0x90, note & 0x7f, velocity & 0x7f); 00327 } 00328 00329 bool USBHostMIDI::sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure) { 00330 return sendMidiBuffer(10, channel & 0xf | 0xa0, note & 0x7f, pressure & 0x7f); 00331 } 00332 00333 bool USBHostMIDI::sendControlChange(uint8_t channel, uint8_t key, uint8_t value) { 00334 return sendMidiBuffer(11, channel & 0xf | 0xb0, key & 0x7f, value & 0x7f); 00335 } 00336 00337 bool USBHostMIDI::sendProgramChange(uint8_t channel, uint8_t program) { 00338 return sendMidiBuffer(12, channel & 0xf | 0xc0, program & 0x7f, 0); 00339 } 00340 00341 bool USBHostMIDI::sendChannelPressure(uint8_t channel, uint8_t pressure) { 00342 return sendMidiBuffer(13, channel & 0xf | 0xd0, pressure & 0x7f, 0); 00343 } 00344 00345 bool USBHostMIDI::sendPitchBend(uint8_t channel, uint16_t value) { 00346 return sendMidiBuffer(14, channel & 0xf | 0xe0, value & 0x7f, (value >> 7) & 0x7f); 00347 } 00348 00349 bool USBHostMIDI::sendSingleByte(uint8_t data) { 00350 return sendMidiBuffer(15, data, 0, 0); 00351 } 00352 00353 void callback_dummy(uint8_t firstArg, ...){ 00354 USB_DBG("Not attached command comming! %d\n", firstArg); 00355 } 00356 00357 /*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid) 00358 { 00359 // we don't check VID/PID for this driver 00360 } 00361 00362 /*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 00363 { 00364 // USB MIDI class/subclass 00365 if ((midi_intf == -1) && 00366 (intf_class == AUDIO_CLASS) && 00367 (intf_subclass == 0x03)) { 00368 midi_intf = intf_nb; 00369 return true; 00370 } 00371 00372 // vendor specific device 00373 if ((midi_intf == -1) && 00374 (intf_class == 0xff) && 00375 (intf_subclass == 0x03)) { 00376 midi_intf = intf_nb; 00377 return true; 00378 } 00379 00380 return false; 00381 } 00382 00383 /*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used 00384 { 00385 if (intf_nb == midi_intf) { 00386 if (type == BULK_ENDPOINT) { 00387 midi_device_found = true; 00388 return true; 00389 } 00390 } 00391 return false; 00392 } 00393 00394 #endif
Generated on Thu Jul 14 2022 17:06:48 by
1.7.2
