From 5f7fa5d08351fc35a4f6bdd89340112c77cf30ab Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sat, 15 Oct 2016 13:41:50 +0200 Subject: [PATCH] Fix #58. --- src/MIDI.hpp | 19 +- .../unit-tests/tests/unit-tests_MidiInput.cpp | 190 ++++++++++++++++++ 2 files changed, 203 insertions(+), 6 deletions(-) diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 7c59a72..7e0b7db 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -677,6 +677,19 @@ bool MidiInterface::parse() const byte extracted = mSerial.read(); + // Ignore Undefined + if (extracted == 0xf9 || extracted == 0xfd) + { + if (Settings::Use1ByteParsing) + { + return false; + } + else + { + return parse(); + } + } + if (mPendingMessageIndex == 0) { // Start a new pending message @@ -717,10 +730,7 @@ bool MidiInterface::parse() mMessage.data2 = 0; mMessage.valid = true; - // \fix Running Status broken when receiving Clock messages. // Do not reset all input attributes, Running Status must remain unchanged. - //resetInput(); - // We still need to reset these mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; @@ -828,8 +838,6 @@ bool MidiInterface::parse() mMessage.valid = true; return true; - break; - // End of Exclusive case 0xf7: if (mMessage.sysexArray[0] == SystemExclusive) @@ -854,7 +862,6 @@ bool MidiInterface::parse() return false; } - break; default: break; } diff --git a/test/unit-tests/tests/unit-tests_MidiInput.cpp b/test/unit-tests/tests/unit-tests_MidiInput.cpp index 172008f..725eae8 100644 --- a/test/unit-tests/tests/unit-tests_MidiInput.cpp +++ b/test/unit-tests/tests/unit-tests_MidiInput.cpp @@ -735,4 +735,194 @@ TEST(MidiInput, realTime) EXPECT_EQ(midi.getData2(), 0); } +// -- + +TEST(MidiInput, interleavedRealTime) +{ + SerialMock serial; + MidiInterface midi(serial); + + // Interleaved Clocks between NoteOn / Off messages (with running status) + { + static const unsigned rxSize = 13; + static const byte rxData[rxSize] = { + 0x9b, 12, 0xf8, 34, + 12, 0, + 42, 0xf8, 127, + 0xf8, + 42, 0xf8, 0 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::NoteOn); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::NoteOn); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 127); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::Clock); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::NoteOff); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 0); + } + // Interleaved ActiveSensing between SysEx + { + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { + 0xf0, 12, 34, 0xfe, 56, 0xf7 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ActiveSensing); + EXPECT_EQ(midi.getChannel(), 0); + EXPECT_EQ(midi.getData1(), 0); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getSysExArrayLength(), rxSize - 1); + const std::vector sysExData(midi.getSysExArray(), + midi.getSysExArray() + rxSize - 1); + EXPECT_THAT(sysExData, ElementsAreArray({ + 0xf0, 12, 34, 56, 0xf7 + })); + } +} + +TEST(MidiInput, strayEox) +{ + // A stray End of Exclusive will reset the parser, but should it ? + SerialMock serial; + MidiInterface midi(serial); + static const unsigned rxSize = 4; + static const byte rxData[rxSize] = { + 0x8b, 42, 0xf7, 12 + }; + midi.begin(MIDI_CHANNEL_OMNI); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); +} + +TEST(MidiInput, strayUndefinedOneByteParsing) +{ + SerialMock serial; + MidiInterface midi(serial); + + static const unsigned rxSize = 13; + static const byte rxData[rxSize] = { + 0xbb, 12, 0xf9, 34, + 12, 0, + 42, 0xfd, 127, + 0xf9, + 42, 0xfd, 0 + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); // Invalid, should not reset parser + + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 127); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 42); + EXPECT_EQ(midi.getData2(), 0); +} + +TEST(MidiInput, strayUndefinedMultiByteParsing) +{ + typedef VariableSettings Settings; + typedef midi::MidiInterface MidiInterface; + + SerialMock serial; + MidiInterface midi(serial); + + static const unsigned rxSize = 4; + static const byte rxData[rxSize] = { + 0xbb, 12, 0xf9, 34, + }; + midi.begin(12); + serial.mRxBuffer.write(rxData, rxSize); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.getType(), midi::ControlChange); + EXPECT_EQ(midi.getChannel(), 12); + EXPECT_EQ(midi.getData1(), 12); + EXPECT_EQ(midi.getData2(), 34); +} + END_UNNAMED_NAMESPACE