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