Skip to content

Commit a6c3a48

Browse files
hyperbolistfranky47
authored andcommitted
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.
1 parent 2d64cc3 commit a6c3a48

File tree

6 files changed

+110
-180
lines changed

6 files changed

+110
-180
lines changed

keywords.txt

-2
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,12 @@ getData1 KEYWORD2
5555
getData2 KEYWORD2
5656
getSysExArray KEYWORD2
5757
getSysExArrayLength KEYWORD2
58-
getFilterMode KEYWORD2
5958
getThruState KEYWORD2
6059
getInputChannel KEYWORD2
6160
check KEYWORD2
6261
setInputChannel KEYWORD2
6362
turnThruOn KEYWORD2
6463
turnThruOff KEYWORD2
65-
setThruFilterMode KEYWORD2
6664
disconnectCallbackFromType KEYWORD2
6765
setHandleNoteOff KEYWORD2
6866
setHandleNoteOn KEYWORD2

src/MIDI.h

+19-6
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,30 @@ class MidiInterface
236236
// MIDI Soft Thru
237237

238238
public:
239-
inline Thru::Mode getFilterMode() const;
240239
inline bool getThruState() const;
241240

242-
inline MidiInterface& turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
241+
using ThruFilterCallback = bool (*)(const MidiMessage& inMessage);
242+
using ThruMapCallback = MidiMessage (*)(const MidiMessage& inMessage);
243+
inline MidiInterface& turnThruOn(ThruFilterCallback fptr = thruOn);
243244
inline MidiInterface& turnThruOff();
244-
inline MidiInterface& setThruFilterMode(Thru::Mode inThruFilterMode);
245+
inline MidiInterface& setThruFilter(ThruFilterCallback fptr)
246+
{
247+
mThruFilterCallback = fptr;
248+
return *this;
249+
}
250+
inline MidiInterface& setThruMap(ThruMapCallback fptr)
251+
{
252+
mThruMapCallback = fptr;
253+
return *this;
254+
}
245255

246256
private:
247-
void thruFilter(byte inChannel);
257+
void thruFilter();
258+
static inline bool thruOn(const MidiMessage& inMessage) { (void)inMessage; return true; }
259+
static inline bool thruOff(const MidiMessage& inMessage) { (void)inMessage; return false; }
260+
static inline MidiMessage thruEcho(const MidiMessage& inMessage) { return inMessage; }
261+
ThruFilterCallback mThruFilterCallback;
262+
ThruMapCallback mThruMapCallback;
248263

249264
// -------------------------------------------------------------------------
250265
// MIDI Parsing
@@ -277,8 +292,6 @@ class MidiInterface
277292
unsigned mPendingMessageIndex;
278293
unsigned mCurrentRpnNumber;
279294
unsigned mCurrentNrpnNumber;
280-
bool mThruActivated : 1;
281-
Thru::Mode mThruFilterMode : 7;
282295
MidiMessage mMessage;
283296
unsigned long mLastMessageSentTime;
284297
unsigned long mLastMessageReceivedTime;

src/MIDI.hpp

+20-79
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ inline MidiInterface<Transport, Settings, Platform>::MidiInterface(Transport& in
4040
, mPendingMessageIndex(0)
4141
, mCurrentRpnNumber(0xffff)
4242
, mCurrentNrpnNumber(0xffff)
43-
, mThruActivated(true)
44-
, mThruFilterMode(Thru::Full)
4543
, mLastMessageSentTime(0)
4644
, mLastMessageReceivedTime(0)
4745
, mSenderActiveSensingPeriodicity(0)
@@ -93,9 +91,8 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
9391
mMessage.data2 = 0;
9492
mMessage.length = 0;
9593

96-
mThruFilterMode = Thru::Full;
97-
mThruActivated = mTransport.thruActivated;
98-
94+
mThruFilterCallback = thruOn;
95+
mThruMapCallback = thruEcho;
9996
return *this;
10097
}
10198

