26 MidiMessageSequence::MidiEventHolder::MidiEventHolder (
const MidiMessage& mm) : message (mm) {}
27 MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (
std::move (mm)) {}
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);
72 list.swapWith (other.list);
97 if (
auto* meh = list[index])
98 if (
auto* noteOff = meh->noteOffObject)
99 return noteOff->message.getTimeStamp();
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);
128 auto numEvents = list.size();
131 for (i = 0; i < numEvents; ++i)
132 if (list.getUnchecked(i)->message.getTimeStamp() >= timeStamp)
141 return getEventTime (0);
146 return getEventTime (list.size() - 1);
151 if (
auto* meh = list[index])
152 return meh->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);
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);
227 std::stable_sort (list.begin(), list.end(),
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;
261 list.insert (j, newEvent);
263 meh->noteOffObject = newEvent;
276 m->message.addToTimeStamp (delta);
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);
299 for (
int i = list.size(); --i >= 0;)
300 if (list.getUnchecked(i)->message.isForChannel (channelNumberToRemove))
306 for (
int i = list.size(); --i >= 0;)
307 if (list.getUnchecked(i)->message.isSysEx())
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;
354 struct MidiMessageSequenceTest :
public UnitTest 356 MidiMessageSequenceTest()
357 :
UnitTest (
"MidiMessageSequence", UnitTestCategories::midi)
360 void runTest()
override 369 beginTest (
"Start & end time");
374 beginTest (
"Matching note off & ons");
381 beginTest (
"Time & indices");
386 beginTest (
"Deleting events");
390 beginTest (
"Merging sequences");
408 static MidiMessageSequenceTest midiMessageSequenceTests;
void addTimeToMessages(double deltaTime) noexcept
void extractSysExMessages(MidiMessageSequence &destSequence) const
void updateMatchedPairs() noexcept
void addSequence(const MidiMessageSequence &other, double timeAdjustmentDelta, double firstAllowableDestTime, double endOfAllowableDestTimes)
void setTimeStamp(double newTimestamp) noexcept
void deleteSysExMessages()
MidiEventHolder ** end() noexcept
void add(const ElementType &newElement)
int getIndexOfMatchingKeyUp(int index) const noexcept
MidiEventHolder * addEvent(const MidiMessage &newMessage, double timeAdjustment=0)
void deleteEvent(int index, bool deleteMatchingNoteUp)
void swapWith(MidiMessageSequence &) noexcept
MidiEventHolder ** begin() noexcept
void deleteMidiChannelMessages(int channelNumberToRemove)
MidiEventHolder * getEventPointer(int index) const noexcept
double getStartTime() const noexcept
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
double getTimeOfMatchingKeyUp(int index) const noexcept
void addToTimeStamp(double delta) noexcept
MidiMessageSequence & operator=(const MidiMessageSequence &)
void createControllerUpdatesForTime(int channelNumber, double time, Array< MidiMessage > &resultMessages)
int getIndexOf(const MidiEventHolder *event) const noexcept
void extractMidiChannelMessages(int channelNumberToExtract, MidiMessageSequence &destSequence, bool alsoIncludeMetaEvents) const
double getTimeStamp() const noexcept
int getNextIndexAtTime(double timeStamp) const noexcept
double getEndTime() const noexcept
int getNumEvents() const noexcept
double getEventTime(int index) const noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept