Line data Source code
1 : #pragma once 2 : 3 : #include "MIDI_Interface.hpp" 4 : #include "USBMIDI/USBMIDI.hpp" 5 : #include "USBMIDI_Sender.hpp" 6 : #include <AH/Error/Error.hpp> 7 : #include <AH/Teensy/TeensyUSBTypes.hpp> 8 : #include <MIDI_Parsers/USBMIDI_Parser.hpp> 9 : 10 : BEGIN_CS_NAMESPACE 11 : 12 : /** 13 : * @brief A class for MIDI interfaces sending MIDI messages over a USB MIDI 14 : * connection. 15 : */ 16 : template <class Backend> 17 : class GenericUSBMIDI_Interface : public MIDI_Interface { 18 : public: 19 : /** 20 : * @brief Construct a new GenericUSBMIDI_Interface. 21 : */ 22 : template <class... Args> 23 29 : GenericUSBMIDI_Interface(Args &&...args) 24 29 : : backend {std::forward<Args>(args)...}, 25 58 : alwaysSendImmediately_(backend.preferImmediateSend()) {} 26 : 27 : GenericUSBMIDI_Interface(const GenericUSBMIDI_Interface &) = delete; 28 : GenericUSBMIDI_Interface(GenericUSBMIDI_Interface &&) = delete; 29 : GenericUSBMIDI_Interface & 30 : operator=(const GenericUSBMIDI_Interface &) = delete; 31 : GenericUSBMIDI_Interface &operator=(GenericUSBMIDI_Interface &&) = delete; 32 : 33 : private: 34 : // MIDI send implementations 35 : void sendChannelMessageImpl(ChannelMessage) override; 36 : void sendSysCommonImpl(SysCommonMessage) override; 37 : void sendSysExImpl(SysExMessage) override; 38 : void sendRealTimeImpl(RealTimeMessage) override; 39 0 : void sendNowImpl() override { backend.sendNow(); } 40 : 41 : private: 42 : #if !DISABLE_PIPES 43 0 : void handleStall() override { MIDI_Interface::handleStall(this); } 44 : #ifdef DEBUG_OUT 45 : const char *getName() const override { return "usb"; } 46 : #endif 47 : #endif 48 : 49 : public: 50 : /// @name Initialization and polling 51 : /// @{ 52 : 53 : /// Initialize. 54 : void begin() override; 55 : /// Poll the backend (if necessary) and invoke the callbacks for any 56 : /// received MIDI messages, as well as sending them over the pipes connected 57 : /// to this interface. 58 : void update() override; 59 : 60 : /// @} 61 : 62 : public: 63 : /// @name Reading incoming MIDI messages 64 : /// @{ 65 : 66 : /// Try reading and parsing a single incoming MIDI message. 67 : /// @return Returns the type of the message read, or 68 : /// `MIDIReadEvent::NO_MESSAGE` if no MIDI message was available. 69 : MIDIReadEvent read(); 70 : 71 : /// Return the received channel voice message. 72 : ChannelMessage getChannelMessage() const; 73 : /// Return the received system common message. 74 : SysCommonMessage getSysCommonMessage() const; 75 : /// Return the received real-time message. 76 : RealTimeMessage getRealTimeMessage() const; 77 : /// Return the received system exclusive message. 78 : SysExMessage getSysExMessage() const; 79 : 80 : /// @} 81 : 82 : public: 83 : /// @name Underlying USB communication 84 : /// @{ 85 : 86 : /// The (platform-specific) backend used for MIDI over USB communication. 87 : Backend backend; 88 : 89 : private: 90 : /// Functor to send USB MIDI packets. 91 : struct Sender { 92 : GenericUSBMIDI_Interface *iface; 93 28 : void operator()(Cable cn, MIDICodeIndexNumber cin, uint8_t d0, 94 : uint8_t d1, uint8_t d2) { 95 28 : uint8_t cn_cin = (cn.getRaw() << 4) | uint8_t(cin); 96 28 : iface->backend.write({cn_cin, d0, d1, d2}); 97 28 : } 98 : }; 99 : /// @} 100 : 101 : private: 102 : /// Parses USB packets into MIDI messages. 103 : USBMIDI_Parser parser; 104 : /// Sends USB MIDI messages. 105 : USBMIDI_Sender sender; 106 : /// @see neverSendImmediately() 107 : bool alwaysSendImmediately_ = true; 108 : 109 : public: 110 : /// @name Buffering USB packets 111 : /// @{ 112 : 113 : /// Check if this USB interface always sends its USB packets immediately 114 : /// after sending a MIDI message. The default value depends on the MIDI USB 115 : /// backend being used: `true` for the `MIDIUSB` library, and `false` for 116 : /// the Teensy Core USB MIDI functions (because they have a short timeout). 117 : bool alwaysSendsImmediately() const { return alwaysSendImmediately_; } 118 : /// Don't send the USB packets immediately after sending a MIDI message. 119 : /// By disabling immediate transmission, packets are buffered until you 120 : /// call @ref sendNow() or until a timeout is reached, so multiple MIDI 121 : /// messages can be transmitted in a single USB packet. This is more 122 : /// efficient and results in a higher maximum bandwidth, but it could 123 : /// increase latency when used incorrectly. 124 : void neverSendImmediately() { alwaysSendImmediately_ = false; } 125 : /// Send the USB packets immediately after sending a MIDI message. 126 : /// @see @ref neverSendImmediately() 127 : void alwaysSendImmediately() { alwaysSendImmediately_ = true; } 128 : 129 : /// @} 130 : }; 131 : 132 : END_CS_NAMESPACE 133 : 134 : #include "USBMIDI_Interface.ipp" 135 : 136 : #if defined(TEENSYDUINO) && !defined(TEENSY_MIDIUSB_ENABLED) 137 : #pragma message( \ 138 : "Teensy: USB MIDI not enabled. Enable it from the Tools > USB Type menu.") 139 : #define CS_USB_MIDI_DISABLED 140 : #endif 141 : 142 : // If MIDI over USB is supported 143 : #if (!defined(CS_USB_MIDI_NOT_SUPPORTED) && !defined(CS_USB_MIDI_DISABLED)) || \ 144 : !defined(ARDUINO) 145 : 146 : BEGIN_CS_NAMESPACE 147 : 148 : /** 149 : * @brief A class for MIDI interfaces sending MIDI messages over a USB MIDI 150 : * connection. 151 : * 152 : * On boards that support it, this will create a native MIDI over USB interface 153 : * using the platform-specific libraries (e.g. MIDIUSB for Arduino Leonardo, or 154 : * the Core usbMIDI library for Teensy). 155 : * On boards without native USB support, it'll fall back to a serial MIDI 156 : * interface at the default @ref MIDI_BAUD "MIDI baud rate" on the UART 157 : * connected to the Serial to USB chip. This can be used with custom 158 : * MIDI over USB firmware for the Serial to USB chip. 159 : * 160 : * @note See @ref md_pages_MIDI-over-USB for more information. 161 : * 162 : * @ingroup MIDIInterfaces 163 : */ 164 : class USBMIDI_Interface 165 : : public GenericUSBMIDI_Interface<USBDeviceMIDIBackend> { 166 : public: 167 : using backend_t = USBDeviceMIDIBackend; 168 : using GenericUSBMIDI_Interface<backend_t>::GenericUSBMIDI_Interface; 169 : using MIDIUSBPacket_t = backend_t::MIDIUSBPacket_t; 170 : }; 171 : 172 : END_CS_NAMESPACE 173 : 174 : // If the main MCU doesn't have a USB connection: 175 : // Fall back on Serial connection at the hardware MIDI baud rate. 176 : // (Can be used with HIDUINO or USBMidiKliK.) 177 : #elif !defined(CS_USB_MIDI_DISABLED) 178 : 179 : #include "SerialMIDI_Interface.hpp" 180 : 181 : BEGIN_CS_NAMESPACE 182 : 183 : /** 184 : * @brief A class for MIDI interfaces sending MIDI messages over a USB MIDI 185 : * connection. 186 : * 187 : * @note See @ref md_pages_MIDI-over-USB for more information. 188 : * 189 : * @ingroup MIDIInterfaces 190 : */ 191 : class USBMIDI_Interface : public USBSerialMIDI_Interface { 192 : public: 193 : /** 194 : * @brief Construct a new USBMIDI_Interface. 195 : */ 196 : USBMIDI_Interface() : USBSerialMIDI_Interface(MIDI_BAUD) {} 197 : }; 198 : 199 : END_CS_NAMESPACE 200 : 201 : #endif