Takuya Urakawa / F401RE-USBHost

Dependencies:   FATFileSystem

Dependents:   F401RE-USBHostMIDI_RecieveExample

Fork of F401RE-USBHost by Norimasa Okamoto

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHostMIDI.cpp Source File

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