26MidiMessageSequence::MidiEventHolder::MidiEventHolder (
const MidiMessage& mm) : message (mm) {}
27MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (std::move (mm)) {}
28MidiMessageSequence::MidiEventHolder::~MidiEventHolder() {}
31MidiMessageSequence::MidiMessageSequence()
37 list.addCopiesOf (
other.list);
39 for (
int i = 0; i < list.size(); ++i)
56 : list (std::move (
other.list))
62 list = std::move (
other.list);
66MidiMessageSequence::~MidiMessageSequence()
72 list.swapWith (
other.list);
75void MidiMessageSequence::clear()
93double MidiMessageSequence::getTimeOfMatchingKeyUp (
int index)
const noexcept
95 if (
auto*
meh = list[index])
96 if (
auto* noteOff =
meh->noteOffObject)
97 return noteOff->message.getTimeStamp();
102int MidiMessageSequence::getIndexOfMatchingKeyUp (
int index)
const noexcept
104 if (
auto*
meh = list[index])
106 if (
auto* noteOff =
meh->noteOffObject)
108 for (
int i = index; i < list.size(); ++i)
109 if (list.getUnchecked(i) == noteOff)
121 return list.indexOf (
event);
124int MidiMessageSequence::getNextIndexAtTime (
double timeStamp)
const noexcept
130 if (list.getUnchecked(i)->message.getTimeStamp() >=
timeStamp)
139 return getEventTime (0);
144 return getEventTime (list.size() - 1);
147double MidiMessageSequence::getEventTime (
const int index)
const noexcept
149 if (
auto*
meh = list[index])
150 return meh->message.getTimeStamp();
159 auto time =
newEvent->message.getTimeStamp();
162 for (i = list.size(); --i >= 0;)
163 if (list.getUnchecked(i)->message.getTimeStamp() <= time)
182 if (isPositiveAndBelow (index, list.
size()))
185 deleteEvent (getIndexOfMatchingKeyUp (index),
false);
215 newOne->message.setTimeStamp (
t);
225 std::stable_sort (list.begin(), list.end(),
229void MidiMessageSequence::updateMatchedPairs()
noexcept
231 for (
int i = 0; i < list.
size(); ++i)
234 auto&
m1 =
meh->message;
238 meh->noteOffObject =
nullptr;
239 auto note =
m1.getNoteNumber();
240 auto chan =
m1.getChannel();
243 for (
int j = i + 1;
j <
len; ++
j)
246 auto&
m =
meh2->message;
248 if (
m.getNoteNumber() ==
note &&
m.getChannel() ==
chan)
260 newEvent->message.setTimeStamp (
m.getTimeStamp());
270void MidiMessageSequence::addTimeToMessages (
double delta)
noexcept
274 m->message.addToTimeStamp (
delta);
282 for (
auto*
meh : list)
290 for (
auto*
meh : list)
291 if (
meh->message.isSysEx())
297 for (
int i = list.
size(); --i >= 0;)
302void MidiMessageSequence::deleteSysExMessages()
304 for (
int i = list.
size(); --i >= 0;)
305 if (list.getUnchecked(i)->message.isSysEx())
316 for (
int i = list.
size(); --i >= 0;)
332 else if (
mm.isController())
353 void runTest()
override
355 MidiMessageSequence s;
357 s.addEvent (MidiMessage::noteOn (1, 60, 0.5f).withTimeStamp (0.0));
358 s.addEvent (MidiMessage::noteOff (1, 60, 0.5f).withTimeStamp (4.0));
359 s.addEvent (MidiMessage::noteOn (1, 30, 0.5f).withTimeStamp (2.0));
360 s.addEvent (MidiMessage::noteOff (1, 30, 0.5f).withTimeStamp (8.0));
362 beginTest (
"Start & end time");
363 expectEquals (s.getStartTime(), 0.0);
364 expectEquals (s.getEndTime(), 8.0);
365 expectEquals (s.getEventTime (1), 2.0);
367 beginTest (
"Matching note off & ons");
368 s.updateMatchedPairs();
369 expectEquals (s.getTimeOfMatchingKeyUp (0), 4.0);
370 expectEquals (s.getTimeOfMatchingKeyUp (1), 8.0);
371 expectEquals (s.getIndexOfMatchingKeyUp (0), 2);
372 expectEquals (s.getIndexOfMatchingKeyUp (1), 3);
374 beginTest (
"Time & indeces");
375 expectEquals (s.getNextIndexAtTime (0.5), 1);
376 expectEquals (s.getNextIndexAtTime (2.5), 2);
377 expectEquals (s.getNextIndexAtTime (9.0), 4);
379 beginTest (
"Deleting events");
380 s.deleteEvent (0,
true);
381 expectEquals (s.getNumEvents(), 2);
383 beginTest (
"Merging sequences");
384 MidiMessageSequence s2;
385 s2.addEvent (MidiMessage::noteOn (2, 25, 0.5f).withTimeStamp (0.0));
386 s2.addEvent (MidiMessage::noteOn (2, 40, 0.5f).withTimeStamp (1.0));
387 s2.addEvent (MidiMessage::noteOff (2, 40, 0.5f).withTimeStamp (5.0));
388 s2.addEvent (MidiMessage::noteOn (2, 80, 0.5f).withTimeStamp (3.0));
389 s2.addEvent (MidiMessage::noteOff (2, 80, 0.5f).withTimeStamp (7.0));
390 s2.addEvent (MidiMessage::noteOff (2, 25, 0.5f).withTimeStamp (9.0));
392 s.addSequence (s2, 0.0, 0.0, 8.0);
393 s.updateMatchedPairs();
395 expectEquals (s.getNumEvents(), 7);
396 expectEquals (s.getIndexOfMatchingKeyUp (0), -1);
397 expectEquals (s.getTimeOfMatchingKeyUp (1), 5.0);
401static MidiMessageSequenceTest midiMessageSequenceTests;
Holds a resizable array of primitive or copy-by-value objects.
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
int size() const noexcept
Returns the current number of elements in the array.
ElementType * begin() const noexcept
Returns a pointer to the first element in the array.
void remove(int indexToRemove)
Removes an element from the array.
void insert(int indexToInsertAt, ParameterType newElement)
Inserts a new element into the array at a given position.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
ElementType * end() const noexcept
Returns a pointer to the element which follows the last element in the array.
Structure used to hold midi events in the sequence.
A sequence of timestamped midi messages.
Encapsulates a MIDI message.
This is a base class for classes that perform a unit test.