Line data Source code
1 : #include "SerialMIDI_Parser.hpp" 2 : 3 : BEGIN_CS_NAMESPACE 4 : 5 459 : MIDIReadEvent SerialMIDI_Parser::parse(uint8_t midiByte) { 6 459 : DEBUGFN(hex << NAMEDVALUE(midiByte) << dec); 7 : #if !IGNORE_SYSEX 8 : // SysEx constants 9 459 : constexpr uint8_t SysExStart = 10 : static_cast<uint8_t>(MIDIMessageType::SYSEX_START); 11 459 : constexpr uint8_t SysExEnd = 12 : static_cast<uint8_t>(MIDIMessageType::SYSEX_END); 13 : 14 : // If the previous byte was a SysExStart 15 : // I have to handle a start in the next time step, because a start can also 16 : // end the previous message. When that happens, I have to return 17 : // SYSEX_MESSAGE without resetting the buffer. 18 : // Then, after handling the message by the user, I do have to reset the 19 : // buffer. 20 459 : if (midimsg.header == SysExStart && !sysexbuffer.isReceiving()) { 21 25 : startSysEx(); 22 25 : addSysExByte(SysExStart); 23 25 : } 24 : #endif 25 : 26 : // If it's a status byte (first byte of a message) 27 459 : if (isStatus(midiByte)) { 28 : // If it's a Real-Time message 29 91 : if (midiByte >= uint8_t(MIDIMessageType::TIMING_CLOCK)) { 30 8 : rtmsg.message = midiByte; 31 8 : return MIDIReadEvent::REALTIME_MESSAGE; 32 : } 33 : // Normal header (channel message, system exclusive, system common) 34 : else { 35 : // If a SysEx message was being received, and now we receive 36 : // another status byte, remember to correctly terminate the SysEx 37 : // message later 38 83 : bool unterminatedSysEx = midimsg.header == SysExStart; 39 : 40 : // Save the newly received status byte 41 83 : midimsg.header = midiByte; 42 : // A new message starts, so we haven't received the second byte yet 43 83 : thirdByte = false; 44 : 45 83 : if (midimsg.header == uint8_t(MIDIMessageType::TUNE_REQUEST)) { 46 : // Tune request (not implemented) 47 : // TODO: should I implement this as a Real-Time message? 48 : // (That might lead to problems when a SysEx message is 49 : // terminated by a Tune Request, see unterminatedSysEx below) 50 : // TODO: should I set midimsg.header in this case? 51 0 : } 52 : 53 : #if !IGNORE_SYSEX 54 83 : if (unterminatedSysEx) { 55 : // If we're currently receiving a SysEx message 56 25 : addSysExByte(SysExEnd); // Try to add SysExEnd byte to buffer 57 : // Even if the buffer is full, end the message anyway 58 25 : endSysEx(); 59 25 : return MIDIReadEvent::SYSEX_MESSAGE; 60 : } 61 : #else 62 : (void)unterminatedSysEx; 63 : #endif // IGNORE_SYSEX 64 83 : } 65 58 : } 66 : 67 : // If it's a data byte 68 : else { 69 368 : if (midimsg.header == 0) { 70 0 : DEBUGFN("Warning: No header"); 71 : ; // Ignore 72 0 : } 73 : // Third byte of three (data 2) 74 368 : else if (thirdByte) { 75 23 : midimsg.data2 = midiByte; 76 23 : thirdByte = false; 77 23 : return MIDIReadEvent::CHANNEL_MESSAGE; 78 : } 79 : // Second byte (data 1) or SysEx data 80 : else { 81 : // Channel message with two data bytes 82 345 : if (midimsg.hasTwoDataBytes()) { 83 23 : midimsg.data1 = midiByte; 84 23 : thirdByte = true; // expect a third byte next 85 23 : } 86 : // Channel message with one data byte 87 322 : else if (midimsg.hasValidHeader()) { 88 6 : midimsg.data1 = midiByte; 89 6 : return MIDIReadEvent::CHANNEL_MESSAGE; 90 : } 91 : // Not a channel message 92 : #if !IGNORE_SYSEX 93 : // SysEx data byte 94 316 : else if (midimsg.header == SysExStart) { 95 307 : addSysExByte(midiByte); 96 307 : } 97 : #endif // IGNORE_SYSEX 98 : else { 99 9 : DEBUGFN("Data byte ignored"); 100 : } 101 : } 102 : } 103 397 : return MIDIReadEvent::NO_MESSAGE; 104 459 : } 105 : 106 : END_CS_NAMESPACE