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
Revision 22:81d8c59d1070, committed 2014-09-17
- Comitter:
- hsgw
- Date:
- Wed Sep 17 13:51:29 2014 +0000
- Parent:
- 21:b2ca8a816174
- Child:
- 23:9c1d09c6a2b6
- Commit message:
- change to USBHostMIDI in Official USB-HOST lib. but not tested yet
Changed in this revision
--- a/USBHostMIDI/CircBuffer.h Wed Sep 17 13:36:49 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* 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. - */ - -#ifndef CIRCBUFFER_H -#define CIRCBUFFER_H - -#include "stdint.h" - -//circular buffer -template<typename T, int size> -class CircBuffer { -public: - - CircBuffer() { - write = 0; - read = 0; - } - - bool isFull() { - bool r = (((write + 1) % size) == read); - return r; - } - - bool isEmpty() { - bool r = (read == write); - return r; - } - - void flush() { - write = 0; - read = 0; - } - - void queue(T k) { - while (((write + 1) % size) == read) { - wait_ms(10); - } - buf[write++] = k; - write %= size; - } - - uint16_t available() { - uint16_t a = (write >= read) ? (write - read) : (size - read + write); - return a; - } - - bool dequeue(T * c) { - bool empty = (read == write); - if (!empty) { - *c = buf[read++]; - read %= size; - } - return (!empty); - } - -private: - volatile uint16_t write; - volatile uint16_t read; - volatile T buf[size]; -}; - -#endif
--- a/USBHostMIDI/USBHostMIDI.cpp Wed Sep 17 13:36:49 2014 +0000 +++ b/USBHostMIDI/USBHostMIDI.cpp Wed Sep 17 13:51:29 2014 +0000 @@ -1,258 +1,362 @@ -/* 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; -} - -void USBHostMIDI::poll() -{ - host->poll(); -} - -/*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 +/* Copyright (c) 2014 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#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 + switch (midi[0] & 0xf) { + case 0: // miscellaneous function codes + 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; + } + } + + // 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
--- a/USBHostMIDI/USBHostMIDI.h Wed Sep 17 13:36:49 2014 +0000 +++ b/USBHostMIDI/USBHostMIDI.h Wed Sep 17 13:51:29 2014 +0000 @@ -1,159 +1,353 @@ -/* 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. - */ - -#ifndef USBHOSTMIDI_H -#define USBHOSTMIDI_H - -#include "USBHostConf.h" - -#if USBHOST_MIDI - -#include "USBHost.h" - -// STM nucleo boards do not support mbed-rtos -//#include "MtxCircBuffer.h" -#include "CircBuffer.h" - -/** - * A class to communicate a USB MIDI device - */ -class USBHostMIDI : public IUSBEnumerator { -public: - /** - * Constructor - */ - USBHostMIDI(); - - /** - * Check if a USB MIDI device is connected - * - * @returns true if a midi device is connected - */ - bool connected(); - - /** - * Try to connect a midi device - * - * @return true if connection was successful - */ - bool connect(); - - /** - * Attach a callback called when note on is received - * - * @param ptr function pointer - */ - inline void attachNoteOn(void (*fn)(unsigned char, unsigned char, unsigned char)) { - if (fn != NULL) { - noteOn = fn; - } - } - - /** - * Attach a callback called when note off is received - * - * @param ptr function pointer - */ - inline void attachNoteOff(void (*fn)(unsigned char, unsigned char, unsigned char)) { - if (fn != NULL) { - noteOff = fn; - } - } - - /** - * Attach a callback called when control change is received - * - * @param ptr function pointer - */ - inline void attachControlChange(void (*fn)(unsigned char, unsigned char, unsigned char)) { - if (fn != NULL) { - controlChange = fn; - } - } - - /** - * Attach a callback called when program change is received - * - * @param ptr function pointer - */ - inline void attachProgramChange(void (*fn)(unsigned char, unsigned char)) { - if (fn != NULL) { - programChange = fn; - } - } - - /** - * Attach a callback called when pitch bend is received - * - * @param ptr function pointer - */ - inline void attachPitchBend(void (*fn)(unsigned char, unsigned int)) { - if (fn != NULL) { - pitchBend = fn; - } - } - - int sendNoteOn(unsigned char channel, unsigned char note, unsigned char velocity); - int sendNoteOff(unsigned char channel, unsigned char note, unsigned char velocity); - int sendControlChange(unsigned char channel, unsigned char key, unsigned char value); - int sendProgramChange(unsigned char channel, unsigned char program); - int sendPitchBend(unsigned char channel, unsigned int value); - - void poll(); - -protected: - //From IUSBEnumerator - virtual void setVidPid(uint16_t vid, uint16_t pid); - virtual bool 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 - virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used - -private: - USBHost * host; - USBDeviceConnected * dev; - USBEndpoint * bulk_in; - USBEndpoint * bulk_out; - uint32_t size_bulk_in; - uint32_t size_bulk_out; - - bool dev_connected; - - void init(); - - CircBuffer<uint8_t, 128> circ_buf; - - uint8_t buf[128]; - - void rxHandler(); - - void (*noteOn)(unsigned char, unsigned char, unsigned char); - void (*noteOff)(unsigned char, unsigned char, unsigned char); - void (*controlChange)(unsigned char, unsigned char, unsigned char); - void (*programChange)(unsigned char, unsigned char); - void (*pitchBend)(unsigned char, unsigned int); - - int midi_intf; - bool midi_device_found; - -}; - -#endif - -#endif +/* Copyright (c) 2014 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef USBHOSTMIDI_H +#define USBHOSTMIDI_H + +#include "USBHostConf.h" + +#if USBHOST_MIDI + +#include "USBHost.h" + +/** + * A class to communicate a USB MIDI device + */ +class USBHostMIDI : public IUSBEnumerator { +public: + /** + * Constructor + */ + USBHostMIDI(); + + /** + * Check if a USB MIDI device is connected + * + * @returns true if a midi device is connected + */ + bool connected(); + + /** + * Try to connect a midi device + * + * @return true if connection was successful + */ + bool connect(); + + /** + * Attach a callback called when miscellaneous function code is received + * + * @param ptr function pointer + * prototype: void onMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3); + */ + inline void attachMiscellaneousFunctionCode(void (*fn)(uint8_t, uint8_t, uint8_t)) { + miscellaneousFunctionCode = fn; + } + + /** + * Attach a callback called when cable event is received + * + * @param ptr function pointer + * prototype: void onCableEvent(uint8_t data1, uint8_t data2, uint8_t data3); + */ + inline void attachCableEvent(void (*fn)(uint8_t, uint8_t, uint8_t)) { + cableEvent = fn; + } + + /** + * Attach a callback called when system exclusive is received + * + * @param ptr function pointer + * prototype: void onSystemCommonTwoBytes(uint8_t data1, uint8_t data2); + */ + inline void attachSystemCommonTwoBytes(void (*fn)(uint8_t, uint8_t)) { + systemCommonTwoBytes = fn; + } + + /** + * Attach a callback called when system exclusive is received + * + * @param ptr function pointer + * prototype: void onSystemCommonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3); + */ + inline void attachSystemCommonThreeBytes(void (*fn)(uint8_t, uint8_t, uint8_t)) { + systemCommonThreeBytes = fn; + } + + /** + * Attach a callback called when system exclusive is received + * + * @param ptr function pointer + * prototype: void onSystemExclusive(uint8_t *data, uint16_t length, bool hasNextData); + */ + inline void attachSystemExclusive(void (*fn)(uint8_t *, uint16_t, bool)) { + systemExclusive = fn; + } + + /** + * Attach a callback called when note on is received + * + * @param ptr function pointer + * prototype: void onNoteOn(uint8_t channel, uint8_t note, uint8_t velocity); + */ + inline void attachNoteOn(void (*fn)(uint8_t, uint8_t, uint8_t)) { + noteOn = fn; + } + + /** + * Attach a callback called when note off is received + * + * @param ptr function pointer + * prototype: void onNoteOff(uint8_t channel, uint8_t note, uint8_t velocity); + */ + inline void attachNoteOff(void (*fn)(uint8_t, uint8_t, uint8_t)) { + noteOff = fn; + } + + /** + * Attach a callback called when poly keypress is received + * + * @param ptr function pointer + * prototype: void onPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure); + */ + inline void attachPolyKeyPress(void (*fn)(uint8_t, uint8_t, uint8_t)) { + polyKeyPress = fn; + } + + /** + * Attach a callback called when control change is received + * + * @param ptr function pointer + * prototype: void onControlChange(uint8_t channel, uint8_t key, uint8_t value); + */ + inline void attachControlChange(void (*fn)(uint8_t, uint8_t, uint8_t)) { + controlChange = fn; + } + + /** + * Attach a callback called when program change is received + * + * @param ptr function pointer + * prototype: void onProgramChange(uint8_t channel, uint8_t program); + */ + inline void attachProgramChange(void (*fn)(uint8_t, uint8_t)) { + programChange = fn; + } + + /** + * Attach a callback called when channel pressure is received + * + * @param ptr function pointer + * prototype: void onChannelPressure(uint8_t channel, uint8_t pressure); + */ + inline void attachChannelPressure(void (*fn)(uint8_t, uint8_t)) { + channelPressure = fn; + } + + /** + * Attach a callback called when pitch bend is received + * + * @param ptr function pointer + * prototype: void onPitchBend(uint8_t channel, uint16_t value); + */ + inline void attachPitchBend(void (*fn)(uint8_t, uint16_t)) { + pitchBend = fn; + } + + /** + * Attach a callback called when single byte is received + * + * @param ptr function pointer + * prototype: void onSingleByte(uint8_t value); + */ + inline void attachSingleByte(void (*fn)(uint8_t)) { + singleByte = fn; + } + + /** + * Send a cable event with 3 bytes event + * + * @param data1 0-255 + * @param data2 0-255 + * @param data3 0-255 + * @return true if message sent successfully + */ + bool sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3); + + /** + * Send a cable event with 3 bytes event + * + * @param data1 0-255 + * @param data2 0-255 + * @param data3 0-255 + * @return true if message sent successfully + */ + bool sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3); + + /** + * Send a system common message with 2 bytes event + * + * @param data1 0-255 + * @param data2 0-255 + * @return true if message sent successfully + */ + bool sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2); + + /** + * Send a system common message with 3 bytes event + * + * @param data1 0-255 + * @param data2 0-255 + * @param data3 0-255 + * @return true if message sent successfully + */ + bool sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3); + + /** + * Send a system exclusive event + * + * @param buffer, starts with 0xF0, and end with 0xf7 + * @param length + * @return true if message sent successfully + */ + bool sendSystemExclusive(uint8_t *buffer, int length); + + /** + * Send a note off event + * + * @param channel 0-15 + * @param note 0-127 + * @param velocity 0-127 + * @return true if message sent successfully + */ + bool sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity); + + /** + * Send a note on event + * + * @param channel 0-15 + * @param note 0-127 + * @param velocity 0-127 (0 means note off) + * @return true if message sent successfully + */ + bool sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity); + + /** + * Send a poly keypress event + * + * @param channel 0-15 + * @param note 0-127 + * @param pressure 0-127 + * @return true if message sent successfully + */ + bool sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure); + + /** + * Send a control change event + * + * @param channel 0-15 + * @param key 0-127 + * @param value 0-127 + * @return true if message sent successfully + */ + bool sendControlChange(uint8_t channel, uint8_t key, uint8_t value); + + /** + * Send a program change event + * + * @param channel 0-15 + * @param program 0-127 + * @return true if message sent successfully + */ + bool sendProgramChange(uint8_t channel, uint8_t program); + + /** + * Send a channel pressure event + * + * @param channel 0-15 + * @param pressure 0-127 + * @return true if message sent successfully + */ + bool sendChannelPressure(uint8_t channel, uint8_t pressure); + + /** + * Send a control change event + * + * @param channel 0-15 + * @param key 0(lower)-8191(center)-16383(higher) + * @return true if message sent successfully + */ + bool sendPitchBend(uint8_t channel, uint16_t value); + + /** + * Send a single byte event + * + * @param data 0-255 + * @return true if message sent successfully + */ + bool sendSingleByte(uint8_t data); + +protected: + //From IUSBEnumerator + virtual void setVidPid(uint16_t vid, uint16_t pid); + virtual bool 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 + virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used + +private: + USBHost * host; + USBDeviceConnected * dev; + USBEndpoint * bulk_in; + USBEndpoint * bulk_out; + uint32_t size_bulk_in; + uint32_t size_bulk_out; + + bool dev_connected; + + void init(); + + uint8_t buf[64]; + + void rxHandler(); + + uint16_t sysExBufferPos; + uint8_t sysExBuffer[64]; + + void (*miscellaneousFunctionCode)(uint8_t, uint8_t, uint8_t); + void (*cableEvent)(uint8_t, uint8_t, uint8_t); + void (*systemCommonTwoBytes)(uint8_t, uint8_t); + void (*systemCommonThreeBytes)(uint8_t, uint8_t, uint8_t); + void (*systemExclusive)(uint8_t *, uint16_t, bool); + void (*noteOff)(uint8_t, uint8_t, uint8_t); + void (*noteOn)(uint8_t, uint8_t, uint8_t); + void (*polyKeyPress)(uint8_t, uint8_t, uint8_t); + void (*controlChange)(uint8_t, uint8_t, uint8_t); + void (*programChange)(uint8_t, uint8_t); + void (*channelPressure)(uint8_t, uint8_t); + void (*pitchBend)(uint8_t, uint16_t); + void (*singleByte)(uint8_t); + + bool sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3); + + int midi_intf; + bool midi_device_found; + +}; + +#endif /* USBHOST_MIDI */ + +#endif /* USBHOSTMIDI_H */