From 8b8d93e937972aa05e904e2860ce8a8bb9acd577 Mon Sep 17 00:00:00 2001 From: Eric Sherman Date: Sat, 31 Jul 2021 20:34:09 -0400 Subject: [PATCH] adds new thru mode: "UnmutedChannels" --- src/MIDI.h | 2 + src/MIDI.hpp | 17 +++ src/midi_Defs.h | 1 + test/unit-tests/tests/unit-tests_MidiThru.cpp | 119 ++++++++++++++++++ 4 files changed, 139 insertions(+) diff --git a/src/MIDI.h b/src/MIDI.h index d15888fc..56c723f5 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -242,6 +242,7 @@ class MidiInterface inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full); inline void turnThruOff(); inline void setThruFilterMode(Thru::Mode inThruFilterMode); + inline void setThruMutedChannels(bool (&inThruMutedChannels)[17]); private: void thruFilter(byte inChannel); @@ -279,6 +280,7 @@ class MidiInterface unsigned mCurrentNrpnNumber; bool mThruActivated : 1; Thru::Mode mThruFilterMode : 7; + bool mThruMutedChannels[17]; MidiMessage mMessage; unsigned long mLastMessageSentTime; unsigned long mLastMessageReceivedTime; diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 144e40e8..f358b3a7 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -1355,6 +1355,12 @@ inline void MidiInterface::setThruFilterMode(Thru mThruActivated = mThruFilterMode != Thru::Off; } +template +inline void MidiInterface::setThruMutedChannels(bool (&inThruMutedChannels)[17]) +{ + memcpy(mThruMutedChannels, inThruMutedChannels, sizeof(inThruMutedChannels)); +} + template inline Thru::Mode MidiInterface::getFilterMode() const { @@ -1439,6 +1445,17 @@ void MidiInterface::thruFilter(Channel inChannel) } break; + case Thru::UnmutedChannels: + if ((mMessage.type == NoteOff) || + (!mThruMutedChannels[0] && !mThruMutedChannels[mMessage.channel])) + { + send(mMessage.type, + mMessage.data1, + mMessage.data2, + mMessage.channel); + } + break; + default: break; } diff --git a/src/midi_Defs.h b/src/midi_Defs.h index ef74621c..0275118f 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -132,6 +132,7 @@ struct Thru Full = 1, ///< Fully enabled Thru (every incoming message is sent back). SameChannel = 2, ///< Only the messages on the Input Channel will be sent back. DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back. + UnmutedChannels = 4, ///< Only the messages on channels that are not muted will be sent back. }; }; diff --git a/test/unit-tests/tests/unit-tests_MidiThru.cpp b/test/unit-tests/tests/unit-tests_MidiThru.cpp index dc0c0c1b..4ff7f9ea 100644 --- a/test/unit-tests/tests/unit-tests_MidiThru.cpp +++ b/test/unit-tests/tests/unit-tests_MidiThru.cpp @@ -386,4 +386,123 @@ TEST(MidiThru, invalidMode) EXPECT_EQ(serial.mTxBuffer.getLength(), 0); } +TEST(MidiThru, unmutedChannelsNoneMuted) // acts like full +{ + SerialMock serial; + Transport transport(serial); + MidiInterface midi((Transport&)transport); + + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::UnmutedChannels); + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9b, 12, 34 + })); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); // Not using TX running status + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9c, 56, 78 + })); +} + +TEST(MidiThru, unmutedChannelsWithMutedChannelTwelve) +{ + SerialMock serial; + Transport transport(serial); + MidiInterface midi((Transport&)transport); + + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::UnmutedChannels); + bool thruMutedChannels[17] = { + false, + false, false, false, false, false, false, false, false, + false, false, false, true, false, false, false, false + }; + midi.setThruMutedChannels(thruMutedChannels); + + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(midi.read(), true); + + buffer.clear(); + buffer.resize(3); + EXPECT_EQ(serial.mTxBuffer.getLength(), 3); + serial.mTxBuffer.read(&buffer[0], 3); + EXPECT_THAT(buffer, ElementsAreArray({ + 0x9c, 56, 78 + })); +} + +TEST(MidiThru, unmutedChannelsWithChannelZeroMuted) // acts like off +{ + SerialMock serial; + Transport transport(serial); + MidiInterface midi((Transport&)transport); + + Buffer buffer; + + midi.begin(MIDI_CHANNEL_OMNI); + midi.setThruFilterMode(midi::Thru::UnmutedChannels); + bool thruMutedChannels[17] = { + true, + false, false, false, false, false, false, false, false, + false, false, false, true, false, false, false, false + }; + midi.setThruMutedChannels(thruMutedChannels); + + + static const unsigned rxSize = 6; + static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 }; + serial.mRxBuffer.write(rxData, rxSize); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), false); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); + EXPECT_EQ(midi.read(), true); + EXPECT_EQ(serial.mTxBuffer.getLength(), 0); +} + END_UNNAMED_NAMESPACE