Line data Source code
1 : #pragma once
2 :
3 : #include "MIDI_Interface.hpp"
4 : #include "USBMIDI/USBMIDI.hpp"
5 : #include <AH/Error/Error.hpp>
6 : #include <AH/Teensy/TeensyUSBTypes.hpp>
7 : #include <MIDI_Parsers/USBMIDI_Parser.hpp>
8 :
9 : AH_DIAGNOSTIC_WERROR()
10 :
11 : #if defined(TEENSYDUINO) && !defined(TEENSY_MIDIUSB_ENABLED)
12 : #warning \
13 : "Teensy: USB MIDI not enabled. Enable it from the Tools > USB Type menu."
14 : #endif
15 :
16 : #ifndef ARDUINO
17 : #include <gmock-wrapper.h>
18 : #endif
19 :
20 : // If the main MCU has a USB connection or is a Teensy with MIDI USB type
21 : #if defined(USBCON) || defined(TEENSY_MIDIUSB_ENABLED) || !defined(ARDUINO)
22 :
23 : BEGIN_CS_NAMESPACE
24 :
25 : /**
26 : * @brief A class for MIDI interfaces sending MIDI messages over a USB MIDI
27 : * connection.
28 : *
29 : * On boards that support it, this will create a native MIDI over USB interface
30 : * using the platform-specific libraries (e.g. MIDIUSB for Arduino Leonardo, or
31 : * the Core usbMIDI library for Teensy).
32 : * On boards without native USB support, it'll fall back to a serial MIDI
33 : * interface at the default @ref MIDI_BAUD "MIDI baud rate" on the UART
34 : * connected to the Serial to USB chip. This can be used with custom
35 : * MIDI over USB firmware for the Serial to USB chip.
36 : *
37 : * @note See @ref md_pages_MIDI-over-USB for more information.
38 : *
39 : * @ingroup MIDIInterfaces
40 : */
41 25 : class USBMIDI_Interface : public Parsing_MIDI_Interface {
42 : public:
43 : /**
44 : * @brief Construct a new USBMIDI_Interface.
45 : */
46 25 : USBMIDI_Interface() : Parsing_MIDI_Interface(parser) {}
47 :
48 : using MIDIUSBPacket_t = USBMIDI::MIDIUSBPacket_t;
49 :
50 : private:
51 : USBMIDI_Parser parser;
52 :
53 : #ifndef ARDUINO
54 : public:
55 42 : MOCK_METHOD(void, writeUSBPacket,
56 : (uint8_t, uint8_t, uint8_t, uint8_t, uint8_t));
57 33 : MOCK_METHOD(MIDIUSBPacket_t, readUSBPacket, ());
58 12 : void flushUSB() {}
59 :
60 : private:
61 : #else
62 : void writeUSBPacket(uint8_t cn, uint8_t cin, uint8_t d0, uint8_t d1,
63 : uint8_t d2) {
64 : USBMIDI::write(cn, cin, d0, d1, d2);
65 : }
66 : MIDIUSBPacket_t readUSBPacket() { return USBMIDI::read(); }
67 : void flushUSB() { USBMIDI::flush(); }
68 : #endif
69 :
70 3 : void sendImpl(uint8_t header, uint8_t d1, uint8_t d2, uint8_t cn) override {
71 6 : writeUSBPacket(cn, header >> 4, // CN|CIN
72 3 : header, // status
73 3 : d1, // data 1
74 3 : d2); // data 2
75 3 : flushUSB();
76 3 : }
77 :
78 1 : void sendImpl(uint8_t header, uint8_t d1, uint8_t cn) override {
79 1 : sendImpl(header, d1, 0, cn);
80 1 : }
81 :
82 8 : void sendImpl(const uint8_t *data, size_t length, uint8_t cn) override {
83 17 : while (length > 3) {
84 9 : writeUSBPacket(cn, 0x4, data[0], data[1], data[2]);
85 9 : data += 3;
86 9 : length -= 3;
87 : }
88 8 : switch (length) {
89 3 : case 3: writeUSBPacket(cn, 0x7, data[0], data[1], data[2]); break;
90 3 : case 2: writeUSBPacket(cn, 0x6, data[0], data[1], 0); break;
91 2 : case 1: writeUSBPacket(cn, 0x5, data[0], 0, 0); break;
92 0 : default: break;
93 : }
94 8 : flushUSB();
95 8 : }
96 :
97 1 : void sendImpl(uint8_t rt, uint8_t cn) override {
98 2 : writeUSBPacket(cn, 0xF, // CN|CIN
99 1 : rt, // single byte
100 : 0, // no data
101 : 0); // no data
102 1 : flushUSB();
103 1 : }
104 :
105 : public:
106 16 : MIDIReadEvent read() override {
107 40 : for (uint8_t i = 0; i < (SYSEX_BUFFER_SIZE + 2) / 3; ++i) {
108 24 : MIDIUSBPacket_t midi_packet = readUSBPacket();
109 24 : if (midi_packet.data[0] == 0)
110 7 : return MIDIReadEvent::NO_MESSAGE;
111 :
112 17 : MIDIReadEvent parseResult = parser.parse(midi_packet.data);
113 :
114 17 : if (parseResult != MIDIReadEvent::NO_MESSAGE)
115 9 : return parseResult;
116 24 : }
117 0 : return MIDIReadEvent::NO_MESSAGE;
118 16 : }
119 : };
120 :
121 : END_CS_NAMESPACE
122 :
123 : // If the main MCU doesn't have a USB connection:
124 : // Fall back on Serial connection at the hardware MIDI baud rate.
125 : // (Can be used with HIDUINO or USBMidiKliK.)
126 : #else
127 :
128 : #include "SerialMIDI_Interface.hpp"
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 : * @note See @ref md_pages_MIDI-over-USB for more information.
137 : *
138 : * @ingroup MIDIInterfaces
139 : */
140 : class USBMIDI_Interface : public USBSerialMIDI_Interface {
141 : public:
142 : /**
143 : * @brief Construct a new USBMIDI_Interface.
144 : */
145 : USBMIDI_Interface() : USBSerialMIDI_Interface(MIDI_BAUD) {}
146 : };
147 :
148 : END_CS_NAMESPACE
149 :
150 : #endif
151 :
152 : AH_DIAGNOSTIC_POP()
|