28 const uint8 noLSBValueReceived = 0xff;
29 const Range<int> allChannels { 1, 17 };
37 std::fill_n (isMemberChannelSustained, 16,
false);
46 legacyMode.isEnabled =
false;
47 legacyMode.pitchbendRange = 2;
66 legacyMode.isEnabled =
false;
76 legacyMode.isEnabled =
true;
77 legacyMode.pitchbendRange = pitchbendRange;
78 legacyMode.channelRange = channelRange;
84 return legacyMode.isEnabled;
89 return legacyMode.channelRange;
98 legacyMode.channelRange = channelRange;
103 return legacyMode.pitchbendRange;
108 jassert (pitchbendRange >= 0 && pitchbendRange <= 96);
112 legacyMode.pitchbendRange = pitchbendRange;
118 pressureDimension.trackingMode =
modeToUse;
123 pitchbendDimension.trackingMode =
modeToUse;
128 timbreDimension.trackingMode =
modeToUse;
147 if (message.
isNoteOn (
true)) processMidiNoteOnMessage (message);
148 else if (message.
isNoteOff (
false)) processMidiNoteOffMessage (message);
150 || message.
isAllNotesOff()) processMidiResetAllControllersMessage (message);
151 else if (message.
isPitchWheel()) processMidiPitchWheelMessage (message);
152 else if (message.
isChannelPressure()) processMidiChannelPressureMessage (message);
153 else if (message.
isController()) processMidiControllerMessage (message);
154 else if (message.
isAftertouch()) processMidiAfterTouchMessage (message);
158void MPEInstrument::processMidiNoteOnMessage (
const MidiMessage& message)
179void MPEInstrument::processMidiNoteOffMessage (
const MidiMessage& message)
182 message.getNoteNumber(),
187void MPEInstrument::processMidiPitchWheelMessage (
const MidiMessage& message)
194void MPEInstrument::processMidiChannelPressureMessage (
const MidiMessage& message)
201void MPEInstrument::processMidiControllerMessage (
const MidiMessage& message)
203 switch (message.getControllerNumber())
205 case 64:
sustainPedal (message.getChannel(), message.isSustainPedalOn());
break;
206 case 66:
sostenutoPedal (message.getChannel(), message.isSostenutoPedalOn());
break;
207 case 70: handlePressureMSB (message.getChannel(), message.getControllerValue());
break;
208 case 74: handleTimbreMSB (message.getChannel(), message.getControllerValue());
break;
209 case 102: handlePressureLSB (message.getChannel(), message.getControllerValue());
break;
210 case 106: handleTimbreLSB (message.getChannel(), message.getControllerValue());
break;
216void MPEInstrument::processMidiResetAllControllersMessage (
const MidiMessage& message)
221 if (legacyMode.isEnabled && legacyMode.channelRange.contains (message.getChannel()))
223 for (
auto i = notes.
size(); --i >= 0;)
227 if (note.midiChannel == message.getChannel())
231 listeners.call ([&] (Listener& l) { l.noteReleased (note); });
238 auto zone = (message.getChannel() == 1 ? zoneLayout.
getLowerZone()
241 for (
auto i = notes.
size(); --i >= 0;)
245 if (zone.isUsing (note.midiChannel))
249 listeners.call ([&] (Listener& l) { l.noteReleased (note); });
256void MPEInstrument::processMidiAfterTouchMessage (
const MidiMessage& message)
266void MPEInstrument::handlePressureMSB (
int midiChannel,
int value)
noexcept
268 auto lsb = lastPressureLowerBitReceivedOnChannel[midiChannel - 1];
271 : MPEValue::from14BitInt (lsb + (value << 7)));
274void MPEInstrument::handlePressureLSB (
int midiChannel,
int value)
noexcept
276 lastPressureLowerBitReceivedOnChannel[midiChannel - 1] = uint8 (value);
279void MPEInstrument::handleTimbreMSB (
int midiChannel,
int value)
noexcept
281 auto lsb = lastTimbreLowerBitReceivedOnChannel[midiChannel - 1];
284 : MPEValue::from14BitInt (lsb + (value << 7)));
287void MPEInstrument::handleTimbreLSB (
int midiChannel,
int value)
noexcept
289 lastTimbreLowerBitReceivedOnChannel[midiChannel - 1] = uint8 (value);
303 getInitialValueForNewNote (midiChannel, pitchbendDimension),
304 getInitialValueForNewNote (midiChannel, pressureDimension),
305 getInitialValueForNewNote (midiChannel, timbreDimension),
309 updateNoteTotalPitchbend (
newNote);
340 if (getLastNotePlayedPtr (midiChannel) ==
nullptr)
354 listeners.call ([=] (
Listener&
l) {
l.noteKeyStateChanged (*
note); });
363 updateDimension (midiChannel, pitchbendDimension, value);
369 updateDimension (midiChannel, pressureDimension, value);
375 updateDimension (midiChannel, timbreDimension, value);
382 for (
auto i = notes.
size(); --i >= 0;)
386 if (
note.midiChannel == midiChannel
388 && pressureDimension.getValue (
note) != value)
390 pressureDimension.getValue (
note) = value;
391 callListenersDimensionChanged (
note, pressureDimension);
396MPEValue MPEInstrument::getInitialValueForNewNote (
int midiChannel, MPEDimension&
dimension)
const
398 if (getLastNotePlayedPtr (midiChannel) !=
nullptr)
401 return dimension.lastValueReceivedOnChannel[midiChannel - 1];
405void MPEInstrument::updateDimension (
int midiChannel, MPEDimension& dimension, MPEValue value)
407 dimension.lastValueReceivedOnChannel[midiChannel - 1] = value;
416 for (
auto i = notes.
size(); --i >= 0;)
420 if (note.midiChannel == midiChannel)
421 updateDimensionForNote (note, dimension, value);
426 if (
auto* note = getNotePtr (midiChannel, dimension.trackingMode))
427 updateDimensionForNote (*note, dimension, value);
432 updateDimensionMaster (midiChannel == 1, dimension, value);
437void MPEInstrument::updateDimensionMaster (
bool isLowerZone, MPEDimension& dimension, MPEValue value)
442 if (! zone.isActive())
445 for (
auto i = notes.
size(); --i >= 0;)
449 if (! zone.isUsing (note.midiChannel))
452 if (&dimension == &pitchbendDimension)
456 updateNoteTotalPitchbend (note);
457 listeners.call ([&] (Listener& l) { l.notePitchbendChanged (note); });
459 else if (dimension.getValue (note) != value)
461 dimension.getValue (note) = value;
462 callListenersDimensionChanged (note, dimension);
468void MPEInstrument::updateDimensionForNote (MPENote& note, MPEDimension& dimension, MPEValue value)
470 if (dimension.getValue (note) != value)
472 dimension.getValue (note) = value;
474 if (&dimension == &pitchbendDimension)
475 updateNoteTotalPitchbend (note);
477 callListenersDimensionChanged (note, dimension);
482void MPEInstrument::callListenersDimensionChanged (
const MPENote& note,
const MPEDimension& dimension)
484 if (&dimension == &pressureDimension) { listeners.call ([&] (Listener& l) { l.notePressureChanged (note); });
return; }
485 if (&dimension == &timbreDimension) { listeners.call ([&] (Listener& l) { l.noteTimbreChanged (note); });
return; }
486 if (&dimension == &pitchbendDimension) { listeners.call ([&] (Listener& l) { l.notePitchbendChanged (note); });
return; }
490void MPEInstrument::updateNoteTotalPitchbend (MPENote& note)
492 if (legacyMode.isEnabled)
494 note.totalPitchbendInSemitones = note.pitchbend.asSignedFloat() * legacyMode.pitchbendRange;
500 if (! zone.isUsing (note.midiChannel))
502 if (zoneLayout.
getUpperZone().isUsing (note.midiChannel))
514 auto notePitchbendInSemitones = 0.0f;
516 if (zone.isUsingChannelAsMemberChannel (note.midiChannel))
517 notePitchbendInSemitones = note.pitchbend.asSignedFloat() * zone.perNotePitchbendRange;
519 auto masterPitchbendInSemitones = pitchbendDimension.lastValueReceivedOnChannel[zone.getMasterChannel() - 1]
521 * zone.masterPitchbendRange;
523 note.totalPitchbendInSemitones = notePitchbendInSemitones + masterPitchbendInSemitones;
531 handleSustainOrSostenuto (midiChannel,
isDown,
false);
537 handleSustainOrSostenuto (midiChannel,
isDown,
true);
541void MPEInstrument::handleSustainOrSostenuto (
int midiChannel,
bool isDown,
bool isSostenuto)
546 if (legacyMode.isEnabled ? (! legacyMode.channelRange.contains (midiChannel)) : (!
isMasterChannel (midiChannel)))
549 auto zone = (midiChannel == 1 ? zoneLayout.
getLowerZone()
552 for (
auto i = notes.
size(); --i >= 0;)
556 if (legacyMode.isEnabled ? (
note.midiChannel == midiChannel) : zone.isUsing (
note.midiChannel))
567 listeners.call ([&] (Listener&
l) {
l.noteReleased (
note); });
572 listeners.call ([&] (Listener& l) { l.noteKeyStateChanged (note); });
579 if (legacyMode.isEnabled)
581 isMemberChannelSustained[midiChannel - 1] = isDown;
585 if (zone.isLowerZone())
586 for (
auto i = zone.getFirstMemberChannel(); i <= zone.getLastMemberChannel(); ++i)
587 isMemberChannelSustained[i - 1] = isDown;
589 for (
auto i = zone.getFirstMemberChannel(); i >= zone.getLastMemberChannel(); --i)
590 isMemberChannelSustained[i - 1] = isDown;
598 if (legacyMode.isEnabled)
599 return legacyMode.channelRange.
contains (midiChannel);
601 return zoneLayout.getLowerZone().isUsingChannelAsMemberChannel (midiChannel)
602 || zoneLayout.getUpperZone().isUsingChannelAsMemberChannel (midiChannel);
607 if (legacyMode.isEnabled)
610 const auto lowerZone = zoneLayout.getLowerZone();
611 const auto upperZone = zoneLayout.getUpperZone();
613 return (lowerZone.isActive() && midiChannel == lowerZone.getMasterChannel())
614 || (upperZone.isActive() && midiChannel == upperZone.getMasterChannel());
619 if (legacyMode.isEnabled)
620 return legacyMode.channelRange.
contains (midiChannel);
622 return zoneLayout.getLowerZone().isUsing (midiChannel)
623 || zoneLayout.getUpperZone().isUsing (midiChannel);
648 if (
auto*
note = getLastNotePlayedPtr (midiChannel))
656 for (
auto i = notes.size(); --i >= 0;)
670 for (
int i = 0; i < notes.size(); ++i)
681MPENote* MPEInstrument::getNotePtr (
int midiChannel,
int midiNoteNumber)
noexcept
683 return const_cast<MPENote*
> (
static_cast<const MPEInstrument&
> (*this).getNotePtr (midiChannel, midiNoteNumber));
687const MPENote* MPEInstrument::getNotePtr (
int midiChannel, TrackingMode mode)
const noexcept
691 jassert (mode != allNotesOnChannel);
693 if (mode == lastNotePlayedOnChannel)
return getLastNotePlayedPtr (midiChannel);
694 if (mode == lowestNoteOnChannel)
return getLowestNotePtr (midiChannel);
695 if (mode == highestNoteOnChannel)
return getHighestNotePtr (midiChannel);
700MPENote* MPEInstrument::getNotePtr (
int midiChannel, TrackingMode mode)
noexcept
702 return const_cast<MPENote*
> (
static_cast<const MPEInstrument&
> (*this).getNotePtr (midiChannel, mode));
706const MPENote* MPEInstrument::getLastNotePlayedPtr (
int midiChannel)
const noexcept
708 for (
auto i = notes.size(); --i >= 0;)
710 auto& note = notes.getReference (i);
712 if (note.midiChannel == midiChannel
720MPENote* MPEInstrument::getLastNotePlayedPtr (
int midiChannel)
noexcept
722 return const_cast<MPENote*
> (
static_cast<const MPEInstrument&
> (*this).getLastNotePlayedPtr (midiChannel));
726const MPENote* MPEInstrument::getHighestNotePtr (
int midiChannel)
const noexcept
728 int initialNoteMax = -1;
729 const MPENote* result =
nullptr;
731 for (
auto i = notes.size(); --i >= 0;)
733 auto& note = notes.getReference (i);
735 if (note.midiChannel == midiChannel
737 && note.initialNote > initialNoteMax)
740 initialNoteMax = note.initialNote;
747MPENote* MPEInstrument::getHighestNotePtr (
int midiChannel)
noexcept
749 return const_cast<MPENote*
> (
static_cast<const MPEInstrument&
> (*this).getHighestNotePtr (midiChannel));
752const MPENote* MPEInstrument::getLowestNotePtr (
int midiChannel)
const noexcept
754 int initialNoteMin = 128;
755 const MPENote* result =
nullptr;
757 for (
auto i = notes.size(); --i >= 0;)
759 auto& note = notes.getReference (i);
761 if (note.midiChannel == midiChannel
763 && note.initialNote < initialNoteMin)
766 initialNoteMin = note.initialNote;
773MPENote* MPEInstrument::getLowestNotePtr (
int midiChannel)
noexcept
775 return const_cast<MPENote*
> (
static_cast<const MPEInstrument&
> (*this).getLowestNotePtr (midiChannel));
783 for (
auto i = notes.
size(); --i >= 0;)
803 :
UnitTest (
"MPEInstrument class", UnitTestCategories::midi)
814 void runTest()
override
816 beginTest (
"initial zone layout");
819 expect (!
test.getZoneLayout().getLowerZone().isActive());
820 expect (!
test.getZoneLayout().getUpperZone().isActive());
823 beginTest (
"get/setZoneLayout");
830 expect (
test.getZoneLayout().getLowerZone().isActive());
831 expect (
test.getZoneLayout().getUpperZone().isActive());
832 expectEquals (
newLayout.getLowerZone().getMasterChannel(), 1);
833 expectEquals (
newLayout.getLowerZone().numMemberChannels, 5);
834 expectEquals (
newLayout.getUpperZone().getMasterChannel(), 16);
835 expectEquals (
newLayout.getUpperZone().numMemberChannels, 6);
838 beginTest (
"noteOn / noteOff");
843 expectEquals (
test.getNumPlayingNotes(), 0);
851 expectEquals (
test.getNumPlayingNotes(), 0);
852 expectEquals (
test.noteAddedCallCounter, 0);
856 expectEquals (
test.getNumPlayingNotes(), 1);
857 expectEquals (
test.noteAddedCallCounter, 1);
862 expectEquals (
test.getNumPlayingNotes(), 0);
863 expectEquals (
test.noteReleasedCallCounter, 1);
869 expectEquals (
test.getNumPlayingNotes(), 1);
870 expectEquals (
test.noteAddedCallCounter, 2);
875 expectEquals (
test.getNumPlayingNotes(), 0);
876 expectEquals (
test.noteReleasedCallCounter, 2);
887 expectEquals (
test.getNumPlayingNotes(), 1);
889 expectEquals (
test.noteReleasedCallCounter, 0);
893 expectEquals (
test.getNumPlayingNotes(), 1);
895 expectEquals (
test.noteReleasedCallCounter, 0);
905 expectEquals (
test.getNumPlayingNotes(), 3);
916 expectEquals (
test.getNumPlayingNotes(), 1);
921 beginTest (
"noteReleased after setZoneLayout");
929 expectEquals (
test.getNumPlayingNotes(), 3);
930 expectEquals (
test.noteReleasedCallCounter, 0);
933 expectEquals (
test.getNumPlayingNotes(), 0);
934 expectEquals (
test.noteReleasedCallCounter, 3);
937 beginTest (
"releaseAllNotes");
944 expectEquals (
test.getNumPlayingNotes(), 3);
946 test.releaseAllNotes();
947 expectEquals (
test.getNumPlayingNotes(), 0);
950 beginTest (
"sustainPedal");
958 test.sustainPedal (3,
true);
963 expectEquals (
test.noteKeyStateChangedCallCounter, 0);
966 test.sustainPedal (7,
true);
969 expectEquals (
test.noteKeyStateChangedCallCounter, 0);
972 test.sustainPedal (1,
true);
975 expectEquals (
test.noteKeyStateChangedCallCounter, 1);
978 test.sustainPedal (1,
false);
981 expectEquals (
test.noteKeyStateChangedCallCounter, 2);
984 test.sustainPedal (1,
true);
985 expectEquals (
test.noteKeyStateChangedCallCounter, 3);
988 expectEquals (
test.noteKeyStateChangedCallCounter, 3);
991 test.sustainPedal (11,
true);
995 expectEquals (
test.noteReleasedCallCounter, 1);
1001 expectEquals (
test.getNumPlayingNotes(), 2);
1002 expectEquals (
test.noteReleasedCallCounter, 2);
1003 expectEquals (
test.noteKeyStateChangedCallCounter, 5);
1008 test.sustainPedal (1,
false);
1009 expectEquals (
test.getNumPlayingNotes(), 0);
1010 expectEquals (
test.noteReleasedCallCounter, 4);
1013 beginTest (
"sostenutoPedal");
1021 test.sostenutoPedal (3,
true);
1024 expectEquals (
test.noteKeyStateChangedCallCounter, 0);
1027 test.sostenutoPedal (9,
true);
1030 expectEquals (
test.noteKeyStateChangedCallCounter, 0);
1033 test.sostenutoPedal (1,
true);
1036 expectEquals (
test.noteKeyStateChangedCallCounter, 1);
1039 test.sostenutoPedal (1,
false);
1042 expectEquals (
test.noteKeyStateChangedCallCounter, 2);
1045 test.sostenutoPedal (1,
true);
1046 expectEquals (
test.noteKeyStateChangedCallCounter, 3);
1048 expectEquals (
test.getNumPlayingNotes(), 3);
1052 expectEquals (
test.noteKeyStateChangedCallCounter, 3);
1059 expectEquals (
test.getNumPlayingNotes(), 1);
1061 expectEquals (
test.noteReleasedCallCounter, 2);
1062 expectEquals (
test.noteKeyStateChangedCallCounter, 4);
1065 test.sustainPedal (1,
false);
1066 expectEquals (
test.getNumPlayingNotes(), 0);
1067 expectEquals (
test.noteReleasedCallCounter, 3);
1070 beginTest (
"getMostRecentNote");
1079 auto note =
test.getMostRecentNote (2);
1080 expect (!
note.isValid());
1083 auto note =
test.getMostRecentNote (3);
1084 expect (
note.isValid());
1085 expectEquals (
int (
note.midiChannel), 3);
1086 expectEquals (
int (
note.initialNote), 61);
1089 test.sustainPedal (1,
true);
1093 auto note =
test.getMostRecentNote (3);
1094 expect (
note.isValid());
1095 expectEquals (
int (
note.midiChannel), 3);
1096 expectEquals (
int (
note.initialNote), 60);
1099 test.sustainPedal (1,
false);
1103 auto note =
test.getMostRecentNote (3);
1104 expect (!
note.isValid());
1108 beginTest (
"getMostRecentNoteOtherThan");
1119 expect (!
test.getMostRecentNoteOtherThan (
testNote).isValid());
1122 expect (!
test.getMostRecentNoteOtherThan (
testNote).isValid());
1125 expect (
test.getMostRecentNoteOtherThan (
testNote).isValid());
1126 expect (
test.getMostRecentNoteOtherThan (
testNote).midiChannel == 4);
1127 expect (
test.getMostRecentNoteOtherThan (
testNote).initialNote == 61);
1134 expect (!
test.getMostRecentNoteOtherThan (
testNote).isValid());
1137 expect (
test.getMostRecentNoteOtherThan (
testNote).isValid());
1138 expect (
test.getMostRecentNoteOtherThan (
testNote).midiChannel == 4);
1139 expect (
test.getMostRecentNoteOtherThan (
testNote).initialNote == 61);
1142 expect (
test.getMostRecentNoteOtherThan (
testNote).isValid());
1143 expect (
test.getMostRecentNoteOtherThan (
testNote).midiChannel == 4);
1144 expect (
test.getMostRecentNoteOtherThan (
testNote).initialNote == 61);
1148 beginTest (
"pressure");
1163 expectEquals (
test.notePressureChangedCallCounter, 1);
1170 expectEquals (
test.notePressureChangedCallCounter, 3);
1177 expectEquals (
test.notePressureChangedCallCounter, 3);
1189 expectEquals (
test.notePressureChangedCallCounter, 1);
1201 expectEquals (
test.getNumPlayingNotes(), 1);
1203 expectEquals (
test.notePressureChangedCallCounter, 1);
1266 beginTest (
"pitchbend");
1281 expectEquals (
test.notePitchbendChangedCallCounter, 1);
1291 expectEquals (
test.notePitchbendChangedCallCounter, 3);
1298 expectEquals (
test.notePitchbendChangedCallCounter, 3);
1310 expectEquals (
test.notePitchbendChangedCallCounter, 1);
1322 expectEquals (
test.getNumPlayingNotes(), 1);
1324 expectEquals (
test.notePitchbendChangedCallCounter, 1);
1339 test.sustainPedal (1,
true);
1341 expectEquals (
test.getNumPlayingNotes(), 1);
1343 expectEquals (
test.noteKeyStateChangedCallCounter, 2);
1347 expectEquals (
test.getNumPlayingNotes(), 2);
1350 expectEquals (
test.notePitchbendChangedCallCounter, 1);
1383 layout.setLowerZone (5, 96);
1389 layout.setLowerZone (5, 1);
1395 layout.setLowerZone (5, 0);
1412 layout.setLowerZone (5, 48, 96);
1418 layout.setLowerZone (5, 48, 1);
1424 layout.setLowerZone (5, 48, 0);
1437 layout.setLowerZone (5, 12, 1);
1449 beginTest (
"timbre");
1464 expectEquals (
test.noteTimbreChangedCallCounter, 1);
1471 expectEquals (
test.noteTimbreChangedCallCounter, 3);
1478 expectEquals (
test.noteTimbreChangedCallCounter, 3);
1490 expectEquals (
test.noteTimbreChangedCallCounter, 1);
1502 expectEquals (
test.getNumPlayingNotes(), 1);
1504 expectEquals (
test.noteTimbreChangedCallCounter, 1);
1521 beginTest (
"setPressureTrackingMode");
1536 expectEquals (
test.notePressureChangedCallCounter, 1);
1551 expectEquals (
test.notePressureChangedCallCounter, 1);
1566 expectEquals (
test.notePressureChangedCallCounter, 1);
1581 expectEquals (
test.notePressureChangedCallCounter, 3);
1585 beginTest (
"setPitchbendTrackingMode");
1600 expectEquals (
test.notePitchbendChangedCallCounter, 1);
1615 expectEquals (
test.notePitchbendChangedCallCounter, 1);
1630 expectEquals (
test.notePitchbendChangedCallCounter, 1);
1645 expectEquals (
test.notePitchbendChangedCallCounter, 3);
1649 beginTest (
"setTimbreTrackingMode");
1664 expectEquals (
test.noteTimbreChangedCallCounter, 1);
1679 expectEquals (
test.noteTimbreChangedCallCounter, 1);
1694 expectEquals (
test.noteTimbreChangedCallCounter, 1);
1709 expectEquals (
test.noteTimbreChangedCallCounter, 3);
1713 beginTest (
"processNextMidiEvent");
1720 expectEquals (
test.noteOnCallCounter, 1);
1721 expectEquals (
test.lastMidiChannelReceived, 3);
1722 expectEquals (
test.lastMidiNoteNumberReceived, 42);
1723 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 92);
1728 expectEquals (
test.noteOffCallCounter, 1);
1729 expectEquals (
test.lastMidiChannelReceived, 4);
1730 expectEquals (
test.lastMidiNoteNumberReceived, 12);
1731 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 33);
1737 expectEquals (
test.noteOffCallCounter, 2);
1738 expectEquals (
test.lastMidiChannelReceived, 5);
1739 expectEquals (
test.lastMidiNoteNumberReceived, 11);
1740 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 64);
1745 expectEquals (
test.pitchbendCallCounter, 1);
1746 expectEquals (
test.lastMidiChannelReceived, 1);
1747 expectEquals (
test.lastMPEValueReceived.as14BitInt(), 3333);
1753 expectEquals (
test.pressureCallCounter, 1);
1754 expectEquals (
test.lastMidiChannelReceived, 10);
1755 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 35);
1762 expectEquals (
test.pressureCallCounter, 2);
1763 expectEquals (
test.lastMidiChannelReceived, 3);
1764 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 120);
1768 expectEquals (
test.pressureCallCounter, 2);
1770 expectEquals (
test.pressureCallCounter, 2);
1772 expectEquals (
test.pressureCallCounter, 3);
1773 expectEquals (
test.lastMidiChannelReceived, 4);
1774 expectEquals (
test.lastMPEValueReceived.as14BitInt(), 121 + (123 << 7));
1776 expectEquals (
test.pressureCallCounter, 4);
1777 expectEquals (
test.lastMidiChannelReceived, 5);
1778 expectEquals (
test.lastMPEValueReceived.as14BitInt(), 122 + (124 << 7));
1780 expectEquals (
test.pressureCallCounter, 5);
1781 expectEquals (
test.lastMidiChannelReceived, 5);
1782 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 64);
1786 expectEquals (
test.timbreCallCounter, 1);
1787 expectEquals (
test.lastMidiChannelReceived, 3);
1788 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 120);
1790 expectEquals (
test.timbreCallCounter, 1);
1792 expectEquals (
test.timbreCallCounter, 1);
1794 expectEquals (
test.timbreCallCounter, 2);
1795 expectEquals (
test.lastMidiChannelReceived, 4);
1796 expectEquals (
test.lastMPEValueReceived.as14BitInt(), 121 + (123 << 7));
1798 expectEquals (
test.timbreCallCounter, 3);
1799 expectEquals (
test.lastMidiChannelReceived, 5);
1800 expectEquals (
test.lastMPEValueReceived.as14BitInt(), 122 + (124 << 7));
1802 expectEquals (
test.timbreCallCounter, 4);
1803 expectEquals (
test.lastMidiChannelReceived, 5);
1804 expectEquals (
test.lastMPEValueReceived.as7BitInt(), 64);
1808 expectEquals (
test.sustainPedalCallCounter, 1);
1809 expectEquals (
test.lastMidiChannelReceived, 1);
1810 expect (
test.lastSustainPedalValueReceived);
1812 expectEquals (
test.sustainPedalCallCounter, 2);
1813 expectEquals (
test.lastMidiChannelReceived, 16);
1814 expect (!
test.lastSustainPedalValueReceived);
1818 expectEquals (
test.sostenutoPedalCallCounter, 1);
1819 expectEquals (
test.lastMidiChannelReceived, 1);
1820 expect (
test.lastSostenutoPedalValueReceived);
1822 expectEquals (
test.sostenutoPedalCallCounter, 2);
1823 expectEquals (
test.lastMidiChannelReceived, 16);
1824 expect (!
test.lastSostenutoPedalValueReceived);
1837 MidiBuffer::Iterator
iter (buffer);
1838 MidiMessage message;
1842 test.processNextMidiEvent (message);
1844 expect (
test.getZoneLayout().getLowerZone().isActive());
1845 expect (
test.getZoneLayout().getUpperZone().isActive());
1846 expectEquals (
test.getZoneLayout().getLowerZone().getMasterChannel(), 1);
1847 expectEquals (
test.getZoneLayout().getLowerZone().numMemberChannels, 5);
1848 expectEquals (
test.getZoneLayout().getUpperZone().getMasterChannel(), 16);
1849 expectEquals (
test.getZoneLayout().getUpperZone().numMemberChannels, 6);
1852 beginTest (
"MIDI all notes off");
1860 expectEquals (
test.getNumPlayingNotes(), 4);
1864 expectEquals (
test.getNumPlayingNotes(), 4);
1868 expectEquals (
test.getNumPlayingNotes(), 4);
1872 expectEquals (
test.getNumPlayingNotes(), 2);
1874 expectEquals (
test.getNumPlayingNotes(), 0);
1877 beginTest (
"MIDI all notes off (legacy mode)");
1880 test.enableLegacyMode();
1885 expectEquals (
test.getNumPlayingNotes(), 4);
1888 expectEquals (
test.getNumPlayingNotes(), 3);
1891 expectEquals (
test.getNumPlayingNotes(), 1);
1894 expectEquals (
test.getNumPlayingNotes(), 0);
1897 beginTest (
"default initial values for pitchbend and timbre");
1915 beginTest (
"Legacy mode");
1920 expect (!
test.isLegacyModeEnabled());
1923 expect (!
test.isLegacyModeEnabled());
1925 test.enableLegacyMode();
1926 expect (
test.isLegacyModeEnabled());
1929 expect (!
test.isLegacyModeEnabled());
1934 test.enableLegacyMode (0, Range<int> (1, 11));
1935 expectEquals (
test.getLegacyModePitchbendRange(), 0);
1936 expect (
test.getLegacyModeChannelRange() == Range<int> (1, 11));
1941 test.enableLegacyMode();
1943 expectEquals (
test.getLegacyModePitchbendRange(), 2);
1944 expect (
test.getLegacyModeChannelRange() == Range<int> (1, 17));
1946 test.setLegacyModePitchbendRange (96);
1947 expectEquals (
test.getLegacyModePitchbendRange(), 96);
1949 test.setLegacyModeChannelRange (Range<int> (10, 12));
1950 expect (
test.getLegacyModeChannelRange() == Range<int> (10, 12));
1956 test.enableLegacyMode();
1962 expectEquals (
test.getNumPlayingNotes(), 4);
1981 expectEquals (
test.getNumPlayingNotes(), 0);
1987 test.enableLegacyMode (2, Range<int> (3, 8));
1998 expectEquals (
test.getNumPlayingNotes(), 4);
2008 test.enableLegacyMode();
2021 test.enableLegacyMode();
2034 test.enableLegacyMode();
2047 test.enableLegacyMode();
2062 test.enableLegacyMode (11);
2071 test.enableLegacyMode();
2073 test.sustainPedal (1,
true);
2079 expectEquals (
test.getNumPlayingNotes(), 1);
2082 test.sustainPedal (1,
false);
2083 expectEquals (
test.getNumPlayingNotes(), 0);
2086 test.sustainPedal (1,
true);
2088 expectEquals (
test.getNumPlayingNotes(), 0);
2094 test.enableLegacyMode();
2097 test.sostenutoPedal (1,
true);
2102 expectEquals (
test.getNumPlayingNotes(), 1);
2105 test.sostenutoPedal (1,
false);
2106 expectEquals (
test.getNumPlayingNotes(), 0);
2109 test.sostenutoPedal (1,
true);
2111 expectEquals (
test.getNumPlayingNotes(), 0);
2118 expectEquals (
test.getNumPlayingNotes(), 1);
2120 test.enableLegacyMode();
2121 expectEquals (
test.getNumPlayingNotes(), 0);
2123 expectEquals (
test.getNumPlayingNotes(), 1);
2126 expectEquals (
test.getNumPlayingNotes(), 0);
2137 private MPEInstrument::Listener
2139 using Base = MPEInstrument;
2142 UnitTestInstrument()
2143 : noteOnCallCounter (0), noteOffCallCounter (0), pitchbendCallCounter (0),
2144 pressureCallCounter (0), timbreCallCounter (0), sustainPedalCallCounter (0),
2145 sostenutoPedalCallCounter (0), noteAddedCallCounter (0), notePressureChangedCallCounter (0),
2146 notePitchbendChangedCallCounter (0), noteTimbreChangedCallCounter (0),
2147 noteKeyStateChangedCallCounter (0), noteReleasedCallCounter (0),
2148 lastMidiChannelReceived (-1), lastMidiNoteNumberReceived (-1),
2149 lastSustainPedalValueReceived (false), lastSostenutoPedalValueReceived (false)
2154 void noteOn (
int midiChannel,
int midiNoteNumber, MPEValue midiNoteOnVelocity)
override
2156 Base::noteOn (midiChannel, midiNoteNumber, midiNoteOnVelocity);
2158 noteOnCallCounter++;
2159 lastMidiChannelReceived = midiChannel;
2160 lastMidiNoteNumberReceived = midiNoteNumber;
2161 lastMPEValueReceived = midiNoteOnVelocity;
2164 void noteOff (
int midiChannel,
int midiNoteNumber, MPEValue midiNoteOffVelocity)
override
2166 Base::noteOff (midiChannel, midiNoteNumber, midiNoteOffVelocity);
2168 noteOffCallCounter++;
2169 lastMidiChannelReceived = midiChannel;
2170 lastMidiNoteNumberReceived = midiNoteNumber;
2171 lastMPEValueReceived = midiNoteOffVelocity;
2174 void pitchbend (
int midiChannel, MPEValue value)
override
2176 Base::pitchbend (midiChannel, value);
2178 pitchbendCallCounter++;
2179 lastMidiChannelReceived = midiChannel;
2180 lastMPEValueReceived = value;
2183 void pressure (
int midiChannel, MPEValue value)
override
2185 Base::pressure (midiChannel, value);
2187 pressureCallCounter++;
2188 lastMidiChannelReceived = midiChannel;
2189 lastMPEValueReceived = value;
2192 void timbre (
int midiChannel, MPEValue value)
override
2194 Base::timbre (midiChannel, value);
2196 timbreCallCounter++;
2197 lastMidiChannelReceived = midiChannel;
2198 lastMPEValueReceived = value;
2201 void sustainPedal (
int midiChannel,
bool value)
override
2203 Base::sustainPedal (midiChannel, value);
2205 sustainPedalCallCounter++;
2206 lastMidiChannelReceived = midiChannel;
2207 lastSustainPedalValueReceived = value;
2210 void sostenutoPedal (
int midiChannel,
bool value)
override
2212 Base::sostenutoPedal (midiChannel, value);
2214 sostenutoPedalCallCounter++;
2215 lastMidiChannelReceived = midiChannel;
2216 lastSostenutoPedalValueReceived = value;
2219 void aftertouch (
int midiChannel,
int midiNoteNumber, MPEValue value)
2222 processNextMidiEvent (message);
2225 int noteOnCallCounter, noteOffCallCounter, pitchbendCallCounter,
2226 pressureCallCounter, timbreCallCounter, sustainPedalCallCounter,
2227 sostenutoPedalCallCounter, noteAddedCallCounter,
2228 notePressureChangedCallCounter, notePitchbendChangedCallCounter,
2229 noteTimbreChangedCallCounter, noteKeyStateChangedCallCounter,
2230 noteReleasedCallCounter, lastMidiChannelReceived, lastMidiNoteNumberReceived;
2232 bool lastSustainPedalValueReceived, lastSostenutoPedalValueReceived;
2233 MPEValue lastMPEValueReceived;
2234 std::unique_ptr<MPENote> lastNoteFinished;
2238 void noteAdded (MPENote)
override { noteAddedCallCounter++; }
2240 void notePressureChanged (MPENote)
override { notePressureChangedCallCounter++; }
2241 void notePitchbendChanged (MPENote)
override { notePitchbendChangedCallCounter++; }
2242 void noteTimbreChanged (MPENote)
override { noteTimbreChangedCallCounter++; }
2243 void noteKeyStateChanged (MPENote)
override { noteKeyStateChangedCallCounter++; }
2245 void noteReleased (MPENote finishedNote)
override
2247 noteReleasedCallCounter++;
2248 lastNoteFinished.reset (
new MPENote (finishedNote));
2271 expect (
test.lastNoteFinished !=
nullptr);
2272 expectEquals (
int (
test.lastNoteFinished->midiChannel), channel);
2273 expectEquals (
int (
test.lastNoteFinished->initialNote),
noteNumber);
2288static MPEInstrumentTests MPEInstrumentUnitTests;
bool isEmpty() const noexcept
int size() const noexcept
void remove(int indexToRemove)
void add(const ElementType &newElement)
bool contains(ParameterType elementToLookFor) const
ElementType & getReference(int index) noexcept
void setPitchbendTrackingMode(TrackingMode modeToUse)
void setLegacyModeChannelRange(Range< int > channelRange)
MPENote getMostRecentNoteOtherThan(MPENote otherThanThisNote) const noexcept
MPEZoneLayout getZoneLayout() const noexcept
virtual void sostenutoPedal(int midiChannel, bool isDown)
virtual void pitchbend(int midiChannel, MPEValue pitchbend)
bool isMemberChannel(int midiChannel) const noexcept
void enableLegacyMode(int pitchbendRange=2, Range< int > channelRange=Range< int >(1, 17))
MPENote getNote(int index) const noexcept
@ lastNotePlayedOnChannel
void setZoneLayout(MPEZoneLayout newLayout)
virtual void polyAftertouch(int midiChannel, int midiNoteNumber, MPEValue value)
virtual void processNextMidiEvent(const MidiMessage &message)
void setLegacyModePitchbendRange(int pitchbendRange)
bool isLegacyModeEnabled() const noexcept
void setPressureTrackingMode(TrackingMode modeToUse)
void addListener(Listener *listenerToAdd)
void removeListener(Listener *listenerToRemove)
virtual void sustainPedal(int midiChannel, bool isDown)
void setTimbreTrackingMode(TrackingMode modeToUse)
int getNumPlayingNotes() const noexcept
virtual void timbre(int midiChannel, MPEValue value)
MPENote getMostRecentNote(int midiChannel) const noexcept
Range< int > getLegacyModeChannelRange() const noexcept
virtual void noteOn(int midiChannel, int midiNoteNumber, MPEValue midiNoteOnVelocity)
int getLegacyModePitchbendRange() const noexcept
virtual void noteOff(int midiChannel, int midiNoteNumber, MPEValue midiNoteOffVelocity)
virtual void pressure(int midiChannel, MPEValue value)
bool isMasterChannel(int midiChannel) const noexcept
bool isUsingChannel(int midiChannel) const noexcept
static MidiBuffer setUpperZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
static MidiBuffer setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
static MPEValue centreValue() noexcept
static MPEValue from14BitInt(int value) noexcept
static MPEValue minValue() noexcept
static MPEValue from7BitInt(int value) noexcept
const Zone getUpperZone() const noexcept
const Zone getLowerZone() const noexcept
void processNextMidiEvent(const MidiMessage &message)
bool isAftertouch() const noexcept
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
int getChannel() const noexcept
static MidiMessage aftertouchChange(int channel, int noteNumber, int aftertouchAmount) noexcept
bool isController() const noexcept
static MidiMessage pitchWheel(int channel, int position) noexcept
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
bool isPitchWheel() const noexcept
int getNoteNumber() const noexcept
static MidiMessage controllerEvent(int channel, int controllerType, int value) noexcept
bool isResetAllControllers() const noexcept
static MidiMessage channelPressureChange(int channel, int pressure) noexcept
bool isAllNotesOff() const noexcept
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
uint8 getVelocity() const noexcept
bool isChannelPressure() const noexcept
static MidiMessage allControllersOff(int channel) noexcept