thru filter overhaul
* resolves #40 with franky47's proposed thru filter overhaul * removes thru filter modes * adds thru filter callback * adds thru map callback * old thru filter unit tests have been replicated with filter callbacks * does not yet include documentation changes I believe this implements the latest proposal for #40 and exercises everything necessary in the unit tests, including the immutability of `mMessage` after a thru map callback has modified the outgoing message. The thru filter callbacks in the unit tests are not suitable for copying and pasting by end-users due to the difference in the MIDI namespace when setup via the unit tests vs via `MIDI_CREATE_DEFAULT_INSTANCE()`. If the changes here are deemed suitable, I'll work on documentation.
This commit is contained in:
parent
d501f4bb3d
commit
00206071e6
|
|
@ -55,14 +55,12 @@ getData1 KEYWORD2
|
||||||
getData2 KEYWORD2
|
getData2 KEYWORD2
|
||||||
getSysExArray KEYWORD2
|
getSysExArray KEYWORD2
|
||||||
getSysExArrayLength KEYWORD2
|
getSysExArrayLength KEYWORD2
|
||||||
getFilterMode KEYWORD2
|
|
||||||
getThruState KEYWORD2
|
getThruState KEYWORD2
|
||||||
getInputChannel KEYWORD2
|
getInputChannel KEYWORD2
|
||||||
check KEYWORD2
|
check KEYWORD2
|
||||||
setInputChannel KEYWORD2
|
setInputChannel KEYWORD2
|
||||||
turnThruOn KEYWORD2
|
turnThruOn KEYWORD2
|
||||||
turnThruOff KEYWORD2
|
turnThruOff KEYWORD2
|
||||||
setThruFilterMode KEYWORD2
|
|
||||||
disconnectCallbackFromType KEYWORD2
|
disconnectCallbackFromType KEYWORD2
|
||||||
setHandleNoteOff KEYWORD2
|
setHandleNoteOff KEYWORD2
|
||||||
setHandleNoteOn KEYWORD2
|
setHandleNoteOn KEYWORD2
|
||||||
|
|
|
||||||
17
src/MIDI.h
17
src/MIDI.h
|
|
@ -236,15 +236,22 @@ private:
|
||||||
// MIDI Soft Thru
|
// MIDI Soft Thru
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline Thru::Mode getFilterMode() const;
|
|
||||||
inline bool getThruState() const;
|
inline bool getThruState() const;
|
||||||
|
|
||||||
inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
|
using ThruFilterCallback = bool (*)(const MidiMessage& inMessage);
|
||||||
|
using ThruMapCallback = MidiMessage (*)(const MidiMessage& inMessage);
|
||||||
|
inline void turnThruOn(ThruFilterCallback fptr = thruOn);
|
||||||
inline void turnThruOff();
|
inline void turnThruOff();
|
||||||
inline void setThruFilterMode(Thru::Mode inThruFilterMode);
|
inline void setThruFilter(ThruFilterCallback fptr) { mThruFilterCallback = fptr; }
|
||||||
|
inline void setThruMap(ThruMapCallback fptr) { mThruMapCallback = fptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void thruFilter(byte inChannel);
|
void thruFilter();
|
||||||
|
static inline bool thruOn(const MidiMessage& inMessage) { (void)inMessage; return true; }
|
||||||
|
static inline bool thruOff(const MidiMessage& inMessage) { (void)inMessage; return false; }
|
||||||
|
static inline MidiMessage thruEcho(const MidiMessage& inMessage) { return inMessage; }
|
||||||
|
ThruFilterCallback mThruFilterCallback;
|
||||||
|
ThruMapCallback mThruMapCallback;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// MIDI Parsing
|
// MIDI Parsing
|
||||||
|
|
@ -277,8 +284,6 @@ private:
|
||||||
unsigned mPendingMessageIndex;
|
unsigned mPendingMessageIndex;
|
||||||
unsigned mCurrentRpnNumber;
|
unsigned mCurrentRpnNumber;
|
||||||
unsigned mCurrentNrpnNumber;
|
unsigned mCurrentNrpnNumber;
|
||||||
bool mThruActivated : 1;
|
|
||||||
Thru::Mode mThruFilterMode : 7;
|
|
||||||
MidiMessage mMessage;
|
MidiMessage mMessage;
|
||||||
unsigned long mLastMessageSentTime;
|
unsigned long mLastMessageSentTime;
|
||||||
unsigned long mLastMessageReceivedTime;
|
unsigned long mLastMessageReceivedTime;
|
||||||
|
|
|
||||||
93
src/MIDI.hpp
93
src/MIDI.hpp
|
|
@ -40,8 +40,6 @@ inline MidiInterface<Transport, Settings, Platform>::MidiInterface(Transport& in
|
||||||
, mPendingMessageIndex(0)
|
, mPendingMessageIndex(0)
|
||||||
, mCurrentRpnNumber(0xffff)
|
, mCurrentRpnNumber(0xffff)
|
||||||
, mCurrentNrpnNumber(0xffff)
|
, mCurrentNrpnNumber(0xffff)
|
||||||
, mThruActivated(true)
|
|
||||||
, mThruFilterMode(Thru::Full)
|
|
||||||
, mLastMessageSentTime(0)
|
, mLastMessageSentTime(0)
|
||||||
, mLastMessageReceivedTime(0)
|
, mLastMessageReceivedTime(0)
|
||||||
, mSenderActiveSensingPeriodicity(0)
|
, mSenderActiveSensingPeriodicity(0)
|
||||||
|
|
@ -93,8 +91,8 @@ void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
||||||
mMessage.data2 = 0;
|
mMessage.data2 = 0;
|
||||||
mMessage.length = 0;
|
mMessage.length = 0;
|
||||||
|
|
||||||
mThruFilterMode = Thru::Full;
|
mThruFilterCallback = thruOn;
|
||||||
mThruActivated = mTransport.thruActivated;
|
mThruMapCallback = thruEcho;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
@ -771,7 +769,7 @@ inline bool MidiInterface<Transport, Settings, Platform>::read(Channel inChannel
|
||||||
if (channelMatch)
|
if (channelMatch)
|
||||||
launchCallback();
|
launchCallback();
|
||||||
|
|
||||||
thruFilter(inChannel);
|
thruFilter();
|
||||||
|
|
||||||
return channelMatch;
|
return channelMatch;
|
||||||
}
|
}
|
||||||
|
|
@ -1343,42 +1341,22 @@ void MidiInterface<Transport, Settings, Platform>::launchCallback()
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! \brief Set the filter for thru mirroring
|
|
||||||
\param inThruFilterMode a filter mode
|
|
||||||
|
|
||||||
@see Thru::Mode
|
|
||||||
*/
|
|
||||||
template<class Transport, class Settings, class Platform>
|
|
||||||
inline void MidiInterface<Transport, Settings, Platform>::setThruFilterMode(Thru::Mode inThruFilterMode)
|
|
||||||
{
|
|
||||||
mThruFilterMode = inThruFilterMode;
|
|
||||||
mThruActivated = mThruFilterMode != Thru::Off;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Transport, class Settings, class Platform>
|
|
||||||
inline Thru::Mode MidiInterface<Transport, Settings, Platform>::getFilterMode() const
|
|
||||||
{
|
|
||||||
return mThruFilterMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Transport, class Settings, class Platform>
|
template<class Transport, class Settings, class Platform>
|
||||||
inline bool MidiInterface<Transport, Settings, Platform>::getThruState() const
|
inline bool MidiInterface<Transport, Settings, Platform>::getThruState() const
|
||||||
{
|
{
|
||||||
return mThruActivated;
|
return mThruFilterCallback != thruOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Transport, class Settings, class Platform>
|
template<class Transport, class Settings, class Platform>
|
||||||
inline void MidiInterface<Transport, Settings, Platform>::turnThruOn(Thru::Mode inThruFilterMode)
|
inline void MidiInterface<Transport, Settings, Platform>::turnThruOn(ThruFilterCallback fptr)
|
||||||
{
|
{
|
||||||
mThruActivated = true;
|
mThruFilterCallback = fptr;
|
||||||
mThruFilterMode = inThruFilterMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Transport, class Settings, class Platform>
|
template<class Transport, class Settings, class Platform>
|
||||||
inline void MidiInterface<Transport, Settings, Platform>::turnThruOff()
|
inline void MidiInterface<Transport, Settings, Platform>::turnThruOff()
|
||||||
{
|
{
|
||||||
mThruActivated = false;
|
mThruFilterCallback = thruOff;
|
||||||
mThruFilterMode = Thru::Off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Transport, class Settings, class Platform>
|
template<class Transport, class Settings, class Platform>
|
||||||
|
|
@ -1397,51 +1375,20 @@ inline void MidiInterface<Transport, Settings, Platform>::UpdateLastSentTime()
|
||||||
// - Channel messages are passed to the output whether their channel
|
// - Channel messages are passed to the output whether their channel
|
||||||
// is matching the input channel and the filter setting
|
// is matching the input channel and the filter setting
|
||||||
template<class Transport, class Settings, class Platform>
|
template<class Transport, class Settings, class Platform>
|
||||||
void MidiInterface<Transport, Settings, Platform>::thruFilter(Channel inChannel)
|
void MidiInterface<Transport, Settings, Platform>::thruFilter()
|
||||||
{
|
{
|
||||||
// If the feature is disabled, don't do anything.
|
if (!mThruFilterCallback(mMessage))
|
||||||
if (!mThruActivated || (mThruFilterMode == Thru::Off))
|
return;
|
||||||
return;
|
|
||||||
|
MidiMessage thruMessage = mThruMapCallback(mMessage);
|
||||||
|
|
||||||
// First, check if the received message is Channel
|
// First, check if the received message is Channel
|
||||||
if (mMessage.type >= NoteOff && mMessage.type <= PitchBend)
|
if (mMessage.type >= NoteOff && mMessage.type <= PitchBend)
|
||||||
{
|
{
|
||||||
const bool filter_condition = ((mMessage.channel == inChannel) ||
|
send(thruMessage.type,
|
||||||
(inChannel == MIDI_CHANNEL_OMNI));
|
thruMessage.data1,
|
||||||
|
thruMessage.data2,
|
||||||
// Now let's pass it to the output
|
thruMessage.channel);
|
||||||
switch (mThruFilterMode)
|
|
||||||
{
|
|
||||||
case Thru::Full:
|
|
||||||
send(mMessage.type,
|
|
||||||
mMessage.data1,
|
|
||||||
mMessage.data2,
|
|
||||||
mMessage.channel);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Thru::SameChannel:
|
|
||||||
if (filter_condition)
|
|
||||||
{
|
|
||||||
send(mMessage.type,
|
|
||||||
mMessage.data1,
|
|
||||||
mMessage.data2,
|
|
||||||
mMessage.channel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Thru::DifferentChannel:
|
|
||||||
if (!filter_condition)
|
|
||||||
{
|
|
||||||
send(mMessage.type,
|
|
||||||
mMessage.data1,
|
|
||||||
mMessage.data2,
|
|
||||||
mMessage.channel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1461,19 +1408,19 @@ void MidiInterface<Transport, Settings, Platform>::thruFilter(Channel inChannel)
|
||||||
|
|
||||||
case SystemExclusive:
|
case SystemExclusive:
|
||||||
// Send SysEx (0xf0 and 0xf7 are included in the buffer)
|
// Send SysEx (0xf0 and 0xf7 are included in the buffer)
|
||||||
sendSysEx(getSysExArrayLength(), getSysExArray(), true);
|
sendSysEx(thruMessage.getSysExSize(), thruMessage.sysexArray, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SongSelect:
|
case SongSelect:
|
||||||
sendSongSelect(mMessage.data1);
|
sendSongSelect(thruMessage.data1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SongPosition:
|
case SongPosition:
|
||||||
sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2 << 7));
|
sendSongPosition(thruMessage.data1 | ((unsigned)thruMessage.data2 << 7));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TimeCodeQuarterFrame:
|
case TimeCodeQuarterFrame:
|
||||||
sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2);
|
sendTimeCodeQuarterFrame(thruMessage.data1,thruMessage.data2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ static const uint16_t ActiveSensingTimeout = 300;
|
||||||
typedef byte StatusByte;
|
typedef byte StatusByte;
|
||||||
typedef byte DataByte;
|
typedef byte DataByte;
|
||||||
typedef byte Channel;
|
typedef byte Channel;
|
||||||
typedef byte FilterMode;
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Errors
|
// Errors
|
||||||
|
|
@ -123,20 +122,6 @@ enum MidiType: uint8_t
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*! Enumeration of Thru filter modes */
|
|
||||||
struct Thru
|
|
||||||
{
|
|
||||||
enum Mode
|
|
||||||
{
|
|
||||||
Off = 0, ///< Thru disabled (nothing passes through).
|
|
||||||
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.
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/*! \brief Enumeration of Control Change command numbers.
|
/*! \brief Enumeration of Control Change command numbers.
|
||||||
See the detailed controllers numbers & description here:
|
See the detailed controllers numbers & description here:
|
||||||
http://www.somascape.org/midi/tech/spec.html#ctrlnums
|
http://www.somascape.org/midi/tech/spec.html#ctrlnums
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ add_executable(unit-tests
|
||||||
tests/unit-tests_MidiThru.cpp
|
tests/unit-tests_MidiThru.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(tests/unit-tests_MidiThru.cpp PROPERTIES COMPILE_FLAGS -Wno-shadow)
|
||||||
|
|
||||||
target_link_libraries(unit-tests
|
target_link_libraries(unit-tests
|
||||||
gtest
|
gtest
|
||||||
gmock
|
gmock
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ typedef test_mocks::SerialMock<32> SerialMock;
|
||||||
typedef midi::SerialMIDI<SerialMock> Transport;
|
typedef midi::SerialMIDI<SerialMock> Transport;
|
||||||
typedef midi::MidiInterface<Transport> MidiInterface;
|
typedef midi::MidiInterface<Transport> MidiInterface;
|
||||||
typedef std::vector<byte> Buffer;
|
typedef std::vector<byte> Buffer;
|
||||||
|
typedef midi::Message<midi::DefaultSettings::SysExMaxSize> MidiMessage;
|
||||||
|
|
||||||
template<unsigned Size>
|
template<unsigned Size>
|
||||||
struct VariableSysExSettings : midi::DefaultSettings
|
struct VariableSysExSettings : midi::DefaultSettings
|
||||||
|
|
@ -24,75 +25,66 @@ struct VariableSysExSettings : midi::DefaultSettings
|
||||||
static const unsigned SysExMaxSize = Size;
|
static const unsigned SysExMaxSize = Size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SerialMock serial;
|
||||||
|
Transport transport(serial);
|
||||||
|
MidiInterface midi((Transport&)transport);
|
||||||
|
|
||||||
|
bool thruFilterSameChannel(const MidiMessage& inMessage)
|
||||||
|
{
|
||||||
|
if (!midi.isChannelMessage(inMessage.type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return MIDI_CHANNEL_OMNI == midi.getInputChannel() ||
|
||||||
|
inMessage.channel == midi.getInputChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool thruFilterDifferentChannel(const MidiMessage& inMessage)
|
||||||
|
{
|
||||||
|
if (!midi.isChannelMessage(inMessage.type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return MIDI_CHANNEL_OMNI != midi.getInputChannel() &&
|
||||||
|
inMessage.channel != midi.getInputChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiMessage thruMapNoteOnFullVelocity(const MidiMessage& inMessage)
|
||||||
|
{
|
||||||
|
if (inMessage.type != midi::MidiType::NoteOn)
|
||||||
|
return inMessage;
|
||||||
|
|
||||||
|
MidiMessage modified = inMessage;
|
||||||
|
modified.data2 = 127;
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
TEST(MidiThru, defaultValues)
|
TEST(MidiThru, defaultValues)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
EXPECT_EQ(midi.getThruState(), true);
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
|
|
||||||
midi.begin(); // Should not change the state
|
midi.begin(); // Should not change the state
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
EXPECT_EQ(midi.getThruState(), true);
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MidiThru, beginEnablesThru)
|
TEST(MidiThru, beginEnablesThru)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
midi.turnThruOff();
|
midi.turnThruOff();
|
||||||
EXPECT_EQ(midi.getThruState(), false);
|
EXPECT_EQ(midi.getThruState(), false);
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Off);
|
|
||||||
midi.begin();
|
midi.begin();
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
EXPECT_EQ(midi.getThruState(), true);
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MidiThru, setGet)
|
TEST(MidiThru, setGet)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
midi.turnThruOff();
|
midi.turnThruOff();
|
||||||
EXPECT_EQ(midi.getThruState(), false);
|
EXPECT_EQ(midi.getThruState(), false);
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Off);
|
|
||||||
|
|
||||||
midi.turnThruOn();
|
midi.turnThruOn();
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
EXPECT_EQ(midi.getThruState(), true);
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
|
|
||||||
midi.turnThruOn(midi::Thru::SameChannel);
|
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::SameChannel);
|
|
||||||
midi.turnThruOn(midi::Thru::DifferentChannel);
|
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::DifferentChannel);
|
|
||||||
|
|
||||||
midi.setThruFilterMode(midi::Thru::Full);
|
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Full);
|
|
||||||
midi.setThruFilterMode(midi::Thru::SameChannel);
|
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::SameChannel);
|
|
||||||
midi.setThruFilterMode(midi::Thru::DifferentChannel);
|
|
||||||
EXPECT_EQ(midi.getThruState(), true);
|
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::DifferentChannel);
|
|
||||||
midi.setThruFilterMode(midi::Thru::Off);
|
|
||||||
EXPECT_EQ(midi.getThruState(), false);
|
|
||||||
EXPECT_EQ(midi.getFilterMode(), midi::Thru::Off);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MidiThru, off)
|
TEST(MidiThru, off)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
midi.begin(MIDI_CHANNEL_OMNI);
|
midi.begin(MIDI_CHANNEL_OMNI);
|
||||||
midi.turnThruOff();
|
midi.turnThruOff();
|
||||||
|
|
||||||
|
|
@ -110,14 +102,9 @@ TEST(MidiThru, off)
|
||||||
|
|
||||||
TEST(MidiThru, full)
|
TEST(MidiThru, full)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
midi.begin(MIDI_CHANNEL_OMNI);
|
midi.begin(MIDI_CHANNEL_OMNI);
|
||||||
midi.setThruFilterMode(midi::Thru::Full);
|
|
||||||
|
|
||||||
static const unsigned rxSize = 6;
|
static const unsigned rxSize = 6;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
||||||
|
|
@ -154,14 +141,10 @@ TEST(MidiThru, full)
|
||||||
|
|
||||||
TEST(MidiThru, sameChannel)
|
TEST(MidiThru, sameChannel)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
midi.begin(12);
|
midi.begin(12);
|
||||||
midi.setThruFilterMode(midi::Thru::SameChannel);
|
midi.setThruFilter(thruFilterSameChannel);
|
||||||
|
|
||||||
static const unsigned rxSize = 6;
|
static const unsigned rxSize = 6;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
||||||
|
|
@ -185,14 +168,10 @@ TEST(MidiThru, sameChannel)
|
||||||
|
|
||||||
TEST(MidiThru, sameChannelOmni) // Acts like full
|
TEST(MidiThru, sameChannelOmni) // Acts like full
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
midi.begin(MIDI_CHANNEL_OMNI);
|
midi.begin(MIDI_CHANNEL_OMNI);
|
||||||
midi.setThruFilterMode(midi::Thru::SameChannel);
|
midi.setThruFilter(thruFilterSameChannel);
|
||||||
|
|
||||||
static const unsigned rxSize = 6;
|
static const unsigned rxSize = 6;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
||||||
|
|
@ -229,14 +208,10 @@ TEST(MidiThru, sameChannelOmni) // Acts like full
|
||||||
|
|
||||||
TEST(MidiThru, differentChannel)
|
TEST(MidiThru, differentChannel)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
midi.begin(12);
|
midi.begin(12);
|
||||||
midi.setThruFilterMode(midi::Thru::DifferentChannel);
|
midi.setThruFilter(thruFilterDifferentChannel);
|
||||||
|
|
||||||
static const unsigned rxSize = 6;
|
static const unsigned rxSize = 6;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
||||||
|
|
@ -260,14 +235,10 @@ TEST(MidiThru, differentChannel)
|
||||||
|
|
||||||
TEST(MidiThru, differentChannelOmni) // Acts like off
|
TEST(MidiThru, differentChannelOmni) // Acts like off
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
midi.begin(MIDI_CHANNEL_OMNI);
|
midi.begin(MIDI_CHANNEL_OMNI);
|
||||||
midi.setThruFilterMode(midi::Thru::DifferentChannel);
|
midi.setThruFilter(thruFilterDifferentChannel);
|
||||||
|
|
||||||
static const unsigned rxSize = 6;
|
static const unsigned rxSize = 6;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
||||||
|
|
@ -293,14 +264,11 @@ TEST(MidiThru, multiByteThru)
|
||||||
typedef VariableSettings<false, false> MultiByteParsing;
|
typedef VariableSettings<false, false> MultiByteParsing;
|
||||||
typedef midi::MidiInterface<Transport, MultiByteParsing> MultiByteMidiInterface;
|
typedef midi::MidiInterface<Transport, MultiByteParsing> MultiByteMidiInterface;
|
||||||
|
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
MultiByteMidiInterface midi((Transport&)transport);
|
MultiByteMidiInterface midi((Transport&)transport);
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
midi.begin(MIDI_CHANNEL_OMNI);
|
midi.begin(MIDI_CHANNEL_OMNI);
|
||||||
midi.setThruFilterMode(midi::Thru::Full);
|
|
||||||
|
|
||||||
static const unsigned rxSize = 6;
|
static const unsigned rxSize = 6;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 56, 78 };
|
||||||
|
|
@ -324,14 +292,11 @@ TEST(MidiThru, withTxRunningStatus)
|
||||||
typedef VariableSettings<true, true> Settings;
|
typedef VariableSettings<true, true> Settings;
|
||||||
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
typedef midi::MidiInterface<Transport, Settings> RsMidiInterface;
|
||||||
|
|
||||||
SerialMock serial;
|
|
||||||
Transport transport(serial);
|
|
||||||
RsMidiInterface midi((Transport&)transport);
|
RsMidiInterface midi((Transport&)transport);
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
midi.begin(MIDI_CHANNEL_OMNI);
|
midi.begin(MIDI_CHANNEL_OMNI);
|
||||||
midi.setThruFilterMode(midi::Thru::Full);
|
|
||||||
|
|
||||||
static const unsigned rxSize = 5;
|
static const unsigned rxSize = 5;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 56, 78 };
|
||||||
|
|
@ -364,26 +329,52 @@ TEST(MidiThru, withTxRunningStatus)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MidiThru, invalidMode)
|
TEST(MidiThru, mapNoteOnFullVelocity)
|
||||||
{
|
{
|
||||||
SerialMock serial;
|
Buffer buffer;
|
||||||
Transport transport(serial);
|
|
||||||
MidiInterface midi((Transport&)transport);
|
|
||||||
|
|
||||||
midi.begin(MIDI_CHANNEL_OMNI);
|
midi.begin(MIDI_CHANNEL_OMNI);
|
||||||
midi.setThruFilterMode(midi::Thru::Mode(42));
|
midi.setThruMap(thruMapNoteOnFullVelocity);
|
||||||
|
|
||||||
static const unsigned rxSize = 6;
|
static const unsigned rxSize = 6;
|
||||||
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
static const byte rxData[rxSize] = { 0x9b, 12, 34, 0x9c, 56, 78 };
|
||||||
serial.mRxBuffer.write(rxData, rxSize);
|
serial.mRxBuffer.write(rxData, rxSize);
|
||||||
|
|
||||||
EXPECT_EQ(midi.read(), false);
|
EXPECT_EQ(midi.read(), false);
|
||||||
|
EXPECT_EQ(serial.mTxBuffer.getLength(), 0);
|
||||||
EXPECT_EQ(midi.read(), false);
|
EXPECT_EQ(midi.read(), false);
|
||||||
EXPECT_EQ(midi.read(), true);
|
EXPECT_EQ(serial.mTxBuffer.getLength(), 0);
|
||||||
EXPECT_EQ(midi.read(), false);
|
|
||||||
EXPECT_EQ(midi.read(), false);
|
|
||||||
EXPECT_EQ(midi.read(), true);
|
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, 127 // thru message full velocity
|
||||||
|
}));
|
||||||
|
EXPECT_EQ(midi.getType(), midi::NoteOn);
|
||||||
|
EXPECT_EQ(midi.getChannel(), 12);
|
||||||
|
EXPECT_EQ(midi.getData1(), 12);
|
||||||
|
EXPECT_EQ(midi.getData2(), 34); // mMessage velocity unchanged
|
||||||
|
|
||||||
|
EXPECT_EQ(midi.read(), false);
|
||||||
EXPECT_EQ(serial.mTxBuffer.getLength(), 0);
|
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({
|
||||||
|
0x9c, 56, 127 // thru message full velocity
|
||||||
|
}));
|
||||||
|
EXPECT_EQ(midi.getType(), midi::NoteOn);
|
||||||
|
EXPECT_EQ(midi.getChannel(), 13);
|
||||||
|
EXPECT_EQ(midi.getData1(), 56);
|
||||||
|
EXPECT_EQ(midi.getData2(), 78); // mMessage velocity unchanged
|
||||||
}
|
}
|
||||||
|
|
||||||
END_UNNAMED_NAMESPACE
|
END_UNNAMED_NAMESPACE
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue