USBHost+USB MIDI
Dependencies: FATFileSystem mbed-rtos
Dependents: USBHostMIDI_example MIDISynthwithSpecAnalyzer
Fork of USBHost by
USBHost with USB MIDI support
(work in progress...)
Tested functions
Receiving
- note on
- note off
- program change
- control change
- pitch bend
Tranmitting
- not tested yet.
Revision 19:bf09452b8f26, committed 2013-12-05
- Comitter:
- kshoji
- Date:
- Thu Dec 05 09:32:50 2013 +0000
- Parent:
- 18:37c948cf0dbf
- Child:
- 20:bd4759650fc0
- Commit message:
- forked
Changed in this revision
--- a/USBHost/USBHostConf.h Thu Oct 17 10:15:19 2013 +0100 +++ b/USBHost/USBHostConf.h Thu Dec 05 09:32:50 2013 +0000 @@ -59,6 +59,11 @@ #define USBHOST_3GMODULE 1 /* +* Enable USBHostMIDI +*/ +#define USBHOST_MIDI 1 + +/* * Maximum number of interfaces of a usb device */ #define MAX_INTF 4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMIDI/MtxCircBuffer.h Thu Dec 05 09:32:50 2013 +0000 @@ -0,0 +1,89 @@ +/* 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 MTXCIRCBUFFER_H +#define MTXCIRCBUFFER_H + +#include "stdint.h" +#include "rtos.h" + +//Mutex protected circular buffer +template<typename T, int size> +class MtxCircBuffer { +public: + + MtxCircBuffer() { + write = 0; + read = 0; + } + + bool isFull() { + mtx.lock(); + bool r = (((write + 1) % size) == read); + mtx.unlock(); + return r; + } + + bool isEmpty() { + mtx.lock(); + bool r = (read == write); + mtx.unlock(); + return r; + } + + void flush() { + write = 0; + read = 0; + } + + void queue(T k) { + mtx.lock(); + while (((write + 1) % size) == read) { + mtx.unlock(); + Thread::wait(10); + mtx.lock(); + } + buf[write++] = k; + write %= size; + mtx.unlock(); + } + + uint16_t available() { + mtx.lock(); + uint16_t a = (write >= read) ? (write - read) : (size - read + write); + mtx.unlock(); + return a; + } + + bool dequeue(T * c) { + mtx.lock(); + bool empty = (read == write); + if (!empty) { + *c = buf[read++]; + read %= size; + } + mtx.unlock(); + return (!empty); + } + +private: + volatile uint16_t write; + volatile uint16_t read; + volatile T buf[size]; + Mutex mtx; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMIDI/USBHostMIDI.cpp Thu Dec 05 09:32:50 2013 +0000 @@ -0,0 +1,248 @@ +/* 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) { + 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostMIDI/USBHostMIDI.h Thu Dec 05 09:32:50 2013 +0000 @@ -0,0 +1,149 @@ +/* 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" +#include "MtxCircBuffer.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); + +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(); + + MtxCircBuffer<uint8_t, 64> circ_buf; + + uint8_t buf[64]; + + 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