@@ -819,7 +816,7 @@ inline bool MidiInterface<Transport, Settings, Platform>::read(Channel inChannel
819816
if (channelMatch)
820817
launchCallback();
821818

822-
thruFilter(inChannel);
819+
thruFilter();
823820

824821
return channelMatch;
825822
}
@@ -1399,51 +1396,26 @@ void MidiInterface<Transport, Settings, Platform>::launchCallback()
13991396
@{
14001397
*/
14011398

1402-
/*! \brief Set the filter for thru mirroring
1403-
\param inThruFilterMode a filter mode
1404-
1405-
@see Thru::Mode
1406-
*/
1407-
template<class Transport, class Settings, class Platform>
1408-
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::setThruFilterMode(Thru::Mode inThruFilterMode)
1409-
{
1410-
mThruFilterMode = inThruFilterMode;
1411-
mThruActivated = mThruFilterMode != Thru::Off;
1412-
1413-
return *this;
1414-
}
1415-
1416-
template<class Transport, class Settings, class Platform>
1417-
inline Thru::Mode MidiInterface<Transport, Settings, Platform>::getFilterMode() const
1418-
{
1419-
return mThruFilterMode;
1420-
}
1421-
14221399
template<class Transport, class Settings, class Platform>
14231400
inline bool MidiInterface<Transport, Settings, Platform>::getThruState() const
14241401
{
1425-
return mThruActivated;
1402+
return mThruFilterCallback != thruOff;
14261403
}
14271404

14281405
template<class Transport, class Settings, class Platform>
1429-
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::turnThruOn(Thru::Mode inThruFilterMode)
1406+
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::turnThruOn(ThruFilterCallback fptr)
14301407
{
1431-
mThruActivated = true;
1432-
mThruFilterMode = inThruFilterMode;
1433-
1408+
mThruFilterCallback = fptr;
14341409
return *this;
14351410
}
14361411

14371412
template<class Transport, class Settings, class Platform>
14381413
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::turnThruOff()
14391414
{
1440-
mThruActivated = false;
1441-
mThruFilterMode = Thru::Off;
1442-
1415+
mThruFilterCallback = thruOff;
14431416
return *this;
14441417
}
14451418

1446-
14471419
/*! @} */ // End of doc group MIDI Thru
14481420

14491421
// This method is called upon reception of a message
@@ -1453,51 +1425,20 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
14531425
// - Channel messages are passed to the output whether their channel
14541426
// is matching the input channel and the filter setting
14551427
template<class Transport, class Settings, class Platform>
1456-
void MidiInterface<Transport, Settings, Platform>::thruFilter(Channel inChannel)
1428+
void MidiInterface<Transport, Settings, Platform>::thruFilter()
14571429
{
1458-
// If the feature is disabled, don't do anything.
1459-
if (!mThruActivated || (mThruFilterMode == Thru::Off))
1460-
return;
1430+
if (!mThruFilterCallback(mMessage))
1431+
return;
1432+
1433+
MidiMessage thruMessage = mThruMapCallback(mMessage);
14611434

14621435
// First, check if the received message is Channel
14631436
if (mMessage.type >= NoteOff && mMessage.type <= PitchBend)
14641437
{
1465-
const bool filter_condition = ((mMessage.channel == inChannel) ||
1466-
(inChannel == MIDI_CHANNEL_OMNI));
1467-
1468-
// Now let's pass it to the output
1469-
switch (mThruFilterMode)
1470-
{
1471-
case Thru::Full:
1472-
send(mMessage.type,
1473-
mMessage.data1,
1474-
mMessage.data2,
1475-
mMessage.channel);
1476-
break;
1477-
1478-
case Thru::SameChannel:
1479-
if (filter_condition)
1480-
{
1481-
send(mMessage.type,
1482-
mMessage.data1,
1483-
mMessage.data2,
1484-
mMessage.channel);
1485-
}
1486-
break;
1487-
1488-
case Thru::DifferentChannel:
1489-
if (!filter_condition)
1490-
{
1491-
send(mMessage.type,
1492-
mMessage.data1,
1493-
mMessage.data2,
1494-
mMessage.channel);
1495-
}
1496-
break;
1497-
1498-
default:
1499-
break;
1500-
}
1438+
send(thruMessage.type,
1439+
thruMessage.data1,
1440+
thruMessage.data2,
1441+
thruMessage.channel);
15011442
}
15021443
else
15031444
{
@@ -1517,19 +1458,19 @@ void MidiInterface<Transport, Settings, Platform>::thruFilter(Channel inChannel)
15171458

15181459
case SystemExclusive:
15191460
// Send SysEx (0xf0 and 0xf7 are included in the buffer)
1520-
sendSysEx(getSysExArrayLength(), getSysExArray(), true);
1461+
sendSysEx(thruMessage.getSysExSize(), thruMessage.sysexArray, true);
15211462
break;
15221463

15231464
case SongSelect:
1524-
sendSongSelect(mMessage.data1);
1465+
sendSongSelect(thruMessage.data1);
15251466
break;
15261467

15271468
case SongPosition:
1528-
sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2 << 7));
1469+
sendSongPosition(thruMessage.data1 | ((unsigned)thruMessage.data2 << 7));
15291470
break;
15301471

15311472
case TimeCodeQuarterFrame:
1532-
sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2);
1473+
sendTimeCodeQuarterFrame(thruMessage.data1,thruMessage.data2);
15331474
break;
15341475

15351476
default:

src/midi_Defs.h

-15
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ static const uint16_t ActiveSensingTimeout = 300;
5656
typedef byte StatusByte;
5757
typedef byte DataByte;
5858
typedef byte Channel;
59-
typedef byte FilterMode;
6059

6160
// -----------------------------------------------------------------------------
6261
// Errors
@@ -123,20 +122,6 @@ enum MidiType: uint8_t
123122

124123
// -----------------------------------------------------------------------------
125124

126-
/*! Enumeration of Thru filter modes */
127-
struct Thru
128-
{
129-
enum Mode
130-
{
131-
Off = 0, ///< Thru disabled (nothing passes through).
132-
Full = 1, ///< Fully enabled Thru (every incoming message is sent back).
133-
SameChannel = 2, ///< Only the messages on the Input Channel will be sent back.
134-
DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back.
135-
};
136-
};
137-
138-
// -----------------------------------------------------------------------------
139-
140125
/*! \brief Enumeration of Control Change command numbers.
141126
See the detailed controllers numbers & description here:
142127
http://www.somascape.org/midi/tech/spec.html#ctrlnums

test/unit-tests/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ add_executable(unit-tests
2323
tests/unit-tests_MidiThru.cpp
2424
)
2525

26+
set_source_files_properties(tests/unit-tests_MidiThru.cpp PROPERTIES COMPILE_FLAGS -Wno-shadow)
27+
2628
target_link_libraries(unit-tests
2729
gtest
2830
gmock

0 commit comments

Comments
 (0)