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