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)
43 if (noteOffIndex >= 0)
44 list.getUnchecked(i)->noteOffObject = list.getUnchecked (noteOffIndex);
56 : list (std::move (other.list))
62 list = std::move (other.list);
66MidiMessageSequence::~MidiMessageSequence()
72 list.swapWith (other.list);
75void MidiMessageSequence::clear()
80int MidiMessageSequence::getNumEvents() const noexcept
95double MidiMessageSequence::getTimeOfMatchingKeyUp (
int index)
const noexcept
97 if (
auto* meh = list[index])
98 if (
auto* noteOff = meh->noteOffObject)
99 return noteOff->message.getTimeStamp();
104int MidiMessageSequence::getIndexOfMatchingKeyUp (
int index)
const noexcept
106 if (
auto* meh = list[index])
108 if (
auto* noteOff = meh->noteOffObject)
110 for (
int i = index; i < list.size(); ++i)
111 if (list.getUnchecked(i) == noteOff)
123 return list.indexOf (event);
126int MidiMessageSequence::getNextIndexAtTime (
double timeStamp)
const noexcept
128 auto numEvents = list.size();
131 for (i = 0; i < numEvents; ++i)
132 if (list.getUnchecked(i)->message.getTimeStamp() >= timeStamp)
139double MidiMessageSequence::getStartTime() const noexcept
141 return getEventTime (0);
144double MidiMessageSequence::getEndTime() const noexcept
146 return getEventTime (list.size() - 1);
149double MidiMessageSequence::getEventTime (
const int index)
const noexcept
151 if (
auto* meh = list[index])
152 return meh->message.getTimeStamp();
161 auto time = newEvent->message.getTimeStamp();
164 for (i = list.size(); --i >= 0;)
165 if (list.getUnchecked(i)->message.getTimeStamp() <= time)
168 list.insert (i + 1, newEvent);
179 return addEvent (
new MidiEventHolder (std::move (newMessage)), timeAdjustment);
182void MidiMessageSequence::deleteEvent (
int index,
bool deleteMatchingNoteUp)
184 if (isPositiveAndBelow (index, list.size()))
186 if (deleteMatchingNoteUp)
187 deleteEvent (getIndexOfMatchingKeyUp (index),
false);
195 for (
auto* m : other)
198 newOne->message.addToTimeStamp (timeAdjustment);
206 double timeAdjustment,
207 double firstAllowableTime,
208 double endOfAllowableDestTimes)
210 for (
auto* m : other)
212 auto t = m->message.getTimeStamp() + timeAdjustment;
214 if (t >= firstAllowableTime && t < endOfAllowableDestTimes)
217 newOne->message.setTimeStamp (t);
225void MidiMessageSequence::sort() noexcept
227 std::stable_sort (list.begin(), list.end(),
231void MidiMessageSequence::updateMatchedPairs() noexcept
233 for (
int i = 0; i < list.size(); ++i)
235 auto* meh = list.getUnchecked(i);
236 auto& m1 = meh->message;
240 meh->noteOffObject =
nullptr;
241 auto note = m1.getNoteNumber();
242 auto chan = m1.getChannel();
243 auto len = list.size();
245 for (
int j = i + 1; j < len; ++j)
247 auto* meh2 = list.getUnchecked(j);
248 auto& m = meh2->message;
250 if (m.getNoteNumber() == note && m.getChannel() == chan)
254 meh->noteOffObject = meh2;
260 auto newEvent =
new MidiEventHolder (MidiMessage::noteOff (chan, note));
261 list.insert (j, newEvent);
262 newEvent->message.setTimeStamp (m.getTimeStamp());
263 meh->noteOffObject = newEvent;
272void MidiMessageSequence::addTimeToMessages (
double delta)
noexcept
276 m->message.addToTimeStamp (delta);
280void MidiMessageSequence::extractMidiChannelMessages (
const int channelNumberToExtract,
282 const bool alsoIncludeMetaEvents)
const
284 for (
auto* meh : list)
285 if (meh->message.isForChannel (channelNumberToExtract)
286 || (alsoIncludeMetaEvents && meh->message.isMetaEvent()))
287 destSequence.
addEvent (meh->message);
292 for (
auto* meh : list)
293 if (meh->message.isSysEx())
294 destSequence.
addEvent (meh->message);
297void MidiMessageSequence::deleteMidiChannelMessages (
const int channelNumberToRemove)
299 for (
int i = list.size(); --i >= 0;)
300 if (list.getUnchecked(i)->message.isForChannel (channelNumberToRemove))
304void MidiMessageSequence::deleteSysExMessages()
306 for (
int i = list.size(); --i >= 0;)
307 if (list.getUnchecked(i)->message.isSysEx())
312void MidiMessageSequence::createControllerUpdatesForTime (
int channelNumber,
double time,
Array<MidiMessage>& dest)
314 bool doneProg =
false;
315 bool donePitchWheel =
false;
316 bool doneControllers[128] = {};
318 for (
int i = list.size(); --i >= 0;)
320 auto& mm = list.getUnchecked(i)->message;
322 if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time)
324 if (mm.isProgramChange() && ! doneProg)
329 else if (mm.isPitchWheel() && ! donePitchWheel)
331 donePitchWheel =
true;
334 else if (mm.isController())
336 auto controllerNumber = mm.getControllerNumber();
337 jassert (isPositiveAndBelow (controllerNumber, 128));
339 if (! doneControllers[controllerNumber])
341 doneControllers[controllerNumber] =
true;
354struct MidiMessageSequenceTest :
public UnitTest
356 MidiMessageSequenceTest()
357 :
UnitTest (
"MidiMessageSequence", UnitTestCategories::midi)
362 MidiMessageSequence s;
364 s.addEvent (MidiMessage::noteOn (1, 60, 0.5f).withTimeStamp (0.0));
365 s.addEvent (MidiMessage::noteOff (1, 60, 0.5f).withTimeStamp (4.0));
366 s.addEvent (MidiMessage::noteOn (1, 30, 0.5f).withTimeStamp (2.0));
367 s.addEvent (MidiMessage::noteOff (1, 30, 0.5f).withTimeStamp (8.0));
375 s.updateMatchedPairs();
387 s.deleteEvent (0,
true);
391 MidiMessageSequence s2;
392 s2.addEvent (MidiMessage::noteOn (2, 25, 0.5f).withTimeStamp (0.0));
393 s2.addEvent (MidiMessage::noteOn (2, 40, 0.5f).withTimeStamp (1.0));
394 s2.addEvent (MidiMessage::noteOff (2, 40, 0.5f).withTimeStamp (5.0));
395 s2.addEvent (MidiMessage::noteOn (2, 80, 0.5f).withTimeStamp (3.0));
396 s2.addEvent (MidiMessage::noteOff (2, 80, 0.5f).withTimeStamp (7.0));
397 s2.addEvent (MidiMessage::noteOff (2, 25, 0.5f).withTimeStamp (9.0));
399 s.addSequence (s2, 0.0, 0.0, 8.0);
400 s.updateMatchedPairs();
408static MidiMessageSequenceTest midiMessageSequenceTests;
void add(const ElementType &newElement)
MidiEventHolder * addEvent(const MidiMessage &newMessage, double timeAdjustment=0)
int getIndexOfMatchingKeyUp(int index) const noexcept
void addToTimeStamp(double delta) noexcept
void expectEquals(ValueType actual, ValueType expected, String failureMessage=String())
void beginTest(const String &testName)