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