diff --git a/examples/Plugins/ArpeggiatorPluginDemo.h b/examples/Plugins/ArpeggiatorPluginDemo.h index 2062d2de98..6f8f5756e8 100644 --- a/examples/Plugins/ArpeggiatorPluginDemo.h +++ b/examples/Plugins/ArpeggiatorPluginDemo.h @@ -88,11 +88,9 @@ public: // get note duration auto noteDuration = static_cast (std::ceil (rate * 0.25f * (0.1f + (1.0f - (*speed))))); - MidiMessage msg; - int ignore; - - for (MidiBuffer::Iterator it (midi); it.getNextEvent (msg, ignore);) + for (const auto metadata : midi) { + const auto msg = metadata.getMessage(); if (msg.isNoteOn()) notes.add (msg.getNoteNumber()); else if (msg.isNoteOff()) notes.removeValue (msg.getNoteNumber()); } diff --git a/examples/Plugins/MultiOutSynthPluginDemo.h b/examples/Plugins/MultiOutSynthPluginDemo.h index d3c6ce7505..e3d77f9990 100644 --- a/examples/Plugins/MultiOutSynthPluginDemo.h +++ b/examples/Plugins/MultiOutSynthPluginDemo.h @@ -147,12 +147,15 @@ private: //============================================================================== static MidiBuffer filterMidiMessagesForChannel (const MidiBuffer& input, int channel) { - MidiMessage msg; - int samplePosition; MidiBuffer output; - for (MidiBuffer::Iterator it (input); it.getNextEvent (msg, samplePosition);) - if (msg.getChannel() == channel) output.addEvent (msg, samplePosition); + for (const auto metadata : input) + { + const auto message = metadata.getMessage(); + + if (message.getChannel() == channel) + output.addEvent (message, metadata.samplePosition); + } return output; } diff --git a/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp b/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp index 0501698bf6..da57a0802d 100644 --- a/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp @@ -81,17 +81,27 @@ namespace MidiBufferHelpers } //============================================================================== -MidiBuffer::MidiBuffer() noexcept {} -MidiBuffer::~MidiBuffer() {} - -MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept : data (other.data) {} - -MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) noexcept +MidiBufferIterator& MidiBufferIterator::operator++() noexcept { - data = other.data; + data += sizeof (int32) + sizeof (uint16) + size_t (MidiBufferHelpers::getEventDataSize (data)); return *this; } +MidiBufferIterator MidiBufferIterator::operator++ (int) noexcept +{ + auto copy = *this; + ++(*this); + return copy; +} + +MidiBufferIterator::reference MidiBufferIterator::operator*() const noexcept +{ + return { data + sizeof (int32) + sizeof (uint16), + MidiBufferHelpers::getEventDataSize (data), + MidiBufferHelpers::getEventTime (data) }; +} + +//============================================================================== MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept { addEvent (message, 0); @@ -138,16 +148,14 @@ void MidiBuffer::addEvent (const void* newData, int maxBytes, int sampleNumber) void MidiBuffer::addEvents (const MidiBuffer& otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd) { - Iterator i (otherBuffer); - i.setNextSamplePosition (startSample); - - const uint8* eventData; - int eventSize, position; - - while (i.getNextEvent (eventData, eventSize, position) - && (position < startSample + numSamples || numSamples < 0)) + for (auto i = otherBuffer.findNextSamplePosition (startSample); i != otherBuffer.cend(); ++i) { - addEvent (eventData, eventSize, position + sampleDeltaToAdd); + const auto metadata = *i; + + if (metadata.samplePosition >= startSample + numSamples && numSamples >= 0) + break; + + addEvent (metadata.data, metadata.numBytes, metadata.samplePosition + sampleDeltaToAdd); } } @@ -185,9 +193,17 @@ int MidiBuffer::getLastEventTime() const noexcept } } +MidiBufferIterator MidiBuffer::findNextSamplePosition (int samplePosition) const noexcept +{ + return std::find_if (cbegin(), cend(), [&] (const MidiMessageMetadata& metadata) noexcept + { + return metadata.samplePosition >= samplePosition; + }); +} + //============================================================================== MidiBuffer::Iterator::Iterator (const MidiBuffer& b) noexcept - : buffer (b), data (b.data.begin()) + : buffer (b), iterator (b.data.begin()) { } @@ -195,37 +211,29 @@ MidiBuffer::Iterator::~Iterator() noexcept {} void MidiBuffer::Iterator::setNextSamplePosition (int samplePosition) noexcept { - data = buffer.data.begin(); - auto dataEnd = buffer.data.end(); - - while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition) - data += MidiBufferHelpers::getEventTotalSize (data); + iterator = buffer.findNextSamplePosition (samplePosition); } bool MidiBuffer::Iterator::getNextEvent (const uint8*& midiData, int& numBytes, int& samplePosition) noexcept { - if (data >= buffer.data.end()) + if (iterator == buffer.cend()) return false; - samplePosition = MidiBufferHelpers::getEventTime (data); - auto itemSize = MidiBufferHelpers::getEventDataSize (data); - numBytes = itemSize; - midiData = data + sizeof (int32) + sizeof (uint16); - data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; - + const auto metadata = *iterator; + midiData = metadata.data; + numBytes = metadata.numBytes; + samplePosition = metadata.samplePosition; return true; } bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept { - if (data >= buffer.data.end()) + if (iterator == buffer.cend()) return false; - samplePosition = MidiBufferHelpers::getEventTime (data); - auto itemSize = MidiBufferHelpers::getEventDataSize (data); - result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition); - data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; - + const auto metadata = *iterator; + result = metadata.getMessage(); + samplePosition = metadata.samplePosition; return true; } diff --git a/modules/juce_audio_basics/midi/juce_MidiBuffer.h b/modules/juce_audio_basics/midi/juce_MidiBuffer.h index 8344a5ed84..14becea3e8 100644 --- a/modules/juce_audio_basics/midi/juce_MidiBuffer.h +++ b/modules/juce_audio_basics/midi/juce_MidiBuffer.h @@ -23,6 +23,104 @@ namespace juce { +//============================================================================== +/** + A view of MIDI message data stored in a contiguous buffer. + + Instances of this class do *not* own the midi data bytes that they point to. + Instead, they expect the midi data to live in a separate buffer that outlives + the MidiMessageMetadata instance. +*/ +struct MidiMessageMetadata final +{ + MidiMessageMetadata() noexcept = default; + + MidiMessageMetadata (const uint8* dataIn, int numBytesIn, int positionIn) noexcept + : data (dataIn), numBytes (numBytesIn), samplePosition (positionIn) + { + } + + /** Constructs a new MidiMessage instance from the data that this object is viewing. + + Note that MidiMessage owns its data storage, whereas MidiMessageMetadata does not. + */ + MidiMessage getMessage() const { return MidiMessage (data, numBytes, samplePosition); } + + /** Pointer to the first byte of a MIDI message. */ + const uint8* data = nullptr; + + /** The number of bytes in the MIDI message. */ + int numBytes = 0; + + /** The MIDI message's timestamp. */ + int samplePosition = 0; +}; + +//============================================================================== +/** + An iterator to move over contiguous raw MIDI data, which Allows iterating + over a MidiBuffer using C++11 range-for syntax. + + In the following example, we log all three-byte messages in a midi buffer. + @code + void processBlock (AudioBuffer&, MidiBuffer& midiBuffer) override + { + for (const MidiMessageMetadata metadata : midiBuffer) + if (metadata.numBytes == 3) + Logger::writeToLog (metadata.getMessage().getDescription()); + } + @endcode +*/ +class JUCE_API MidiBufferIterator +{ + using Ptr = const uint8*; + +public: + MidiBufferIterator() = default; + + /** Constructs an iterator pointing at the message starting at the byte `dataIn`. + `dataIn` must point to the start of a valid MIDI message. If it does not, + calling other member functions on the iterator will result in undefined + behaviour. + */ + explicit MidiBufferIterator (const uint8* dataIn) noexcept + : data (dataIn) + { + } + + using difference_type = std::iterator_traits::difference_type; + using value_type = MidiMessageMetadata; + using reference = MidiMessageMetadata; + using pointer = void; + using iterator_category = std::bidirectional_iterator_tag; + + /** Make this iterator point to the next message in the buffer. */ + MidiBufferIterator& operator++() noexcept; + + /** Create a copy of this object, make this iterator point to the next message in + the buffer, then return the copy. + */ + MidiBufferIterator operator++ (int) noexcept; + + /** Return true if this iterator points to the same message as another + iterator instance, otherwise return false. + */ + bool operator== (const MidiBufferIterator& other) const noexcept { return data == other.data; } + + /** Return false if this iterator points to the same message as another + iterator instance, otherwise returns true. + */ + bool operator!= (const MidiBufferIterator& other) const noexcept { return ! operator== (other); } + + /** Return an instance of MidiMessageMetadata which describes the message to which + the iterator is currently pointing. + */ + reference operator*() const noexcept; + +private: + Ptr data = nullptr; +}; + //============================================================================== /** Holds a sequence of time-stamped midi events. @@ -44,20 +142,11 @@ class JUCE_API MidiBuffer public: //============================================================================== /** Creates an empty MidiBuffer. */ - MidiBuffer() noexcept; + MidiBuffer() noexcept = default; /** Creates a MidiBuffer containing a single midi message. */ explicit MidiBuffer (const MidiMessage& message) noexcept; - /** Creates a copy of another MidiBuffer. */ - MidiBuffer (const MidiBuffer&) noexcept; - - /** Makes a copy of another MidiBuffer. */ - MidiBuffer& operator= (const MidiBuffer&) noexcept; - - /** Destructor */ - ~MidiBuffer(); - //============================================================================== /** Removes all events from the buffer. */ void clear() noexcept; @@ -70,7 +159,7 @@ public: void clear (int start, int numSamples); /** Returns true if the buffer is empty. - To actually retrieve the events, use a MidiBuffer::Iterator object + To actually retrieve the events, use a MidiBufferIterator object */ bool isEmpty() const noexcept; @@ -91,7 +180,7 @@ public: If an event is added whose sample position is the same as one or more events already in the buffer, the new event will be placed after the existing ones. - To retrieve events, use a MidiBuffer::Iterator object + To retrieve events, use a MidiBufferIterator object */ void addEvent (const MidiMessage& midiMessage, int sampleNumber); @@ -109,7 +198,7 @@ public: it'll actually only store 3 bytes. If the midi data is invalid, it might not add an event at all. - To retrieve events, use a MidiBuffer::Iterator object + To retrieve events, use a MidiBufferIterator object */ void addEvent (const void* rawMidiData, int maxBytesOfMidiData, @@ -158,6 +247,23 @@ public: */ void ensureSize (size_t minimumNumBytes); + /** Get a read-only iterator pointing to the beginning of this buffer. */ + MidiBufferIterator begin() const noexcept { return cbegin(); } + + /** Get a read-only iterator pointing one past the end of this buffer. */ + MidiBufferIterator end() const noexcept { return cend(); } + + /** Get a read-only iterator pointing to the beginning of this buffer. */ + MidiBufferIterator cbegin() const noexcept { return MidiBufferIterator (data.begin()); } + + /** Get a read-only iterator pointing one past the end of this buffer. */ + MidiBufferIterator cend() const noexcept { return MidiBufferIterator (data.end()); } + + /** Get an iterator pointing to the first event with a timestamp greater-than or + equal-to `samplePosition`. + */ + MidiBufferIterator findNextSamplePosition (int samplePosition) const noexcept; + //============================================================================== /** Used to iterate through the events in a MidiBuffer. @@ -171,8 +277,10 @@ public: { public: //============================================================================== - /** Creates an Iterator for this MidiBuffer. */ - Iterator (const MidiBuffer&) noexcept; + /** Creates an Iterator for this MidiBuffer. + This class has been deprecated in favour of MidiBufferIterator. + */ + JUCE_DEPRECATED (Iterator (const MidiBuffer&) noexcept); /** Creates a copy of an iterator. */ Iterator (const Iterator&) = default; @@ -218,7 +326,7 @@ public: private: //============================================================================== const MidiBuffer& buffer; - const uint8* data; + MidiBufferIterator iterator; }; /** The raw data holding this buffer. diff --git a/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp b/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp index d027624dbc..7688dd2950 100644 --- a/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp @@ -145,25 +145,20 @@ void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer, const int numSamples, const bool injectIndirectEvents) { - MidiBuffer::Iterator i (buffer); - MidiMessage message; - int time; - const ScopedLock sl (lock); - while (i.getNextEvent (message, time)) - processNextMidiEvent (message); + for (const auto metadata : buffer) + processNextMidiEvent (metadata.getMessage()); if (injectIndirectEvents) { - MidiBuffer::Iterator i2 (eventsToAdd); const int firstEventToAdd = eventsToAdd.getFirstEventTime(); const double scaleFactor = numSamples / (double) (eventsToAdd.getLastEventTime() + 1 - firstEventToAdd); - while (i2.getNextEvent (message, time)) + for (const auto metadata : eventsToAdd) { - const int pos = jlimit (0, numSamples - 1, roundToInt ((time - firstEventToAdd) * scaleFactor)); - buffer.addEvent (message, startSample + pos); + const auto pos = jlimit (0, numSamples - 1, roundToInt ((metadata.samplePosition - firstEventToAdd) * scaleFactor)); + buffer.addEvent (metadata.getMessage(), startSample + pos); } } diff --git a/modules/juce_audio_basics/midi/juce_MidiRPN.cpp b/modules/juce_audio_basics/midi/juce_MidiRPN.cpp index 10e8e03a4c..fc4ef427a5 100644 --- a/modules/juce_audio_basics/midi/juce_MidiRPN.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiRPN.cpp @@ -351,14 +351,13 @@ private: //============================================================================== void expectContainsRPN (const MidiBuffer& midiBuffer, MidiRPNMessage expected) { - MidiBuffer::Iterator iter (midiBuffer); - MidiMessage midiMessage; MidiRPNMessage result = MidiRPNMessage(); MidiRPNDetector detector; - int samplePosition; // not actually used, so no need to initialise. - while (iter.getNextEvent (midiMessage, samplePosition)) + for (const auto metadata : midiBuffer) { + const auto midiMessage = metadata.getMessage(); + if (detector.parseControllerMessage (midiMessage.getChannel(), midiMessage.getControllerNumber(), midiMessage.getControllerValue(), diff --git a/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp b/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp index 24eb3a0619..286b4fd64c 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp +++ b/modules/juce_audio_basics/mpe/juce_MPEInstrument.cpp @@ -1834,12 +1834,8 @@ public: buffer.addEvents (MPEMessages::setLowerZone (5), 0, -1, 0); buffer.addEvents (MPEMessages::setUpperZone (6), 0, -1, 0); - MidiBuffer::Iterator iter (buffer); - MidiMessage message; - int samplePosition; // not actually used, so no need to initialise. - - while (iter.getNextEvent (message, samplePosition)) - test.processNextMidiEvent (message); + for (const auto metadata : buffer) + test.processNextMidiEvent (metadata.getMessage()); expect (test.getZoneLayout().getLowerZone().isActive()); expect (test.getZoneLayout().getUpperZone().isActive()); diff --git a/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp b/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp index 214df7cfde..a7e7a6a021 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp +++ b/modules/juce_audio_basics/mpe/juce_MPEMessages.cpp @@ -216,14 +216,11 @@ private: void extractRawBinaryData (const MidiBuffer& midiBuffer, const uint8* bufferToCopyTo, std::size_t maxBytes) { std::size_t pos = 0; - MidiBuffer::Iterator iter (midiBuffer); - MidiMessage midiMessage; - int samplePosition; // Note: Not actually used, so no need to initialise. - while (iter.getNextEvent (midiMessage, samplePosition)) + for (const auto metadata : midiBuffer) { - const uint8* data = midiMessage.getRawData(); - std::size_t dataSize = (std::size_t) midiMessage.getRawDataSize(); + const uint8* data = metadata.data; + std::size_t dataSize = (std::size_t) metadata.numBytes; if (pos + dataSize > maxBytes) return; diff --git a/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp b/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp index 51483f0eba..98bf69e835 100644 --- a/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp +++ b/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp @@ -110,48 +110,47 @@ void MPESynthesiserBase::renderNextBlock (AudioBuffer& outputAudio, // you must set the sample rate before using this! jassert (sampleRate != 0); - MidiBuffer::Iterator midiIterator (inputMidi); - midiIterator.setNextSamplePosition (startSample); + const auto midiIterator = inputMidi.findNextSamplePosition (startSample); bool firstEvent = true; - int midiEventPos; - MidiMessage m; const ScopedLock sl (noteStateLock); while (numSamples > 0) { - if (! midiIterator.getNextEvent (m, midiEventPos)) + if (midiIterator == inputMidi.cend()) { renderNextSubBlock (outputAudio, startSample, numSamples); return; } - auto samplesToNextMidiMessage = midiEventPos - startSample; + const auto metadata = *midiIterator; + auto samplesToNextMidiMessage = metadata.samplePosition - startSample; if (samplesToNextMidiMessage >= numSamples) { renderNextSubBlock (outputAudio, startSample, numSamples); - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); break; } if (samplesToNextMidiMessage < ((firstEvent && ! subBlockSubdivisionIsStrict) ? 1 : minimumSubBlockSize)) { - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); continue; } firstEvent = false; renderNextSubBlock (outputAudio, startSample, samplesToNextMidiMessage); - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); startSample += samplesToNextMidiMessage; numSamples -= samplesToNextMidiMessage; } - while (midiIterator.getNextEvent (m, midiEventPos)) - handleMidiEvent (m); + std::for_each (midiIterator, + inputMidi.cend(), + [&] (const MidiMessageMetadata& meta) { handleMidiEvent (meta.getMessage()); }); } // explicit instantiation for supported float types: diff --git a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp index dfcba78e74..1fd7faae2d 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp +++ b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp @@ -169,12 +169,8 @@ void MPEZoneLayout::processPitchbendRangeRpnMessage (MidiRPNMessage rpn) void MPEZoneLayout::processNextMidiBuffer (const MidiBuffer& buffer) { - MidiBuffer::Iterator iter (buffer); - MidiMessage message; - int samplePosition; // not actually used, so no need to initialise. - - while (iter.getNextEvent (message, samplePosition)) - processNextMidiEvent (message); + for (const auto metadata : buffer) + processNextMidiEvent (metadata.getMessage()); } //============================================================================== diff --git a/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp b/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp index 8c02bf246d..719528f824 100644 --- a/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp +++ b/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp @@ -163,18 +163,15 @@ void Synthesiser::processNextBlock (AudioBuffer& outputAudio, jassert (sampleRate != 0); const int targetChannels = outputAudio.getNumChannels(); - MidiBuffer::Iterator midiIterator (midiData); - midiIterator.setNextSamplePosition (startSample); + auto midiIterator = midiData.findNextSamplePosition (startSample); bool firstEvent = true; - int midiEventPos; - MidiMessage m; const ScopedLock sl (lock); while (numSamples > 0) { - if (! midiIterator.getNextEvent (m, midiEventPos)) + if (midiIterator == midiData.cend()) { if (targetChannels > 0) renderVoices (outputAudio, startSample, numSamples); @@ -182,20 +179,21 @@ void Synthesiser::processNextBlock (AudioBuffer& outputAudio, return; } - const int samplesToNextMidiMessage = midiEventPos - startSample; + const auto metadata = *midiIterator; + const int samplesToNextMidiMessage = metadata.samplePosition - startSample; if (samplesToNextMidiMessage >= numSamples) { if (targetChannels > 0) renderVoices (outputAudio, startSample, numSamples); - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); break; } if (samplesToNextMidiMessage < ((firstEvent && ! subBlockSubdivisionIsStrict) ? 1 : minimumSubBlockSize)) { - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); continue; } @@ -204,13 +202,14 @@ void Synthesiser::processNextBlock (AudioBuffer& outputAudio, if (targetChannels > 0) renderVoices (outputAudio, startSample, samplesToNextMidiMessage); - handleMidiEvent (m); + handleMidiEvent (metadata.getMessage()); startSample += samplesToNextMidiMessage; numSamples -= samplesToNextMidiMessage; } - while (midiIterator.getNextEvent (m, midiEventPos)) - handleMidiEvent (m); + std::for_each (midiIterator, + midiData.cend(), + [&] (const MidiMessageMetadata& meta) { handleMidiEvent (meta.getMessage()); }); } // explicit template instantiation diff --git a/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp b/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp index a5f761a2b6..ea0de56117 100644 --- a/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp +++ b/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp @@ -30,12 +30,8 @@ MidiOutput::MidiOutput (const String& deviceName, const String& deviceIdentifier void MidiOutput::sendBlockOfMessagesNow (const MidiBuffer& buffer) { - MidiBuffer::Iterator i (buffer); - MidiMessage message; - int samplePosition; // Note: Not actually used, so no need to initialise. - - while (i.getNextEvent (message, samplePosition)) - sendMessageNow (message); + for (const auto metadata : buffer) + sendMessageNow (metadata.getMessage()); } void MidiOutput::sendBlockOfMessages (const MidiBuffer& buffer, @@ -50,13 +46,10 @@ void MidiOutput::sendBlockOfMessages (const MidiBuffer& buffer, auto timeScaleFactor = 1000.0 / samplesPerSecondForBuffer; - const uint8* data; - int len, time; - - for (MidiBuffer::Iterator i (buffer); i.getNextEvent (data, len, time);) + for (const auto metadata : buffer) { - auto eventTime = millisecondCounterToStartAt + timeScaleFactor * time; - auto* m = new PendingMessage (data, len, eventTime); + auto eventTime = millisecondCounterToStartAt + timeScaleFactor * metadata.samplePosition; + auto* m = new PendingMessage (metadata.data, metadata.numBytes, eventTime); const ScopedLock sl (lock); diff --git a/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp b/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp index 97f7330340..ca72d2fee6 100644 --- a/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp +++ b/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp @@ -90,33 +90,28 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, int startSample = 0; int scale = 1 << 16; - const uint8* midiData; - int numBytes, samplePosition; - - MidiBuffer::Iterator iter (incomingMessages); - if (numSourceSamples > numSamples) { // if our list of events is longer than the buffer we're being // asked for, scale them down to squeeze them all in.. const int maxBlockLengthToUse = numSamples << 5; + auto iter = incomingMessages.cbegin(); + if (numSourceSamples > maxBlockLengthToUse) { startSample = numSourceSamples - maxBlockLengthToUse; numSourceSamples = maxBlockLengthToUse; - iter.setNextSamplePosition (startSample); + iter = incomingMessages.findNextSamplePosition (startSample); } scale = (numSamples << 10) / numSourceSamples; - while (iter.getNextEvent (midiData, numBytes, samplePosition)) + std::for_each (iter, incomingMessages.cend(), [&] (const MidiMessageMetadata& meta) { - samplePosition = ((samplePosition - startSample) * scale) >> 10; - - destBuffer.addEvent (midiData, numBytes, - jlimit (0, numSamples - 1, samplePosition)); - } + const auto pos = ((meta.samplePosition - startSample) * scale) >> 10; + destBuffer.addEvent (meta.data, meta.numBytes, jlimit (0, numSamples - 1, pos)); + }); } else { @@ -124,11 +119,9 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, // towards the end of the buffer startSample = numSamples - numSourceSamples; - while (iter.getNextEvent (midiData, numBytes, samplePosition)) - { - destBuffer.addEvent (midiData, numBytes, - jlimit (0, numSamples - 1, samplePosition + startSample)); - } + for (const auto metadata : incomingMessages) + destBuffer.addEvent (metadata.data, metadata.numBytes, + jlimit (0, numSamples - 1, metadata.samplePosition + startSample)); } incomingMessages.clear(); diff --git a/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp b/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp index e93bcdd291..06d4403fe0 100644 --- a/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp @@ -1418,22 +1418,18 @@ namespace AAXClasses #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect { - const juce::uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiBuffer); - AAX_CMidiPacket packet; packet.mIsImmediate = false; - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + for (const auto metadata : midiBuffer) { - jassert (isPositiveAndBelow (midiEventPosition, bufferSize)); + jassert (isPositiveAndBelow (metadata.samplePosition, bufferSize)); - if (midiEventSize <= 4) + if (metadata.numBytes <= 4) { - packet.mTimestamp = (uint32_t) midiEventPosition; - packet.mLength = (uint32_t) midiEventSize; - memcpy (packet.mData, midiEventData, (size_t) midiEventSize); + packet.mTimestamp = (uint32_t) metadata.samplePosition; + packet.mLength = (uint32_t) metadata.numBytes; + memcpy (packet.mData, metadata.data, (size_t) metadata.numBytes); check (midiNodesOut->PostMIDIPacket (&packet)); } diff --git a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm b/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm index 91133ee978..6d8c2c1119 100644 --- a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm +++ b/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm @@ -1821,15 +1821,12 @@ private: UInt32 numPackets = 0; size_t dataSize = 0; - const juce::uint8* midiEventData; - int midiEventSize, midiEventPosition; - - for (MidiBuffer::Iterator i (midiEvents); i.getNextEvent (midiEventData, midiEventSize, midiEventPosition);) + for (const auto metadata : midiEvents) { - jassert (isPositiveAndBelow (midiEventPosition, nFrames)); + jassert (isPositiveAndBelow (metadata.samplePosition, nFrames)); ignoreUnused (nFrames); - dataSize += (size_t) midiEventSize; + dataSize += (size_t) metadata.numBytes; ++numPackets; } @@ -1843,11 +1840,11 @@ private: p = packetList->packet; - for (MidiBuffer::Iterator i (midiEvents); i.getNextEvent (midiEventData, midiEventSize, midiEventPosition);) + for (const auto metadata : midiEvents) { - p->timeStamp = (MIDITimeStamp) midiEventPosition; - p->length = (UInt16) midiEventSize; - memcpy (p->data, midiEventData, (size_t) midiEventSize); + p->timeStamp = (MIDITimeStamp) metadata.samplePosition; + p->length = (UInt16) metadata.numBytes; + memcpy (p->data, metadata.data, (size_t) metadata.numBytes); p = MIDIPacketNext (p); } diff --git a/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm b/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm index 4810a0f63c..d56ccfba91 100644 --- a/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm +++ b/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm @@ -1528,11 +1528,8 @@ private: #if JucePlugin_ProducesMidiOutput && JUCE_AUV3_MIDI_OUTPUT_SUPPORTED if (auto midiOut = [au MIDIOutputEventBlock]) { - MidiMessage msg; - int samplePosition; - - for (MidiBuffer::Iterator it (midiMessages); it.getNextEvent (msg, samplePosition);) - midiOut (samplePosition, 0, msg.getRawDataSize(), msg.getRawData()); + for (const auto metadata : midiMessages) + midiOut (metadata.samplePosition, 0, metadata.numBytes, metadata.data); } #endif diff --git a/modules/juce_audio_plugin_client/RTAS/juce_RTAS_Wrapper.cpp b/modules/juce_audio_plugin_client/RTAS/juce_RTAS_Wrapper.cpp index 501995b082..2c70b9cadf 100644 --- a/modules/juce_audio_plugin_client/RTAS/juce_RTAS_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/RTAS/juce_RTAS_Wrapper.cpp @@ -590,13 +590,9 @@ public: if (! midiEvents.isEmpty()) { #if JucePlugin_ProducesMidiOutput - const juce::uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiEvents); - - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + for (const auto metadata : midiEvents) { - //jassert (midiEventPosition >= 0 && midiEventPosition < (int) numSamples); + //jassert (metadata.samplePosition >= 0 && metadata.samplePosition < (int) numSamples); } #elif JUCE_DEBUG || JUCE_LOG_ASSERTIONS // if your plugin creates midi messages, you'll need to set diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index 2358293a84..d3f2dca555 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -521,15 +521,11 @@ public: outgoingEvents.ensureSize (numEvents); outgoingEvents.clear(); - const uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiEvents); - - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + for (const auto metadata : midiEvents) { - jassert (midiEventPosition >= 0 && midiEventPosition < numSamples); + jassert (metadata.samplePosition >= 0 && metadata.samplePosition < numSamples); - outgoingEvents.addEvent (midiEventData, midiEventSize, midiEventPosition); + outgoingEvents.addEvent (metadata.data, metadata.numBytes, metadata.samplePosition); } // Send VST events to the host. diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index 0e2eae0842..e2f87329a5 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -1072,17 +1072,14 @@ public: if (wantsMidiMessages) { - const uint8* midiEventData; - int midiEventSize, midiEventPosition; - - for (MidiBuffer::Iterator i (midiMessages); i.getNextEvent (midiEventData, midiEventSize, midiEventPosition);) + for (const auto metadata : midiMessages) { - if (midiEventSize <= 3) + if (metadata.numBytes <= 3) MusicDeviceMIDIEvent (audioUnit, - midiEventData[0], midiEventData[1], midiEventData[2], - (UInt32) midiEventPosition); + metadata.data[0], metadata.data[1], metadata.data[2], + (UInt32) metadata.samplePosition); else - MusicDeviceSysEx (audioUnit, midiEventData, (UInt32) midiEventSize); + MusicDeviceSysEx (audioUnit, metadata.data, (UInt32) metadata.numBytes); } midiMessages.clear(); diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index 53516ccbbd..81bf489211 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -514,20 +514,15 @@ public: Steinberg::Vst::IParameterChanges* parameterChanges = nullptr, Steinberg::Vst::IMidiMapping* midiMapping = nullptr) { - MidiBuffer::Iterator iterator (midiBuffer); - const uint8* midiEventData = nullptr; - int midiEventSize = 0; - int midiEventPosition = 0; - enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once int numEvents = 0; - while (iterator.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + for (const auto metadata : midiBuffer) { if (++numEvents > maxNumEvents) break; - MidiMessage msg (midiEventData, midiEventSize); + auto msg = metadata.getMessage(); if (midiMapping != nullptr && parameterChanges != nullptr) { @@ -544,7 +539,7 @@ public: Steinberg::int32 ignore; if (auto* queue = parameterChanges->addParameterData (controlParamID, ignore)) - queue->addPoint (midiEventPosition, controlEvent.paramValue, ignore); + queue->addPoint (metadata.samplePosition, controlEvent.paramValue, ignore); } continue; @@ -575,7 +570,7 @@ public: else if (msg.isSysEx()) { e.type = Steinberg::Vst::Event::kDataEvent; - e.data.bytes = midiEventData + 1; + e.data.bytes = metadata.data + 1; e.data.size = (uint32) msg.getSysExDataSize(); e.data.type = Steinberg::Vst::DataEvent::kMidiSysEx; } @@ -592,7 +587,7 @@ public: } e.busIndex = 0; - e.sampleOffset = midiEventPosition; + e.sampleOffset = metadata.samplePosition; result.addEvent (e); } diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index a566774517..82ab4dfa15 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -2384,13 +2384,9 @@ private: midiEventsToSend.clear(); midiEventsToSend.ensureSize (1); - MidiBuffer::Iterator iter (midiMessages); - const uint8* midiData; - int numBytesOfMidiData, samplePosition; - - while (iter.getNextEvent (midiData, numBytesOfMidiData, samplePosition)) - midiEventsToSend.addEvent (midiData, numBytesOfMidiData, - jlimit (0, numSamples - 1, samplePosition)); + for (const auto metadata : midiMessages) + midiEventsToSend.addEvent (metadata.data, metadata.numBytes, + jlimit (0, numSamples - 1, metadata.samplePosition)); vstEffect->dispatcher (vstEffect, Vst2::effProcessEvents, 0, 0, midiEventsToSend.events, 0); }