1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

MidiBuffer: Add iterator compatible with C++11 range-for

This commit is contained in:
reuk 2020-03-05 11:29:20 +00:00
parent e7e1de78fa
commit eae9a10944
21 changed files with 259 additions and 205 deletions

View file

@ -88,11 +88,9 @@ public:
// get note duration
auto noteDuration = static_cast<int> (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());
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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<float>&, 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<Ptr>::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.

View file

@ -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);
}
}

View file

@ -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(),

View file

@ -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());

View file

@ -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;

View file

@ -110,48 +110,47 @@ void MPESynthesiserBase::renderNextBlock (AudioBuffer<floatType>& 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:

View file

@ -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());
}
//==============================================================================

View file

@ -163,18 +163,15 @@ void Synthesiser::processNextBlock (AudioBuffer<floatType>& 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<floatType>& 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<floatType>& 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

View file

@ -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);

View file

@ -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();

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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();

View file

@ -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);
}

View file

@ -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);
}