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