Line data Source code
1 : #include "USBMIDI_Parser.hpp"
2 : #include <Settings/SettingsWrapper.hpp>
3 :
4 : BEGIN_CS_NAMESPACE
5 :
6 6 : MIDIReadEvent USBMIDI_Parser::handleChannelMessage(MIDIUSBPacket_t packet,
7 : Cable cable) {
8 6 : midimsg.header = packet[1];
9 6 : midimsg.data1 = packet[2];
10 6 : midimsg.data2 = packet[3];
11 6 : midimsg.cable = cable;
12 6 : return MIDIReadEvent::CHANNEL_MESSAGE;
13 : }
14 :
15 102 : MIDIReadEvent USBMIDI_Parser::handleSysExStartCont(MIDIUSBPacket_t packet,
16 : Cable cable) {
17 : #if !IGNORE_SYSEX
18 : // If this is a SysEx start packet
19 102 : if (packet[1] == uint8_t(MIDIMessageType::SysExStart)) {
20 10 : startSysEx(cable); // start a new message
21 : // (overwrites previous unfinished message)
22 : }
23 : // If we haven't received a SysExStart
24 92 : else if (!receivingSysEx(cable)) {
25 : DEBUGREF(F("No SysExStart received"));
26 1 : return MIDIReadEvent::NO_MESSAGE; // ignore the data
27 : }
28 :
29 : // Check if the SysEx buffer has enough space to store the data
30 101 : if (!hasSysExSpace(cable, 3)) {
31 1 : storePacket(packet);
32 1 : endSysExChunk(cable);
33 1 : return MIDIReadEvent::SYSEX_CHUNK;
34 : }
35 :
36 : // Enough space available in buffer, store the data
37 100 : addSysExBytes(cable, &packet[1], 3);
38 : #else
39 : (void)packet;
40 : (void)cable;
41 : #endif
42 100 : return MIDIReadEvent::NO_MESSAGE; // SysEx is not finished yet
43 : }
44 :
45 : template <uint8_t NumBytes>
46 11 : MIDIReadEvent USBMIDI_Parser::handleSysExEnd(MIDIUSBPacket_t packet,
47 : Cable cable) {
48 : static_assert(NumBytes == 2 || NumBytes == 3,
49 : "Only 2- or 3-byte SysEx packets are supported");
50 :
51 : #if !IGNORE_SYSEX
52 : // This could be the a very short SysEx message that starts and ends with
53 : // this packet
54 11 : if (packet[1] == uint8_t(MIDIMessageType::SysExStart)) {
55 2 : startSysEx(cable); // start a new message
56 : // (overwrites previous unfinished message)
57 : }
58 : // If we haven't received a SysExStart
59 9 : else if (!receivingSysEx(cable)) {
60 : DEBUGFN(F("No SysExStart received"));
61 2 : return MIDIReadEvent::NO_MESSAGE; // ignore the data
62 : }
63 :
64 : // Check if the SysEx buffer has enough space to store the end byte
65 9 : if (!hasSysExSpace(cable, NumBytes)) {
66 1 : storePacket(packet);
67 1 : endSysExChunk(cable);
68 1 : return MIDIReadEvent::SYSEX_CHUNK; // Buffer full
69 : }
70 :
71 : // Enough space available in buffer, finish the message
72 8 : addSysExBytes(cable, &packet[1], NumBytes);
73 8 : endSysEx(cable);
74 8 : return MIDIReadEvent::SYSEX_MESSAGE;
75 : #else
76 : (void)packet;
77 : (void)cable;
78 : return MIDIReadEvent::NO_MESSAGE;
79 : #endif
80 : }
81 :
82 : template <>
83 7 : MIDIReadEvent USBMIDI_Parser::handleSysExEnd<1>(MIDIUSBPacket_t packet,
84 : Cable cable) {
85 : // Single-byte System Common Message
86 7 : if (packet[1] != uint8_t(MIDIMessageType::SysExEnd)) {
87 : // System Common (1 byte)
88 2 : midimsg.header = packet[1];
89 2 : midimsg.cable = cable;
90 2 : return MIDIReadEvent::SYSCOMMON_MESSAGE;
91 : }
92 :
93 : #if !IGNORE_SYSEX
94 : // SysEx ends with following single byte
95 : else {
96 : // If we haven't received a SysExStart
97 5 : if (!receivingSysEx(cable)) {
98 : DEBUGREF(F("No SysExStart received"));
99 1 : return MIDIReadEvent::NO_MESSAGE; // ignore the data
100 : }
101 :
102 : // Check if the SysEx buffer has enough space to store the end byte
103 4 : if (!hasSysExSpace(cable, 1)) {
104 0 : storePacket(packet);
105 0 : endSysExChunk(cable);
106 0 : return MIDIReadEvent::SYSEX_CHUNK;
107 : }
108 :
109 : // Enough space available in buffer, finish the message
110 4 : addSysExByte(cable, packet[1]);
111 4 : endSysEx(cable);
112 4 : return MIDIReadEvent::SYSEX_MESSAGE;
113 : }
114 : #else
115 : (void)packet;
116 : (void)cable;
117 : return MIDIReadEvent::NO_MESSAGE;
118 : #endif
119 : }
120 :
121 4 : MIDIReadEvent USBMIDI_Parser::handleSysCommon(MIDIUSBPacket_t packet,
122 : Cable cable) {
123 4 : midimsg.header = packet[1];
124 4 : midimsg.data1 = packet[2];
125 4 : midimsg.data2 = packet[3];
126 4 : midimsg.cable = cable;
127 4 : return MIDIReadEvent::SYSCOMMON_MESSAGE;
128 : }
129 :
130 : // Single Byte
131 3 : MIDIReadEvent USBMIDI_Parser::handleSingleByte(MIDIUSBPacket_t packet,
132 : Cable cable) {
133 3 : rtmsg.message = packet[1];
134 3 : rtmsg.cable = cable;
135 3 : return MIDIReadEvent::REALTIME_MESSAGE;
136 : }
137 :
138 : // https://usb.org/sites/default/files/midi10.pdf
139 133 : MIDIReadEvent USBMIDI_Parser::feed(MIDIUSBPacket_t packet) {
140 : // DEBUG("MIDIUSB packet:\t" << hex << packet[0] << ' ' << packet[1] << ' '
141 : // << packet[2] << ' ' << packet[3] << dec);
142 :
143 : // MIDI USB cable number and code index number
144 133 : Cable cable = Cable(packet[0] >> 4);
145 133 : MIDICodeIndexNumber CIN = MIDICodeIndexNumber(packet[0] & 0xF);
146 :
147 : // Ignore all messages for cables that we don't have
148 133 : if (cable.getRaw() >= USB_MIDI_NUMBER_OF_CABLES)
149 : return MIDIReadEvent::NO_MESSAGE; // LCOV_EXCL_LINE
150 :
151 : using M = MIDICodeIndexNumber;
152 133 : switch (CIN) {
153 : case M::MiscFunctionCodes: break; // LCOV_EXCL_LINE
154 : case M::CableEvents: break; // LCOV_EXCL_LINE
155 4 : case M::SystemCommon2B: // fallthrough
156 4 : case M::SystemCommon3B: return handleSysCommon(packet, cable);
157 102 : case M::SysExStartCont: return handleSysExStartCont(packet, cable);
158 7 : case M::SysExEnd1B: return handleSysExEnd<1>(packet, cable);
159 5 : case M::SysExEnd2B: return handleSysExEnd<2>(packet, cable);
160 6 : case M::SysExEnd3B: return handleSysExEnd<3>(packet, cable);
161 6 : case M::NoteOff: // fallthrough
162 : case M::NoteOn: // fallthrough
163 : case M::KeyPressure: // fallthrough
164 : case M::ControlChange: // fallthrough
165 : case M::ProgramChange: // fallthrough
166 : case M::ChannelPressure: // fallthrough
167 6 : case M::PitchBend: return handleChannelMessage(packet, cable);
168 3 : case M::SingleByte: return handleSingleByte(packet, cable);
169 : default: break; // LCOV_EXCL_LINE
170 : }
171 :
172 : return MIDIReadEvent::NO_MESSAGE; // LCOV_EXCL_LINE
173 : }
174 :
175 39 : MIDIReadEvent USBMIDI_Parser::resume() {
176 : #if !IGNORE_SYSEX
177 39 : if (!hasStoredPacket())
178 37 : return MIDIReadEvent::NO_MESSAGE;
179 :
180 2 : MIDIUSBPacket_t packet = popStoredPacket();
181 :
182 : // If a SysEx message was in progress
183 2 : if (receivingSysEx(activeCable)) {
184 : // Reset the buffer for the next chunk
185 2 : startSysEx(activeCable);
186 : }
187 :
188 2 : return feed(packet);
189 : #else
190 : return MIDIReadEvent::NO_MESSAGE;
191 : #endif
192 : }
193 :
194 : END_CS_NAMESPACE
|