My Fork of F401RE-USBHost. Add USBHostMIDI functions (originaled by Kaoru Shoji http://mbed.org/users/kshoji/code/USBHostMIDI/)
Dependents: F401RE-USBHostMIDI_RecieveExample
Fork of F401RE-USBHost by
Diff: USBHostMIDI/USBHostMIDI.cpp
- Revision:
- 24:5281ea9f6e68
- Parent:
- 23:9c1d09c6a2b6
- Child:
- 26:077ab26227c6
--- a/USBHostMIDI/USBHostMIDI.cpp Wed Sep 17 14:29:11 2014 +0000 +++ b/USBHostMIDI/USBHostMIDI.cpp Thu Sep 18 10:50:22 2014 +0000 @@ -1,253 +1,366 @@ -/* USBHostMidi library - * Originaled by k.shoji - * porting by Takuya Urakawa - */ - -/* mbed USBHost Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "USBHostMIDI.h" - -#if USBHOST_MIDI - -#include "dbg.h" - -#define SET_LINE_CODING 0x20 - -USBHostMIDI::USBHostMIDI(): circ_buf() { - host = USBHost::getHostInst(); - size_bulk_in = 0; - size_bulk_out = 0; - init(); -} - -void USBHostMIDI::init() { - dev = NULL; - bulk_in = NULL; - bulk_out = NULL; - dev_connected = false; - midi_intf = -1; - midi_device_found = false; - circ_buf.flush(); -} - -bool USBHostMIDI::connected() -{ - return dev_connected; -} - -bool USBHostMIDI::connect() { - - if (dev_connected) { - return true; - } - for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { - if ((dev = host->getDevice(i)) != NULL) { - - USB_DBG("Trying to connect MIDI device\r\n"); - - if(host->enumerate(dev, this)) - break; - - if (midi_device_found) { - bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN); - bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT); - - if (!bulk_in || !bulk_out) - break; - - USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf); - dev->setName("MIDI", midi_intf); - host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init); - - size_bulk_in = bulk_in->getSize(); - size_bulk_out = bulk_out->getSize(); - - bulk_in->attach(this, &USBHostMIDI::rxHandler); - - host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); - dev_connected = true; - return true; - } - } - } - init(); - return false; -} - -void USBHostMIDI::rxHandler() { - uint8_t pos = 0; - uint8_t midi[4]; - if (bulk_in) { - int len = bulk_in->getLengthTransferred(); - if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) { - for (int i = 0; i < len; i++) { - circ_buf.queue(buf[i]); - } - - // MIDI event handling - while (!circ_buf.isEmpty()) { - // read each four bytes - circ_buf.dequeue(&midi[pos++]); - if (pos == 4) { - pos = 0; - - // process MIDI message - // switch by code index number - switch (midi[0] & 0xf) { - case 8: - noteOff(midi[1] & 0xf, midi[2], midi[3]); - break; - case 9: - if (midi[3]) { - noteOn(midi[1] & 0xf, midi[2], midi[3]); - } else { - noteOff(midi[1] & 0xf, midi[2], midi[3]); - } - break; - case 11: - controlChange(midi[1] & 0xf, midi[2], midi[3]); - break; - case 12: - programChange(midi[1] & 0xf, midi[2]); - break; - case 14: - pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7)); - break; - default: - break; - } - } - } - - host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); - } - } -} - -int USBHostMIDI::sendNoteOn(unsigned char channel, unsigned char note, unsigned char velocity) { - uint8_t midi[4]; - - if (bulk_out) { - midi[0] = 9; - midi[1] = channel & 0xf; - midi[2] = note & 0x7f; - midi[3] = velocity & 0x7f; - if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { - return 1; - } - } - return -1; -} - -int USBHostMIDI::sendNoteOff(unsigned char channel, unsigned char note, unsigned char velocity) { - uint8_t midi[4]; - - if (bulk_out) { - midi[0] = 8; - midi[1] = channel & 0xf; - midi[2] = note & 0x7f; - midi[3] = velocity & 0x7f; - if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { - return 1; - } - } - return -1; -} - -int USBHostMIDI::sendControlChange(unsigned char channel, unsigned char key, unsigned char value) { - uint8_t midi[4]; - - if (bulk_out) { - midi[0] = 11; - midi[1] = channel & 0xf; - midi[2] = key & 0x7f; - midi[3] = value & 0x7f; - if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { - return 1; - } - } - return -1; -} - -int USBHostMIDI::sendProgramChange(unsigned char channel, unsigned char program) { - uint8_t midi[4]; - - if (bulk_out) { - midi[0] = 12; - midi[1] = channel & 0xf; - midi[2] = program & 0x7f; - midi[3] = 0; - if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { - return 1; - } - } - return -1; -} - -int USBHostMIDI::sendPitchBend(unsigned char channel, unsigned int value) { - uint8_t midi[4]; - - if (bulk_out) { - midi[0] = 14; - midi[1] = channel & 0xf; - midi[2] = value & 0x7f; - midi[3] = (value >> 7) & 0x7f; - if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { - return 1; - } - } - return -1; -} - -/*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid) -{ - // we don't check VID/PID for this driver -} - -/*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 -{ - // USB MIDI class/subclass - if ((midi_intf == -1) && - (intf_class == AUDIO_CLASS) && - (intf_subclass == 0x03)) { - midi_intf = intf_nb; - return true; - } - - // vendor specific device - if ((midi_intf == -1) && - (intf_class == 0xff) && - (intf_subclass == 0x03)) { - midi_intf = intf_nb; - return true; - } - - return false; -} - -/*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used -{ - if (intf_nb == midi_intf) { - if (type == BULK_ENDPOINT) { - midi_device_found = true; - return true; - } - } - return false; -} - -#endif +/* USBHostMidi library + * Originaled by k.shoji + * porting by Takuya Urakawa + */ + +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "USBHostMIDI.h" + +#if USBHOST_MIDI + +#include "dbg.h" + +#define SET_LINE_CODING 0x20 + +USBHostMIDI::USBHostMIDI() { + host = USBHost::getHostInst(); + size_bulk_in = 0; + size_bulk_out = 0; + init(); +} + +void USBHostMIDI::init() { + dev = NULL; + bulk_in = NULL; + bulk_out = NULL; + dev_connected = false; + midi_intf = -1; + midi_device_found = false; + sysExBufferPos = 0; +} + +bool USBHostMIDI::connected() +{ + return dev_connected; +} + +bool USBHostMIDI::connect() { + + if (dev_connected) { + return true; + } + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { + if ((dev = host->getDevice(i)) != NULL) { + + USB_DBG("Trying to connect MIDI device\r\n"); + + if(host->enumerate(dev, this)) + break; + + if (midi_device_found) { + bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN); + bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT); + + if (!bulk_in || !bulk_out) + break; + + USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf); + dev->setName("MIDI", midi_intf); + host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init); + + size_bulk_in = bulk_in->getSize(); + size_bulk_out = bulk_out->getSize(); + + bulk_in->attach(this, &USBHostMIDI::rxHandler); + + host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); + dev_connected = true; + return true; + } + } + } + init(); + return false; +} + +void USBHostMIDI::rxHandler() { + uint8_t *midi; + if (bulk_in) { + int length = bulk_in->getLengthTransferred(); + if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) { + // MIDI event handling + for (int i = 0; i < length; i += 4) { + if (i + 4 > length) { + // length shortage, ignored. + break; + } + + // read each four bytes + midi = &buf[i]; + // process MIDI message + // switch by code index number + USB_DBG("midi: %d, %d, %d, %d", midi[0]&0xf, midi[1], midi[2], midi[3]); + switch (midi[0] & 0xf) { + case 0: // miscellaneous function codes + //if(midi[1] == 0) break; + //miscellaneousFunctionCode(midi[1], midi[2], midi[3]); + break; + case 1: // cable events + //cableEvent(midi[1], midi[2], midi[3]); + break; + case 2: // two bytes system common messages + systemCommonTwoBytes(midi[1], midi[2]); + break; + case 3: // three bytes system common messages + systemCommonThreeBytes(midi[1], midi[2], midi[3]); + break; + case 4: // SysEx starts or continues + sysExBuffer[sysExBufferPos++] = midi[1]; + if (sysExBufferPos >= 64) { + systemExclusive(sysExBuffer, sysExBufferPos, true); + sysExBufferPos = 0; + } + sysExBuffer[sysExBufferPos++] = midi[2]; + if (sysExBufferPos >= 64) { + systemExclusive(sysExBuffer, sysExBufferPos, true); + sysExBufferPos = 0; + } + sysExBuffer[sysExBufferPos++] = midi[3]; + // SysEx continues. don't send + break; + case 5: // SysEx ends with single byte + sysExBuffer[sysExBufferPos++] = midi[1]; + systemExclusive(sysExBuffer, sysExBufferPos, false); + sysExBufferPos = 0; + break; + case 6: // SysEx ends with two bytes + sysExBuffer[sysExBufferPos++] = midi[1]; + if (sysExBufferPos >= 64) { + systemExclusive(sysExBuffer, sysExBufferPos, true); + sysExBufferPos = 0; + } + sysExBuffer[sysExBufferPos++] = midi[2]; + systemExclusive(sysExBuffer, sysExBufferPos, false); + sysExBufferPos = 0; + break; + case 7: // SysEx ends with three bytes + sysExBuffer[sysExBufferPos++] = midi[1]; + if (sysExBufferPos >= 64) { + systemExclusive(sysExBuffer, sysExBufferPos, true); + sysExBufferPos = 0; + } + sysExBuffer[sysExBufferPos++] = midi[2]; + if (sysExBufferPos >= 64) { + systemExclusive(sysExBuffer, sysExBufferPos, true); + sysExBufferPos = 0; + } + sysExBuffer[sysExBufferPos++] = midi[3]; + systemExclusive(sysExBuffer, sysExBufferPos, false); + sysExBufferPos = 0; + break; + case 8: + noteOff(midi[1] & 0xf, midi[2], midi[3]); + break; + case 9: + if (midi[3]) { + noteOn(midi[1] & 0xf, midi[2], midi[3]); + } else { + noteOff(midi[1] & 0xf, midi[2], midi[3]); + } + break; + case 10: + polyKeyPress(midi[1] & 0xf, midi[2], midi[3]); + break; + case 11: + controlChange(midi[1] & 0xf, midi[2], midi[3]); + break; + case 12: + programChange(midi[1] & 0xf, midi[2]); + break; + case 13: + channelPressure(midi[1] & 0xf, midi[2]); + break; + case 14: + pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7)); + break; + case 15: + singleByte(midi[1]); + break; + default: break; + } + } + + // read another message + host->bulkRead(dev, bulk_in, buf, size_bulk_in, false); + } + } +} + +bool USBHostMIDI::sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) { + if (bulk_out) { + uint8_t midi[4]; + + midi[0] = data0; + midi[1] = data1; + midi[2] = data2; + midi[3] = data3; + if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) { + return true; + } + } + return false; +} + +bool USBHostMIDI::sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3) { + return sendMidiBuffer(0, data1, data2, data3); +} + +bool USBHostMIDI::sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3) { + return sendMidiBuffer(1, data1, data2, data3); +} + +bool USBHostMIDI::sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2) { + return sendMidiBuffer(2, data1, data2, 0); +} + +bool USBHostMIDI::sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3) { + return sendMidiBuffer(3, data1, data2, 0); +} + +bool USBHostMIDI::sendSystemExclusive(uint8_t *buffer, int length) { + uint8_t midi[64]; + int midiLength; + int midiPos; + if (bulk_out) { + for (int i = 0; i < length; i += 48) { + if (i + 48 >= length) { + // contains last data + midiLength = (((length - i) + 2) / 3) * 4; + for (int pos = i; pos < length; pos += 3) { + midiPos = (pos + 2) / 3 * 4; + if (pos + 3 >= length) { + // last data + switch (pos % 3) { + case 0: + midi[midiPos ] = 7; + midi[midiPos + 1] = buffer[pos ]; + midi[midiPos + 2] = buffer[pos + 1]; + midi[midiPos + 3] = buffer[pos + 2]; + break; + case 1: + midi[midiPos ] = 5; + midi[midiPos + 1] = buffer[pos ]; + midi[midiPos + 2] = 0; + midi[midiPos + 3] = 0; + break; + case 2: + midi[midiPos ] = 6; + midi[midiPos + 1] = buffer[pos ]; + midi[midiPos + 2] = buffer[pos + 1]; + midi[midiPos + 3] = 0; + break; + } + } else { + // has more data + midi[midiPos ] = 4; + midi[midiPos + 1] = buffer[pos ]; + midi[midiPos + 2] = buffer[pos + 1]; + midi[midiPos + 3] = buffer[pos + 2]; + } + } + } else { + // has more data + midiLength = 64; + for (int pos = i; pos < length; pos += 3) { + midiPos = (pos + 2) / 3 * 4; + midi[midiPos ] = 4; + midi[midiPos + 1] = buffer[pos ]; + midi[midiPos + 2] = buffer[pos + 1]; + midi[midiPos + 3] = buffer[pos + 2]; + } + } + + if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, midiLength) != USB_TYPE_OK) { + return false; + } + } + return true; + } + return false; +} + +bool USBHostMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) { + return sendMidiBuffer(8, channel & 0xf | 0x80, note & 0x7f, velocity & 0x7f); +} + +bool USBHostMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { + return sendMidiBuffer(9, channel & 0xf | 0x90, note & 0x7f, velocity & 0x7f); +} + +bool USBHostMIDI::sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure) { + return sendMidiBuffer(10, channel & 0xf | 0xa0, note & 0x7f, pressure & 0x7f); +} + +bool USBHostMIDI::sendControlChange(uint8_t channel, uint8_t key, uint8_t value) { + return sendMidiBuffer(11, channel & 0xf | 0xb0, key & 0x7f, value & 0x7f); +} + +bool USBHostMIDI::sendProgramChange(uint8_t channel, uint8_t program) { + return sendMidiBuffer(12, channel & 0xf | 0xc0, program & 0x7f, 0); +} + +bool USBHostMIDI::sendChannelPressure(uint8_t channel, uint8_t pressure) { + return sendMidiBuffer(13, channel & 0xf | 0xd0, pressure & 0x7f, 0); +} + +bool USBHostMIDI::sendPitchBend(uint8_t channel, uint16_t value) { + return sendMidiBuffer(14, channel & 0xf | 0xe0, value & 0x7f, (value >> 7) & 0x7f); +} + +bool USBHostMIDI::sendSingleByte(uint8_t data) { + return sendMidiBuffer(15, data, 0, 0); +} + +/*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid) +{ + // we don't check VID/PID for this driver +} + +/*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 +{ + // USB MIDI class/subclass + if ((midi_intf == -1) && + (intf_class == AUDIO_CLASS) && + (intf_subclass == 0x03)) { + midi_intf = intf_nb; + return true; + } + + // vendor specific device + if ((midi_intf == -1) && + (intf_class == 0xff) && + (intf_subclass == 0x03)) { + midi_intf = intf_nb; + return true; + } + + return false; +} + +/*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used +{ + if (intf_nb == midi_intf) { + if (type == BULK_ENDPOINT) { + midi_device_found = true; + return true; + } + } + return false; +} + +#endif