Skip to content

Commit 0020607

Browse files
committed
thru filter overhaul
* resolves FortySevenEffects#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 FortySevenEffects#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 d501f4b commit 0020607

File tree

6 files changed

+102
-174
lines changed

6 files changed

+102
-174
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

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

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

242-
inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
241+
using ThruFilterCallback = bool (*)(const MidiMessage& inMessage);
242+
using ThruMapCallback = MidiMessage (*)(const MidiMessage& inMessage);
243+
inline void turnThruOn(ThruFilterCallback fptr = thruOn);
243244
inline void turnThruOff();
244-
inline void setThruFilterMode(Thru::Mode inThruFilterMode);
245+
inline void setThruFilter(ThruFilterCallback fptr) { mThruFilterCallback = fptr; }
246+
inline void setThruMap(ThruMapCallback fptr) { mThruMapCallback = fptr; }
245247

246248
private:
247-
void thruFilter(byte inChannel);
249+
void thruFilter();
250+
static inline bool thruOn(const MidiMessage& inMessage) { (void)inMessage; return true; }
251+
static inline bool thruOff(const MidiMessage& inMessage) { (void)inMessage; return false; }
252+
static inline MidiMessage thruEcho(const MidiMessage& inMessage) { return inMessage; }
253+
ThruFilterCallback mThruFilterCallback;
254+
ThruMapCallback mThruMapCallback;
248255

249256
// -------------------------------------------------------------------------
250257
// MIDI Parsing
@@ -277,8 +284,6 @@ class MidiInterface
277284
unsigned mPendingMessageIndex;
278285
unsigned mCurrentRpnNumber;
279286
unsigned mCurrentNrpnNumber;
280-
bool mThruActivated : 1;
281-
Thru::Mode mThruFilterMode : 7;
282287
MidiMessage mMessage;
283288
unsigned long mLastMessageSentTime;
284289
unsigned long mLastMessageReceivedTime;

src/MIDI.hpp

+20-73
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,8 +91,8 @@ void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
9391
mMessage.data2 = 0;
9492
mMessage.length = 0;
9593

96-
mThruFilterMode = Thru::Full;
97-
mThruActivated = mTransport.thruActivated;
94+
mThruFilterCallback = thruOn;
95+
mThruMapCallback = thruEcho;
9896
}
9997

