diff --git a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp index e0c0bb8994..6a3f851cbf 100644 --- a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp @@ -20,6 +20,12 @@ ============================================================================== */ + +MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm) : message (mm) {} +MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (static_cast (mm)) {} +MidiMessageSequence::MidiEventHolder::~MidiEventHolder() {} + +//============================================================================== MidiMessageSequence::MidiMessageSequence() { } @@ -37,15 +43,25 @@ MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& return *this; } -void MidiMessageSequence::swapWith (MidiMessageSequence& other) noexcept +MidiMessageSequence::MidiMessageSequence (MidiMessageSequence&& other) noexcept + : list (static_cast&&> (other.list)) +{} + +MidiMessageSequence& MidiMessageSequence::operator= (MidiMessageSequence&& other) noexcept { - list.swapWith (other.list); + list = static_cast&&> (other.list); + return *this; } MidiMessageSequence::~MidiMessageSequence() { } +void MidiMessageSequence::swapWith (MidiMessageSequence& other) noexcept +{ + list.swapWith (other.list); +} + void MidiMessageSequence::clear() { list.clear(); @@ -56,34 +72,37 @@ int MidiMessageSequence::getNumEvents() const noexcept return list.size(); } -MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const noexcept +MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (int index) const noexcept { - return list [index]; + return list[index]; } -double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const noexcept +MidiMessageSequence::MidiEventHolder** MidiMessageSequence::begin() const noexcept { return list.begin(); } +MidiMessageSequence::MidiEventHolder** MidiMessageSequence::end() const noexcept { return list.end(); } + +double MidiMessageSequence::getTimeOfMatchingKeyUp (int index) const noexcept { - if (const MidiEventHolder* const meh = list [index]) + if (auto* meh = list[index]) if (meh->noteOffObject != nullptr) return meh->noteOffObject->message.getTimeStamp(); return 0.0; } -int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const noexcept +int MidiMessageSequence::getIndexOfMatchingKeyUp (int index) const noexcept { - if (const MidiEventHolder* const meh = list [index]) + if (auto* meh = list [index]) return list.indexOf (meh->noteOffObject); return -1; } -int MidiMessageSequence::getIndexOf (const MidiEventHolder* const event) const noexcept +int MidiMessageSequence::getIndexOf (const MidiEventHolder* event) const noexcept { return list.indexOf (event); } -int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const noexcept +int MidiMessageSequence::getNextIndexAtTime (double timeStamp) const noexcept { const int numEvents = list.size(); @@ -108,32 +127,38 @@ double MidiMessageSequence::getEndTime() const noexcept double MidiMessageSequence::getEventTime (const int index) const noexcept { - if (const MidiEventHolder* const meh = list [index]) + if (auto* meh = list [index]) return meh->message.getTimeStamp(); return 0.0; } //============================================================================== -MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (const MidiMessage& newMessage, - double timeAdjustment) +MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (MidiEventHolder* newEvent, double timeAdjustment) { - MidiEventHolder* const newOne = new MidiEventHolder (newMessage); - - timeAdjustment += newMessage.getTimeStamp(); - newOne->message.setTimeStamp (timeAdjustment); + newEvent->message.addToTimeStamp (timeAdjustment); + auto time = newEvent->message.getTimeStamp(); int i; for (i = list.size(); --i >= 0;) - if (list.getUnchecked(i)->message.getTimeStamp() <= timeAdjustment) + if (list.getUnchecked(i)->message.getTimeStamp() <= time) break; - list.insert (i + 1, newOne); - return newOne; + list.insert (i + 1, newEvent); + return newEvent; } -void MidiMessageSequence::deleteEvent (const int index, - const bool deleteMatchingNoteUp) +MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (const MidiMessage& newMessage, double timeAdjustment) +{ + return addEvent (new MidiEventHolder (newMessage), timeAdjustment); +} + +MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (MidiMessage&& newMessage, double timeAdjustment) +{ + return addEvent (new MidiEventHolder (static_cast (newMessage)), timeAdjustment); +} + +void MidiMessageSequence::deleteEvent (int index, bool deleteMatchingNoteUp) { if (isPositiveAndBelow (index, list.size())) { @@ -144,23 +169,11 @@ void MidiMessageSequence::deleteEvent (const int index, } } -struct MidiMessageSequenceSorter -{ - static int compareElements (const MidiMessageSequence::MidiEventHolder* const first, - const MidiMessageSequence::MidiEventHolder* const second) noexcept - { - const double diff = first->message.getTimeStamp() - second->message.getTimeStamp(); - return (diff > 0) - (diff < 0); - } -}; - void MidiMessageSequence::addSequence (const MidiMessageSequence& other, double timeAdjustment) { - for (int i = 0; i < other.list.size(); ++i) + for (auto* m : other) { - const MidiMessage& m = other.list.getUnchecked(i)->message; - - MidiEventHolder* const newOne = new MidiEventHolder (m); + auto newOne = new MidiEventHolder (m->message); newOne->message.addToTimeStamp (timeAdjustment); list.add (newOne); } @@ -173,16 +186,14 @@ void MidiMessageSequence::addSequence (const MidiMessageSequence& other, double firstAllowableTime, double endOfAllowableDestTimes) { - for (int i = 0; i < other.list.size(); ++i) + for (auto* m : other) { - const MidiMessage& m = other.list.getUnchecked(i)->message; - const double t = m.getTimeStamp() + timeAdjustment; + auto t = m->message.getTimeStamp() + timeAdjustment; if (t >= firstAllowableTime && t < endOfAllowableDestTimes) { - MidiEventHolder* const newOne = new MidiEventHolder (m); + auto newOne = new MidiEventHolder (m->message); newOne->message.setTimeStamp (t); - list.add (newOne); } } @@ -190,7 +201,16 @@ void MidiMessageSequence::addSequence (const MidiMessageSequence& other, sort(); } -//============================================================================== +struct MidiMessageSequenceSorter +{ + static int compareElements (const MidiMessageSequence::MidiEventHolder* first, + const MidiMessageSequence::MidiEventHolder* second) noexcept + { + auto diff = first->message.getTimeStamp() - second->message.getTimeStamp(); + return (diff > 0) - (diff < 0); + } +}; + void MidiMessageSequence::sort() noexcept { MidiMessageSequenceSorter sorter; @@ -201,30 +221,32 @@ void MidiMessageSequence::updateMatchedPairs() noexcept { for (int i = 0; i < list.size(); ++i) { - MidiEventHolder* const meh = list.getUnchecked(i); - const MidiMessage& m1 = meh->message; + auto* meh = list.getUnchecked(i); + auto& m1 = meh->message; if (m1.isNoteOn()) { meh->noteOffObject = nullptr; - const int note = m1.getNoteNumber(); - const int chan = m1.getChannel(); - const int len = list.size(); + auto note = m1.getNoteNumber(); + auto chan = m1.getChannel(); + auto len = list.size(); for (int j = i + 1; j < len; ++j) { - const MidiMessage& m = list.getUnchecked(j)->message; + auto* meh2 = list.getUnchecked(j); + auto& m = meh2->message; if (m.getNoteNumber() == note && m.getChannel() == chan) { if (m.isNoteOff()) { - meh->noteOffObject = list[j]; + meh->noteOffObject = meh2; break; } - else if (m.isNoteOn()) + + if (m.isNoteOn()) { - MidiEventHolder* const newEvent = new MidiEventHolder (MidiMessage::noteOff (chan, note)); + auto newEvent = new MidiEventHolder (MidiMessage::noteOff (chan, note)); list.insert (j, newEvent); newEvent->message.setTimeStamp (m.getTimeStamp()); meh->noteOffObject = newEvent; @@ -236,13 +258,11 @@ void MidiMessageSequence::updateMatchedPairs() noexcept } } -void MidiMessageSequence::addTimeToMessages (const double delta) noexcept +void MidiMessageSequence::addTimeToMessages (double delta) noexcept { - for (int i = list.size(); --i >= 0;) - { - MidiMessage& mm = list.getUnchecked(i)->message; - mm.setTimeStamp (mm.getTimeStamp() + delta); - } + if (delta != 0) + for (auto* m : list) + m->message.addToTimeStamp (delta); } //============================================================================== @@ -250,24 +270,17 @@ void MidiMessageSequence::extractMidiChannelMessages (const int channelNumberToE MidiMessageSequence& destSequence, const bool alsoIncludeMetaEvents) const { - for (int i = 0; i < list.size(); ++i) - { - const MidiMessage& mm = list.getUnchecked(i)->message; - - if (mm.isForChannel (channelNumberToExtract) || (alsoIncludeMetaEvents && mm.isMetaEvent())) - destSequence.addEvent (mm); - } + for (auto* meh : list) + if (meh->message.isForChannel (channelNumberToExtract) + || (alsoIncludeMetaEvents && meh->message.isMetaEvent())) + destSequence.addEvent (meh->message); } void MidiMessageSequence::extractSysExMessages (MidiMessageSequence& destSequence) const { - for (int i = 0; i < list.size(); ++i) - { - const MidiMessage& mm = list.getUnchecked(i)->message; - - if (mm.isSysEx()) - destSequence.addEvent (mm); - } + for (auto* meh : list) + if (meh->message.isSysEx()) + destSequence.addEvent (meh->message); } void MidiMessageSequence::deleteMidiChannelMessages (const int channelNumberToRemove) @@ -285,15 +298,15 @@ void MidiMessageSequence::deleteSysExMessages() } //============================================================================== -void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber, const double time, Array& dest) +void MidiMessageSequence::createControllerUpdatesForTime (int channelNumber, double time, Array& dest) { bool doneProg = false; bool donePitchWheel = false; - bool doneControllers[128] = { 0 }; + bool doneControllers[128] = {}; for (int i = list.size(); --i >= 0;) { - const MidiMessage& mm = list.getUnchecked(i)->message; + auto& mm = list.getUnchecked(i)->message; if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time) { @@ -321,14 +334,3 @@ void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumbe } } } - - -//============================================================================== -MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm) - : message (mm), noteOffObject (nullptr) -{ -} - -MidiMessageSequence::MidiEventHolder::~MidiEventHolder() -{ -} diff --git a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h index b729ce925b..916431b986 100644 --- a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h +++ b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h @@ -46,16 +46,10 @@ public: MidiMessageSequence& operator= (const MidiMessageSequence&); /** Move constructor */ - MidiMessageSequence (MidiMessageSequence&& other) noexcept - : list (static_cast&&> (other.list)) - {} + MidiMessageSequence (MidiMessageSequence&&) noexcept; /** Move assignment operator */ - MidiMessageSequence& operator= (MidiMessageSequence&& other) noexcept - { - list = static_cast&&> (other.list); - return *this; - } + MidiMessageSequence& operator= (MidiMessageSequence&&) noexcept; /** Destructor. */ ~MidiMessageSequence(); @@ -86,12 +80,13 @@ public: note-offs up-to-date after events have been moved around in the sequence or deleted. */ - MidiEventHolder* noteOffObject; + MidiEventHolder* noteOffObject = nullptr; private: //============================================================================== friend class MidiMessageSequence; MidiEventHolder (const MidiMessage&); + MidiEventHolder (MidiMessage&&); JUCE_LEAK_DETECTOR (MidiEventHolder) }; @@ -105,6 +100,12 @@ public: /** Returns a pointer to one of the events. */ MidiEventHolder* getEventPointer (int index) const noexcept; + /** Iterator for the list of MidiEventHolders */ + MidiEventHolder** begin() const noexcept; + + /** Iterator for the list of MidiEventHolders */ + MidiEventHolder** end() const noexcept; + /** Returns the time of the note-up that matches the note-on at this index. If the event at this index isn't a note-on, it'll just return 0. @see MidiMessageSequence::MidiEventHolder::noteOffObject @@ -155,8 +156,21 @@ public: that will be inserted @see updateMatchedPairs */ - MidiEventHolder* addEvent (const MidiMessage& newMessage, - double timeAdjustment = 0); + MidiEventHolder* addEvent (const MidiMessage& newMessage, double timeAdjustment = 0); + + /** Inserts a midi message into the sequence. + + The index at which the new message gets inserted will depend on its timestamp, + because the sequence is kept sorted. + + Remember to call updateMatchedPairs() after adding note-on events. + + @param newMessage the new message to add (an internal copy will be made) + @param timeAdjustment an optional value to add to the timestamp of the message + that will be inserted + @see updateMatchedPairs + */ + MidiEventHolder* addEvent (MidiMessage&& newMessage, double timeAdjustment = 0); /** Deletes one of the events in the sequence. @@ -276,5 +290,7 @@ private: friend class MidiFile; OwnedArray list; + MidiEventHolder* addEvent (MidiEventHolder*, double); + JUCE_LEAK_DETECTOR (MidiMessageSequence) };