26MidiMessageSequence::MidiEventHolder::MidiEventHolder (
const MidiMessage& mm) : message (mm) {}
27MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (std::move (mm)) {}
30MidiMessageSequence::MidiMessageSequence()
36 list.addCopiesOf (other.list);
38 for (
int i = 0; i < list.size(); ++i)
43 list.getUnchecked (i)->noteOffObject = list.getUnchecked (
noteOffIndex);
55 : list (std::move (other.list))
61 list = std::move (other.list);
67 list.swapWith (other.list);
70void MidiMessageSequence::clear()
90double MidiMessageSequence::getTimeOfMatchingKeyUp (
int index)
const noexcept
92 if (
auto*
meh = list[index])
93 if (
auto* noteOff =
meh->noteOffObject)
94 return noteOff->message.getTimeStamp();
99int MidiMessageSequence::getIndexOfMatchingKeyUp (
int index)
const noexcept
101 if (
auto*
meh = list[index])
103 if (
auto* noteOff =
meh->noteOffObject)
105 for (
int i = index; i < list.size(); ++i)
106 if (list.getUnchecked (i) == noteOff)
118 return list.indexOf (
event);
121int MidiMessageSequence::getNextIndexAtTime (
double timeStamp)
const noexcept
127 if (list.getUnchecked (i)->message.getTimeStamp() >= timeStamp)
136 return getEventTime (0);
141 return getEventTime (list.size() - 1);
144double MidiMessageSequence::getEventTime (
const int index)
const noexcept
146 if (
auto*
meh = list[index])
147 return meh->message.getTimeStamp();
156 auto time =
newEvent->message.getTimeStamp();
159 for (i = list.size(); --i >= 0;)
160 if (list.getUnchecked (i)->message.getTimeStamp() <= time)
179 if (isPositiveAndBelow (index, list.size()))
182 deleteEvent (getIndexOfMatchingKeyUp (index),
false);
190 for (
auto* m : other)
205 for (
auto* m : other)
212 newOne->message.setTimeStamp (
t);
222 std::stable_sort (list.begin(), list.end(),
226void MidiMessageSequence::updateMatchedPairs()
noexcept
228 for (
int i = 0; i < list.size(); ++i)
230 auto*
meh = list.getUnchecked (i);
231 auto&
m1 =
meh->message;
235 meh->noteOffObject =
nullptr;
236 auto note =
m1.getNoteNumber();
237 auto chan =
m1.getChannel();
238 auto len = list.size();
240 for (
int j = i + 1;
j <
len; ++
j)
242 auto*
meh2 = list.getUnchecked (
j);
243 auto& m =
meh2->message;
245 if (m.getNoteNumber() ==
note && m.getChannel() ==
chan)
257 newEvent->message.setTimeStamp (m.getTimeStamp());
267void MidiMessageSequence::addTimeToMessages (
double delta)
noexcept
269 if (! approximatelyEqual (
delta, 0.0))
271 m->message.addToTimeStamp (
delta);
279 for (
auto*
meh : list)
287 for (
auto*
meh : list)
288 if (
meh->message.isSysEx())
294 for (
int i = list.size(); --i >= 0;)
299void MidiMessageSequence::deleteSysExMessages()
301 for (
int i = list.size(); --i >= 0;)
302 if (list.getUnchecked (i)->message.isSysEx())
307class OptionalPitchWheel
314 if (value.hasValue())
315 out.add (MidiMessage::pitchWheel (channel, *value));
324class OptionalControllerValues
326 Optional<char> values[128];
329 void emit (
int channel, Array<MidiMessage>& out)
const
331 for (
auto it = std::begin (values); it != std::end (values); ++it)
333 out.add (MidiMessage::controllerEvent (channel, (
int) std::distance (std::begin (values), it), **it));
336 void set (
int controller,
int value)
338 values[controller] = (char) value;
342class OptionalProgramChange
344 Optional<char> value, bankLSB, bankMSB;
347 void emit (
int channel,
double time, Array<MidiMessage>& out)
const
349 if (! value.hasValue())
352 if (bankLSB.hasValue() && bankMSB.hasValue())
354 out.add (MidiMessage::controllerEvent (channel, 0x00, *bankMSB).withTimeStamp (time));
355 out.add (MidiMessage::controllerEvent (channel, 0x20, *bankLSB).withTimeStamp (time));
358 out.add (MidiMessage::programChange (channel, *value).withTimeStamp (time));
362 bool trySetBank (
int controller,
int v)
366 case 0x00: bankMSB = (char) v;
return true;
367 case 0x20: bankLSB = (char) v;
return true;
373 void setProgram (
int v) { value = (char) v; }
376class ParameterNumberState
378 enum class Kind { rpn, nrpn };
380 Optional<char> newestRpnLsb, newestRpnMsb, newestNrpnLsb, newestNrpnMsb, lastSentLsb, lastSentMsb;
381 Kind lastSentKind = Kind::rpn, newestKind = Kind::rpn;
388 void sendIfNecessary (
int channel,
double time, Array<MidiMessage>& out)
390 const auto newestMsb = newestKind == Kind::rpn ? newestRpnMsb : newestNrpnMsb;
391 const auto newestLsb = newestKind == Kind::rpn ? newestRpnLsb : newestNrpnLsb;
393 auto lastSent = std::tie (lastSentKind, lastSentMsb, lastSentLsb);
394 const auto newest = std::tie (newestKind, newestMsb, newestLsb);
396 if (lastSent == newest || ! newestMsb.hasValue() || ! newestLsb.hasValue())
399 out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x65 : 0x63, *newestMsb).withTimeStamp (time));
400 out.add (MidiMessage::controllerEvent (channel, newestKind == Kind::rpn ? 0x64 : 0x62, *newestLsb).withTimeStamp (time));
406 bool trySetProgramNumber (
int controller,
int value)
410 case 0x65: newestRpnMsb = (char) value; newestKind = Kind::rpn;
return true;
411 case 0x64: newestRpnLsb = (char) value; newestKind = Kind::rpn;
return true;
412 case 0x63: newestNrpnMsb = (char) value; newestKind = Kind::nrpn;
return true;
413 case 0x62: newestNrpnLsb = (char) value; newestKind = Kind::nrpn;
return true;
420void MidiMessageSequence::createControllerUpdatesForTime (
int channel,
double time,
Array<MidiMessage>& dest)
422 OptionalProgramChange programChange;
424 OptionalPitchWheel pitchWheel;
427 for (
const auto& item : list)
429 const auto&
mm = item->message;
431 if (! (
mm.isForChannel (channel) &&
mm.getTimeStamp() <= time))
434 if (
mm.isController())
436 const auto num =
mm.getControllerNumber();
441 if (programChange.trySetBank (num,
mm.getControllerValue()))
444 constexpr int passthroughs[] { 0x06, 0x26, 0x60, 0x61 };
456 else if (
mm.isProgramChange())
458 programChange.setProgram (
mm.getProgramChangeNumber());
460 else if (
mm.isPitchWheel())
462 pitchWheel.set (
mm.getPitchWheelValue());
466 pitchWheel.emit (channel, dest);
470 programChange.emit (channel, time, dest);
483 :
UnitTest (
"MidiMessageSequence", UnitTestCategories::midi)
486 void runTest()
override
488 MidiMessageSequence s;
490 s.addEvent (MidiMessage::noteOn (1, 60, 0.5f).withTimeStamp (0.0));
491 s.addEvent (MidiMessage::noteOff (1, 60, 0.5f).withTimeStamp (4.0));
492 s.addEvent (MidiMessage::noteOn (1, 30, 0.5f).withTimeStamp (2.0));
493 s.addEvent (MidiMessage::noteOff (1, 30, 0.5f).withTimeStamp (8.0));
495 beginTest (
"Start & end time");
496 expectEquals (s.getStartTime(), 0.0);
497 expectEquals (s.getEndTime(), 8.0);
498 expectEquals (s.getEventTime (1), 2.0);
500 beginTest (
"Matching note off & ons");
501 s.updateMatchedPairs();
502 expectEquals (s.getTimeOfMatchingKeyUp (0), 4.0);
503 expectEquals (s.getTimeOfMatchingKeyUp (1), 8.0);
504 expectEquals (s.getIndexOfMatchingKeyUp (0), 2);
505 expectEquals (s.getIndexOfMatchingKeyUp (1), 3);
507 beginTest (
"Time & indices");
508 expectEquals (s.getNextIndexAtTime (0.5), 1);
509 expectEquals (s.getNextIndexAtTime (2.5), 2);
510 expectEquals (s.getNextIndexAtTime (9.0), 4);
512 beginTest (
"Deleting events");
513 s.deleteEvent (0,
true);
514 expectEquals (s.getNumEvents(), 2);
516 beginTest (
"Merging sequences");
517 MidiMessageSequence s2;
518 s2.addEvent (MidiMessage::noteOn (2, 25, 0.5f).withTimeStamp (0.0));
519 s2.addEvent (MidiMessage::noteOn (2, 40, 0.5f).withTimeStamp (1.0));
520 s2.addEvent (MidiMessage::noteOff (2, 40, 0.5f).withTimeStamp (5.0));
521 s2.addEvent (MidiMessage::noteOn (2, 80, 0.5f).withTimeStamp (3.0));
522 s2.addEvent (MidiMessage::noteOff (2, 80, 0.5f).withTimeStamp (7.0));
523 s2.addEvent (MidiMessage::noteOff (2, 25, 0.5f).withTimeStamp (9.0));
525 s.addSequence (s2, 0.0, 0.0, 8.0);
526 s.updateMatchedPairs();
528 expectEquals (s.getNumEvents(), 7);
529 expectEquals (s.getIndexOfMatchingKeyUp (0), -1);
530 expectEquals (s.getTimeOfMatchingKeyUp (1), 5.0);
532 struct ControlValue {
int control, value; };
536 int controllerBase, channel, parameter, value;
539 std::array<ControlValue, 4> getControlValues()
const
541 return { { { controllerBase + 1, (parameter >> 7) & 0x7f },
542 { controllerBase + 0, (parameter >> 0) & 0x7f },
543 { 0x06, (value >> 7) & 0x7f },
544 { 0x26, (value >> 0) & 0x7f } } };
547 void addToSequence (MidiMessageSequence& s)
const
549 for (
const auto& pair : getControlValues())
550 s.addEvent (MidiMessage::controllerEvent (channel, pair.control, pair.value), time);
553 bool matches (
const MidiMessage* begin,
const MidiMessage* end)
const
555 const auto isEqual = [
this] (
const ControlValue& cv,
const MidiMessage& msg)
557 return exactlyEqual (msg.getTimeStamp(), time)
558 && msg.isController()
559 && msg.getChannel() == channel
560 && msg.getControllerNumber() == cv.control
561 && msg.getControllerValue() == cv.value;
564 const auto pairs = getControlValues();
565 return std::equal (pairs.begin(), pairs.end(), begin, end, isEqual);
569 const auto addNrpn = [&] (MidiMessageSequence& seq,
int channel,
int parameter,
int value,
double time = 0.0)
571 DataEntry { 0x62, channel, parameter, value, time }.addToSequence (seq);
574 const auto addRpn = [&] (MidiMessageSequence& seq,
int channel,
int parameter,
int value,
double time = 0.0)
576 DataEntry { 0x64, channel, parameter, value, time }.addToSequence (seq);
579 const auto checkNrpn = [&] (
const MidiMessage* begin,
const MidiMessage* end,
int channel,
int parameter,
int value,
double time = 0.0)
581 expect (DataEntry { 0x62, channel, parameter, value, time }.matches (begin, end));
584 const auto checkRpn = [&] (
const MidiMessage* begin,
const MidiMessage* end,
int channel,
int parameter,
int value,
double time = 0.0)
586 expect (DataEntry { 0x64, channel, parameter, value, time }.matches (begin, end));
589 beginTest (
"createControllerUpdatesForTime should emit (N)RPN components in the correct order");
591 const auto channel = 1;
592 const auto number = 200;
593 const auto value = 300;
595 MidiMessageSequence sequence;
596 addNrpn (sequence, channel, number, value);
598 Array<MidiMessage> m;
599 sequence.createControllerUpdatesForTime (channel, 1.0, m);
601 checkNrpn (m.begin(), m.end(), channel, number, value);
604 beginTest (
"createControllerUpdatesForTime ignores (N)RPNs after the final requested time");
606 const auto channel = 2;
607 const auto number = 123;
608 const auto value = 456;
610 MidiMessageSequence sequence;
611 addRpn (sequence, channel, number, value, 0.5);
612 addRpn (sequence, channel, 111, 222, 1.5);
613 addRpn (sequence, channel, 333, 444, 2.5);
615 Array<MidiMessage> m;
616 sequence.createControllerUpdatesForTime (channel, 1.0, m);
618 checkRpn (m.begin(), std::next (m.begin(), 4), channel, number, value, 0.5);
621 beginTest (
"createControllerUpdatesForTime should emit separate (N)RPN messages when appropriate");
623 const auto channel = 2;
624 const auto numberA = 1111;
625 const auto valueA = 9999;
627 const auto numberB = 8888;
628 const auto valueB = 2222;
630 const auto numberC = 7777;
631 const auto valueC = 3333;
633 const auto numberD = 6666;
634 const auto valueD = 4444;
636 const auto time = 0.5;
638 MidiMessageSequence sequence;
639 addRpn (sequence, channel, numberA, valueA, time);
640 addRpn (sequence, channel, numberB, valueB, time);
641 addNrpn (sequence, channel, numberC, valueC, time);
642 addNrpn (sequence, channel, numberD, valueD, time);
644 Array<MidiMessage> m;
645 sequence.createControllerUpdatesForTime (channel, time * 2, m);
647 checkRpn (std::next (m.begin(), 0), std::next (m.begin(), 4), channel, numberA, valueA, time);
648 checkRpn (std::next (m.begin(), 4), std::next (m.begin(), 8), channel, numberB, valueB, time);
649 checkNrpn (std::next (m.begin(), 8), std::next (m.begin(), 12), channel, numberC, valueC, time);
650 checkNrpn (std::next (m.begin(), 12), std::next (m.begin(), 16), channel, numberD, valueD, time);
653 beginTest (
"createControllerUpdatesForTime correctly emits (N)RPN messages on multiple channels");
655 struct Info {
int channel, number, value; };
657 const Info infos[] { { 2, 1111, 9999 },
662 const auto time = 0.5;
664 MidiMessageSequence sequence;
666 for (
const auto& info : infos)
667 addRpn (sequence, info.channel, info.number, info.value, time);
669 for (
const auto& info : infos)
671 Array<MidiMessage> m;
672 sequence.createControllerUpdatesForTime (info.channel, time * 2, m);
673 checkRpn (std::next (m.begin(), 0), std::next (m.begin(), 4), info.channel, info.number, info.value, time);
677 const auto messagesAreEqual = [] (
const MidiMessage& a,
const MidiMessage& b)
679 return std::equal (a.getRawData(), a.getRawData() + a.getRawDataSize(),
680 b.getRawData(), b.getRawData() + b.getRawDataSize());
683 beginTest (
"createControllerUpdatesForTime sends bank select messages when the next program is in a new bank");
685 MidiMessageSequence sequence;
687 const auto time = 0.0;
688 const auto channel = 1;
690 sequence.addEvent (MidiMessage::programChange (channel, 5), time);
692 sequence.addEvent (MidiMessage::controllerEvent (channel, 0x00, 128), time);
693 sequence.addEvent (MidiMessage::controllerEvent (channel, 0x20, 64), time);
694 sequence.addEvent (MidiMessage::programChange (channel, 63), time);
696 const Array<MidiMessage> finalEvents { MidiMessage::controllerEvent (channel, 0x00, 50),
697 MidiMessage::controllerEvent (channel, 0x20, 40),
698 MidiMessage::programChange (channel, 30) };
700 for (
const auto& e : finalEvents)
701 sequence.addEvent (e);
703 Array<MidiMessage> m;
704 sequence.createControllerUpdatesForTime (channel, 1.0, m);
706 expect (std::equal (m.begin(), m.end(), finalEvents.begin(), finalEvents.end(), messagesAreEqual));
709 beginTest (
"createControllerUpdatesForTime preserves all Data Increment and Data Decrement messages");
711 MidiMessageSequence sequence;
713 const auto time = 0.0;
714 const auto channel = 1;
716 const Array<MidiMessage> messages { MidiMessage::controllerEvent (channel, 0x60, 0),
717 MidiMessage::controllerEvent (channel, 0x06, 100),
718 MidiMessage::controllerEvent (channel, 0x26, 50),
719 MidiMessage::controllerEvent (channel, 0x60, 10),
720 MidiMessage::controllerEvent (channel, 0x61, 10),
721 MidiMessage::controllerEvent (channel, 0x06, 20),
722 MidiMessage::controllerEvent (channel, 0x26, 30),
723 MidiMessage::controllerEvent (channel, 0x61, 10),
724 MidiMessage::controllerEvent (channel, 0x61, 20) };
726 for (
const auto& m : messages)
727 sequence.addEvent (m, time);
729 Array<MidiMessage> m;
730 sequence.createControllerUpdatesForTime (channel, 1.0, m);
732 expect (std::equal (m.begin(), m.end(), messages.begin(), messages.end(), messagesAreEqual));
735 beginTest (
"createControllerUpdatesForTime does not emit redundant parameter number changes");
737 MidiMessageSequence sequence;
739 const auto time = 0.0;
740 const auto channel = 1;
742 const Array<MidiMessage> messages { MidiMessage::controllerEvent (channel, 0x65, 0),
743 MidiMessage::controllerEvent (channel, 0x64, 100),
744 MidiMessage::controllerEvent (channel, 0x63, 50),
745 MidiMessage::controllerEvent (channel, 0x62, 10),
746 MidiMessage::controllerEvent (channel, 0x06, 10) };
748 for (
const auto& m : messages)
749 sequence.addEvent (m, time);
751 Array<MidiMessage> m;
752 sequence.createControllerUpdatesForTime (channel, 1.0, m);
754 const Array<MidiMessage> expected { MidiMessage::controllerEvent (channel, 0x63, 50),
755 MidiMessage::controllerEvent (channel, 0x62, 10),
756 MidiMessage::controllerEvent (channel, 0x06, 10) };
758 expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual));
761 beginTest (
"createControllerUpdatesForTime sets parameter number correctly at end of sequence");
763 MidiMessageSequence sequence;
765 const auto time = 0.0;
766 const auto channel = 1;
768 const Array<MidiMessage> messages { MidiMessage::controllerEvent (channel, 0x65, 0),
769 MidiMessage::controllerEvent (channel, 0x64, 100),
770 MidiMessage::controllerEvent (channel, 0x63, 50),
771 MidiMessage::controllerEvent (channel, 0x62, 10),
772 MidiMessage::controllerEvent (channel, 0x06, 10),
773 MidiMessage::controllerEvent (channel, 0x64, 5) };
775 for (
const auto& m : messages)
776 sequence.addEvent (m, time);
778 const auto finalTime = 1.0;
780 Array<MidiMessage> m;
781 sequence.createControllerUpdatesForTime (channel, finalTime, m);
783 const Array<MidiMessage> expected { MidiMessage::controllerEvent (channel, 0x63, 50),
784 MidiMessage::controllerEvent (channel, 0x62, 10),
785 MidiMessage::controllerEvent (channel, 0x06, 10),
787 MidiMessage::controllerEvent (channel, 0x65, 0).withTimeStamp (finalTime),
788 MidiMessage::controllerEvent (channel, 0x64, 5).withTimeStamp (finalTime) };
790 expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual));
793 beginTest (
"createControllerUpdatesForTime does not emit duplicate parameter number change messages");
795 MidiMessageSequence sequence;
797 const auto time = 0.0;
798 const auto channel = 1;
800 const Array<MidiMessage> messages { MidiMessage::controllerEvent (channel, 0x65, 1),
801 MidiMessage::controllerEvent (channel, 0x64, 2),
802 MidiMessage::controllerEvent (channel, 0x63, 3),
803 MidiMessage::controllerEvent (channel, 0x62, 4),
804 MidiMessage::controllerEvent (channel, 0x06, 10),
805 MidiMessage::controllerEvent (channel, 0x63, 30),
806 MidiMessage::controllerEvent (channel, 0x62, 40),
807 MidiMessage::controllerEvent (channel, 0x63, 3),
808 MidiMessage::controllerEvent (channel, 0x62, 4),
809 MidiMessage::controllerEvent (channel, 0x60, 5),
810 MidiMessage::controllerEvent (channel, 0x65, 10) };
812 for (
const auto& m : messages)
813 sequence.addEvent (m, time);
815 const auto finalTime = 1.0;
817 Array<MidiMessage> m;
818 sequence.createControllerUpdatesForTime (channel, finalTime, m);
820 const Array<MidiMessage> expected { MidiMessage::controllerEvent (channel, 0x63, 3),
821 MidiMessage::controllerEvent (channel, 0x62, 4),
822 MidiMessage::controllerEvent (channel, 0x06, 10),
825 MidiMessage::controllerEvent (channel, 0x60, 5),
827 MidiMessage::controllerEvent (channel, 0x65, 10).withTimeStamp (finalTime),
828 MidiMessage::controllerEvent (channel, 0x64, 2) .withTimeStamp (finalTime) };
830 expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual));
833 beginTest (
"createControllerUpdatesForTime emits bank change messages immediately before program change");
835 MidiMessageSequence sequence;
837 const auto time = 0.0;
838 const auto channel = 1;
840 const Array<MidiMessage> messages { MidiMessage::controllerEvent (channel, 0x00, 1),
841 MidiMessage::controllerEvent (channel, 0x20, 2),
842 MidiMessage::controllerEvent (channel, 0x65, 0),
843 MidiMessage::controllerEvent (channel, 0x64, 0),
844 MidiMessage::programChange (channel, 5) };
846 for (
const auto& m : messages)
847 sequence.addEvent (m, time);
849 const auto finalTime = 1.0;
851 Array<MidiMessage> m;
852 sequence.createControllerUpdatesForTime (channel, finalTime, m);
854 const Array<MidiMessage> expected { MidiMessage::controllerEvent (channel, 0x00, 1),
855 MidiMessage::controllerEvent (channel, 0x20, 2),
856 MidiMessage::programChange (channel, 5),
857 MidiMessage::controllerEvent (channel, 0x65, 0).withTimeStamp (finalTime),
858 MidiMessage::controllerEvent (channel, 0x64, 0).withTimeStamp (finalTime) };
861 expect (std::equal (m.begin(), m.end(), expected.begin(), expected.end(), messagesAreEqual));
866static MidiMessageSequenceTest midiMessageSequenceTests;