10098
// -----------------------------------------------------------------------------
@@ -771,7 +769,7 @@ inline bool MidiInterface<Transport, Settings, Platform>::read(Channel inChannel
771769
if (channelMatch)
772770
launchCallback();
773771

774-
thruFilter(inChannel);
772+
thruFilter();
775773

776774
return channelMatch;
777775
}
@@ -1343,42 +1341,22 @@ void MidiInterface<Transport, Settings, Platform>::launchCallback()
13431341
@{
13441342
*/
13451343

1346-
/*! \brief Set the filter for thru mirroring
1347-
\param inThruFilterMode a filter mode
1348-
1349-
@see Thru::Mode
1350-
*/
1351-
template<class Transport, class Settings, class Platform>
1352-
inline void MidiInterface<Transport, Settings, Platform>::setThruFilterMode(Thru::Mode inThruFilterMode)
1353-
{
1354-
mThruFilterMode = inThruFilterMode;
1355-
mThruActivated = mThruFilterMode != Thru::Off;
1356-
}
1357-
1358-
template<class Transport, class Settings, class Platform>
1359-
inline Thru::Mode MidiInterface<Transport, Settings, Platform>::getFilterMode() const
1360-
{
1361-
return mThruFilterMode;
1362-
}
1363-
13641344
template<class Transport, class Settings, class Platform>
13651345
inline bool MidiInterface<Transport, Settings, Platform>::getThruState() const
13661346
{
1367-
return mThruActivated;
1347+
return mThruFilterCallback != thruOff;
13681348
}
13691349

13701350
template<class Transport, class Settings, class Platform>
1371-
inline void MidiInterface<Transport, Settings, Platform>::turnThruOn(Thru::Mode inThruFilterMode)
1351+
inline void MidiInterface<Transport, Settings, Platform>::turnThruOn(ThruFilterCallback fptr)
13721352
{
1373-
mThruActivated = true;
1374-
mThruFilterMode = inThruFilterMode;
1353+
mThruFilterCallback = fptr;
13751354
}
13761355

13771356
template<class Transport, class Settings, class Platform>
13781357
inline void MidiInterface<Transport, Settings, Platform>::turnThruOff()
13791358
{
1380-
mThruActivated = false;
1381-
mThruFilterMode = Thru::Off;
1359+
mThruFilterCallback = thruOff;
13821360
}
13831361

13841362
template<class Transport, class Settings, class Platform>
@@ -1397,51 +1375,20 @@ inline void MidiInterface<Transport, Settings, Platform>::UpdateLastSentTime()
13971375
// - Channel messages are passed to the output whether their channel
13981376
// is matching the input channel and the filter setting
13991377
template<class Transport, class Settings, class Platform>
1400-
void MidiInterface<Transport, Settings, Platform>::thruFilter(Channel inChannel)
1378+
void MidiInterface<Transport, Settings, Platform>::thruFilter()
14011379
{
1402-
// If the feature is disabled, don't do anything.
1403-
if (!mThruActivated || (mThruFilterMode == Thru::Off))
1404-
return;
1380+
if (!mThruFilterCallback(mMessage))
1381+
return;
1382+
1383+
MidiMessage thruMessage = mThruMapCallback(mMessage);
14051384

14061385
// First, check if the received message is Channel
14071386
if (mMessage.type >= NoteOff && mMessage.type <= PitchBend)
14081387
{
1409-
const bool filter_condition = ((mMessage.channel == inChannel) ||
1410-
(inChannel == MIDI_CHANNEL_OMNI));
1411-
1412-
// Now let's pass it to the output
1413-
switch (mThruFilterMode)
1414-
{
1415-
case Thru::Full:
1416-
send(mMessage.type,
1417-
mMessage.data1,
1418-
mMessage.data2,
1419-
mMessage.channel);
1420-
break;
1421-
1422-
case Thru::SameChannel:
1423-
if (filter_condition)
1424-
{
1425-
send(mMessage.type,
1426-
mMessage.data1,
1427-
mMessage.data2,
1428-
mMessage.channel);
1429-
}
1430-
break;
1431-
1432-
case Thru::DifferentChannel:
1433-
if (!filter_condition)
1434-
{
1435-
send(mMessage.type,
1436-
mMessage.data1,
1437-
mMessage.data2,
1438-
mMessage.channel);
1439-
}
1440-
break;
1441-
1442-
default:
1443-
break;
1444-
}
1388+
send(thruMessage.type,
1389+
thruMessage.data1,
1390+
thruMessage.data2,
1391+
thruMessage.channel);
14451392
}
14461393
else
14471394
{
@@ -1461,19 +1408,19 @@ void MidiInterface<Transport, Settings, Platform>::thruFilter(Channel inChannel)
14611408

14621409
case SystemExclusive:
14631410
// Send SysEx (0xf0 and 0xf7 are included in the buffer)
1464-
sendSysEx(getSysExArrayLength(), getSysExArray(), true);
1411+
sendSysEx(thruMessage.getSysExSize(), thruMessage.sysexArray, true);
14651412
break;
14661413

14671414
case SongSelect:
1468-
sendSongSelect(mMessage.data1);
1415+
sendSongSelect(thruMessage.data1);
14691416
break;
14701417

14711418
case SongPosition:
1472-
sendSongPosition(mMessage.data1 | ((unsigned)mMessage.data2 << 7));
1419+
sendSongPosition(thruMessage.data1 | ((unsigned)thruMessage.data2 << 7));
14731420
break;
14741421

14751422
case TimeCodeQuarterFrame:
1476-
sendTimeCodeQuarterFrame(mMessage.data1,mMessage.data2);
1423+
sendTimeCodeQuarterFrame(thruMessage.data1,thruMessage.data2);
14771424
break;
14781425

14791426
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)