From 203a26ea3a66dede743259c8cee2e98db2f772c7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 10 Oct 2016 16:59:03 +0200 Subject: [PATCH] Added USB transport for native MIDI through USB. #52 --- src/midi_UsbTransport.h | 30 +++++++- src/midi_UsbTransport.hpp | 153 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 src/midi_UsbTransport.hpp diff --git a/src/midi_UsbTransport.h b/src/midi_UsbTransport.h index 7d59480..8ea9044 100644 --- a/src/midi_UsbTransport.h +++ b/src/midi_UsbTransport.h @@ -29,19 +29,45 @@ #pragma once #include "midi_Defs.h" +#include "midi_RingBuffer.h" +#include BEGIN_MIDI_NAMESPACE +template class UsbTransport { public: inline UsbTransport(); + inline ~UsbTransport(); public: // Serial / Stream API required for template compatibility inline void begin(unsigned inBaudrate); - inline int available() const; + inline unsigned available(); inline byte read(); - inline void write(byte); + inline void write(byte inData); + +private: + inline bool pollUsbMidi(); + inline void recomposeAndSendTxPackets(); + inline void resetTx(); + static inline byte encodePacketHeader(StatusByte inStatusByte); + static inline int getPacketLength(const midiEventPacket_t& inPacket); + +private: + typedef RingBuffer Buffer; + Buffer mTxBuffer; + Buffer mRxBuffer; + + union TxPacket + { + byte mDataArray[4]; + midiEventPacket_t mPacket; + }; + TxPacket mCurrentTxPacket; + int mCurrentTxPacketByteIndex; }; END_MIDI_NAMESPACE + +#include "midi_UsbTransport.hpp" diff --git a/src/midi_UsbTransport.hpp b/src/midi_UsbTransport.hpp new file mode 100644 index 0000000..6849e59 --- /dev/null +++ b/src/midi_UsbTransport.hpp @@ -0,0 +1,153 @@ +#pragma once + +BEGIN_MIDI_NAMESPACE + +template +inline UsbTransport::UsbTransport() +{ + +} + +template +inline UsbTransport::~UsbTransport() +{ + +} + +// ----------------------------------------------------------------------------- + +template +inline void UsbTransport::begin(unsigned inBaudrate) +{ + mTxBuffer.clear(); + mRxBuffer.clear(); +} + +template +inline unsigned UsbTransport::available() +{ + pollUsbMidi(); + return mRxBuffer.getLength(); +} + +template +inline byte UsbTransport::read() +{ + return mRxBuffer.read(); +} + +template +inline void UsbTransport::write(byte inData) +{ + mTxBuffer.write(inData); + recomposeAndSendTxPackets(); +} + +// ----------------------------------------------------------------------------- + +template +inline bool UsbTransport::pollUsbMidi() +{ + bool received = false; + midiEventPacket_t packet = MidiUSB.read(); + while (packet.header != 0) + { + received = true; + + switch (packet.header << 4) + { + // 3 bytes messages + case midi::NoteOff: + case midi::NoteOn: + case midi::AfterTouchPoly: + case midi::ControlChange: + case midi::PitchBend: + mRxBuffer.write(packet.byte1); + mRxBuffer.write(packet.byte2); + mRxBuffer.write(packet.byte3); + break; + + // 2 bytes messages + case midi::ProgramChange: + case midi::AfterTouchChannel: + mRxBuffer.write(packet.byte1); + mRxBuffer.write(packet.byte2); + break; + + // 1 byte message + case midi::TuneRequest: + case midi::Clock: + case midi::Start: + case midi::Continue: + case midi::Stop: + case midi::ActiveSensing: + case midi::SystemReset: + mRxBuffer.write(packet.byte1); + break; + + // Special cases + // case midi::SystemExclusive: + // case midi::TimeCodeQuarterFrame: + // case midi::SongPosition: + // case midi::SongSelect: + // break; + + default: + break; + } + + packet = MidiUSB.read(); + } + return received; +} + +template +inline void UsbTransport::recomposeAndSendTxPackets() +{ + while (!mTxBuffer.isEmpty()) + { + const byte data = mTxBuffer.read(); + if (mCurrentTxPacketByteIndex == 0) + { + mCurrentTxPacket.mPacket.header = encodePacketHeader(data); + } + else + { + mCurrentTxPacket.mDataArray[mCurrentTxPacketByteIndex] = data; + } + mCurrentTxPacketByteIndex++; + + const int packetLength = getPacketLength(mCurrentTxPacket.mPacket); + + if (mCurrentTxPacketByteIndex == packetLength) + { + MidiUSB.write(mCurrentTxPacket.mDataArray, packetLength); + resetTx(); + } + } +} + +template +inline void UsbTransport::resetTx() +{ + mCurrentTxPacket.mPacket.header = 0; + mCurrentTxPacket.mPacket.byte1 = 0; + mCurrentTxPacket.mPacket.byte2 = 0; + mCurrentTxPacket.mPacket.byte3 = 0; + mCurrentTxPacketByteIndex = 0; +} + +template +inline byte UsbTransport::encodePacketHeader(StatusByte inStatusByte) +{ + // todo: fix me for other types than channel + return inStatusByte >> 4; +} + +template +inline int UsbTransport::getPacketLength(const midiEventPacket_t& inPacket) +{ + return 3; +} + +END_MIDI_NAMESPACE