test public

Dependencies:   HttpServer_snapshot_mbed-os

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHostMIDI.cpp Source File

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     host = USBHost::getHostInst();
00029     size_bulk_in = 0;
00030     size_bulk_out = 0;
00031 #if defined(TARGET_RZ_A2XX)
00032     buf_in  = (uint8_t *)AllocNonCacheMem(64);
00033     buf_out  = (uint8_t *)AllocNonCacheMem(64);
00034 #endif
00035     init();
00036 }
00037 
00038 #if defined(TARGET_RZ_A2XX)
00039 USBHostMIDI::~USBHostMIDI() {
00040   FreeNonCacheMem(buf_in);
00041   FreeNonCacheMem(buf_out);
00042 }
00043 #endif
00044 
00045 void USBHostMIDI::init() {
00046     dev = NULL;
00047     bulk_in = NULL;
00048     bulk_out = NULL;
00049     dev_connected = false;
00050     midi_intf = -1;
00051     midi_device_found = false;
00052     sysExBufferPos = 0;
00053 }
00054 
00055 bool USBHostMIDI::connected() {
00056     return dev_connected;
00057 }
00058 
00059 bool USBHostMIDI::connect() {
00060     if (dev_connected) {
00061         return true;
00062     }
00063 
00064     for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
00065         if ((dev = host->getDevice(i)) != NULL) {
00066             
00067             USB_DBG("Trying to connect MIDI device\r\n");
00068 
00069             if (host->enumerate(dev, this)) {
00070                 break;
00071             }
00072             
00073             if (midi_device_found) {
00074                 bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN);
00075                 bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT);
00076                 
00077                 if (!bulk_in || !bulk_out) {
00078                     break;
00079                 }
00080                 
00081                 USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf);
00082                 dev->setName("MIDI", midi_intf);
00083                 host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init);
00084                 
00085                 size_bulk_in = bulk_in->getSize();
00086                 size_bulk_out = bulk_out->getSize();
00087                 
00088                 bulk_in->attach(this, &USBHostMIDI::rxHandler);
00089                 
00090 #if defined(TARGET_RZ_A2XX)
00091                 host->bulkRead(dev, bulk_in, buf_in, size_bulk_in, false);
00092 #else
00093                 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
00094 #endif
00095                 dev_connected = true;
00096                 return true;
00097             }
00098         }
00099     }
00100 
00101     init();
00102     return false;
00103 }
00104 
00105 void USBHostMIDI::rxHandler() {
00106     uint8_t *midi;
00107     if (bulk_in) {
00108         int length = bulk_in->getLengthTransferred();
00109         if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) {
00110             // MIDI event handling
00111             for (int i = 0; i < length; i += 4) {
00112                 if (i + 4 > length) {
00113                     // length shortage, ignored.
00114                     break;
00115                 }
00116 
00117                 // read each four bytes
00118 #if defined(TARGET_RZ_A2XX)
00119                 midi = &buf_in[i];
00120 #else
00121                 midi = &buf[i];
00122 #endif
00123                 // process MIDI message
00124                 // switch by code index number
00125                 switch (midi[0] & 0xf) {
00126                     case 0: // miscellaneous function codes
00127                         miscellaneousFunctionCode(midi[1], midi[2], midi[3]);
00128                         break;
00129                     case 1: // cable events
00130                         cableEvent(midi[1], midi[2], midi[3]);
00131                         break;
00132                     case 2: // two bytes system common messages 
00133                         systemCommonTwoBytes(midi[1], midi[2]);
00134                         break;
00135                     case 3: // three bytes system common messages 
00136                         systemCommonThreeBytes(midi[1], midi[2], midi[3]);
00137                         break;
00138                     case 4: // SysEx starts or continues
00139                         sysExBuffer[sysExBufferPos++] = midi[1];
00140                         if (sysExBufferPos >= 64) {
00141                             systemExclusive(sysExBuffer, sysExBufferPos, true);
00142                             sysExBufferPos = 0;
00143                         }
00144                         sysExBuffer[sysExBufferPos++] = midi[2];
00145                         if (sysExBufferPos >= 64) {
00146                             systemExclusive(sysExBuffer, sysExBufferPos, true);
00147                             sysExBufferPos = 0;
00148                         }
00149                         sysExBuffer[sysExBufferPos++] = midi[3];
00150                         // SysEx continues. don't send
00151                         break;
00152                     case 5: // SysEx ends with single byte
00153                         sysExBuffer[sysExBufferPos++] = midi[1];
00154                         systemExclusive(sysExBuffer, sysExBufferPos, false);
00155                         sysExBufferPos = 0;
00156                         break;
00157                     case 6: // SysEx ends with two bytes
00158                         sysExBuffer[sysExBufferPos++] = midi[1];
00159                         if (sysExBufferPos >= 64) {
00160                             systemExclusive(sysExBuffer, sysExBufferPos, true);
00161                             sysExBufferPos = 0;
00162                         }
00163                         sysExBuffer[sysExBufferPos++] = midi[2];
00164                         systemExclusive(sysExBuffer, sysExBufferPos, false);
00165                         sysExBufferPos = 0;
00166                         break;
00167                     case 7: // SysEx ends with three bytes
00168                         sysExBuffer[sysExBufferPos++] = midi[1];
00169                         if (sysExBufferPos >= 64) {
00170                             systemExclusive(sysExBuffer, sysExBufferPos, true);
00171                             sysExBufferPos = 0;
00172                         }
00173                         sysExBuffer[sysExBufferPos++] = midi[2];
00174                         if (sysExBufferPos >= 64) {
00175                             systemExclusive(sysExBuffer, sysExBufferPos, true);
00176                             sysExBufferPos = 0;
00177                         }
00178                         sysExBuffer[sysExBufferPos++] = midi[3];
00179                         systemExclusive(sysExBuffer, sysExBufferPos, false);
00180                         sysExBufferPos = 0;
00181                         break;
00182                     case 8:
00183                         noteOff(midi[1] & 0xf, midi[2], midi[3]);
00184                         break;
00185                     case 9:
00186                         if (midi[3]) {
00187                             noteOn(midi[1] & 0xf, midi[2], midi[3]);
00188                         } else {
00189                             noteOff(midi[1] & 0xf, midi[2], midi[3]);
00190                         }
00191                         break;
00192                     case 10:
00193                         polyKeyPress(midi[1] & 0xf, midi[2], midi[3]);
00194                         break;
00195                     case 11:
00196                         controlChange(midi[1] & 0xf, midi[2], midi[3]);
00197                         break;
00198                     case 12:
00199                         programChange(midi[1] & 0xf, midi[2]);
00200                         break;
00201                     case 13:
00202                         channelPressure(midi[1] & 0xf, midi[2]);
00203                         break;
00204                     case 14:
00205                         pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7));
00206                         break;
00207                     case 15:
00208                         singleByte(midi[1]);
00209                         break;
00210                 }
00211             }
00212             
00213             // read another message
00214 #if defined(TARGET_RZ_A2XX)
00215             host->bulkRead(dev, bulk_in, buf_in, size_bulk_in, false);
00216 #else
00217             host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
00218 #endif
00219         }
00220     }
00221 }
00222 
00223 bool USBHostMIDI::sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) {
00224     if (bulk_out) {
00225 #if defined(TARGET_RZ_A2XX)
00226         uint8_t * midi = buf_out;
00227 #else
00228         uint8_t midi[4];
00229 #endif
00230 
00231         midi[0] = data0;
00232         midi[1] = data1;
00233         midi[2] = data2;
00234         midi[3] = data3;
00235         if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) {
00236             return true;
00237         }
00238     }
00239     return false;
00240 }
00241 
00242 bool USBHostMIDI::sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3) {
00243     return sendMidiBuffer(0, data1, data2, data3);
00244 }
00245 
00246 bool USBHostMIDI::sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3) {
00247     return sendMidiBuffer(1, data1, data2, data3);
00248 }
00249 
00250 bool USBHostMIDI::sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2) {
00251     return sendMidiBuffer(2, data1, data2, 0);
00252 }
00253 
00254 bool USBHostMIDI::sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3) {
00255     return sendMidiBuffer(3, data1, data2, 0);
00256 }
00257 
00258 bool USBHostMIDI::sendSystemExclusive(uint8_t *buffer, int length) {
00259 #if defined(TARGET_RZ_A2XX)
00260     uint8_t * midi = buf_out;
00261 #else
00262     uint8_t midi[64];
00263 #endif
00264     int midiLength;
00265     int midiPos;
00266     if (bulk_out) {
00267         for (int i = 0; i < length; i += 48) {
00268             if (i + 48 >= length) {
00269                 // contains last data
00270                 midiLength = (((length - i) + 2) / 3) * 4;
00271                 for (int pos = i; pos < length; pos += 3) {
00272                     midiPos = (pos + 2) / 3 * 4;
00273                     if (pos + 3 >= length) {
00274                         // last data
00275                         switch (pos % 3) {
00276                             case 0:
00277                                 midi[midiPos    ] = 7;
00278                                 midi[midiPos + 1] = buffer[pos    ];
00279                                 midi[midiPos + 2] = buffer[pos + 1];
00280                                 midi[midiPos + 3] = buffer[pos + 2];
00281                                 break;
00282                             case 1:
00283                                 midi[midiPos    ] = 5;
00284                                 midi[midiPos + 1] = buffer[pos    ];
00285                                 midi[midiPos + 2] = 0;
00286                                 midi[midiPos + 3] = 0;
00287                                break;
00288                             case 2:
00289                                 midi[midiPos    ] = 6;
00290                                 midi[midiPos + 1] = buffer[pos    ];
00291                                 midi[midiPos + 2] = buffer[pos + 1];
00292                                 midi[midiPos + 3] = 0;
00293                                 break;
00294                         }
00295                     } else {
00296                         // has more data
00297                         midi[midiPos    ] = 4;
00298                         midi[midiPos + 1] = buffer[pos    ];
00299                         midi[midiPos + 2] = buffer[pos + 1];
00300                         midi[midiPos + 3] = buffer[pos + 2];
00301                     }
00302                 }
00303             } else {
00304                 // has more data
00305                 midiLength = 64;
00306                 for (int pos = i; pos < length; pos += 3) {
00307                     midiPos = (pos + 2) / 3 * 4;
00308                     midi[midiPos    ] = 4;
00309                     midi[midiPos + 1] = buffer[pos    ];
00310                     midi[midiPos + 2] = buffer[pos + 1];
00311                     midi[midiPos + 3] = buffer[pos + 2];
00312                 }
00313             }
00314 
00315             if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, midiLength) != USB_TYPE_OK) {
00316                 return false;
00317             }
00318         }
00319         return true;
00320     }
00321     return false;
00322 }
00323 
00324 bool USBHostMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
00325     return sendMidiBuffer(8, (channel & 0xf) | 0x80, note & 0x7f, velocity & 0x7f);
00326 }
00327 
00328 bool USBHostMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
00329     return sendMidiBuffer(9, (channel & 0xf) | 0x90, note & 0x7f, velocity & 0x7f);
00330 }
00331 
00332 bool USBHostMIDI::sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure) {
00333     return sendMidiBuffer(10, (channel & 0xf) | 0xa0, note & 0x7f, pressure & 0x7f);
00334 }
00335 
00336 bool USBHostMIDI::sendControlChange(uint8_t channel, uint8_t key, uint8_t value) {
00337     return sendMidiBuffer(11, (channel & 0xf) | 0xb0, key & 0x7f, value & 0x7f);
00338 }
00339 
00340 bool USBHostMIDI::sendProgramChange(uint8_t channel, uint8_t program) {
00341     return sendMidiBuffer(12, (channel & 0xf) | 0xc0, program & 0x7f, 0);
00342 }
00343 
00344 bool USBHostMIDI::sendChannelPressure(uint8_t channel, uint8_t pressure) {
00345     return sendMidiBuffer(13, (channel & 0xf) | 0xd0, pressure & 0x7f, 0);
00346 }
00347 
00348 bool USBHostMIDI::sendPitchBend(uint8_t channel, uint16_t value) {
00349     return sendMidiBuffer(14, (channel & 0xf) | 0xe0, value & 0x7f, (value >> 7) & 0x7f);
00350 }
00351 
00352 bool USBHostMIDI::sendSingleByte(uint8_t data) {
00353     return sendMidiBuffer(15, data, 0, 0);
00354 }
00355 
00356 /*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid)
00357 {
00358     // we don't check VID/PID for this driver
00359 }
00360 
00361 /*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
00362 {
00363     // USB MIDI class/subclass
00364     if ((midi_intf == -1) &&
00365         (intf_class == AUDIO_CLASS) &&
00366         (intf_subclass == 0x03)) {
00367         midi_intf = intf_nb;
00368         return true;
00369     }
00370     
00371     // vendor specific device
00372     if ((midi_intf == -1) &&
00373         (intf_class == 0xff) &&
00374         (intf_subclass == 0x03)) {
00375         midi_intf = intf_nb;
00376         return true;
00377     }
00378     
00379     return false;
00380 }
00381 
00382 /*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
00383 {
00384     if (intf_nb == midi_intf) {
00385         if (type == BULK_ENDPOINT) {
00386             midi_device_found = true;
00387             return true;
00388         }
00389     }
00390     return false;
00391 }
00392 
00393 #endif