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
|