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:
parent
e7e1de78fa
commit
eae9a10944
21 changed files with 259 additions and 205 deletions
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue