26namespace MidiBufferHelpers
28 inline int getEventTime (
const void* d)
noexcept
30 return readUnaligned<int32> (d);
33 inline uint16 getEventDataSize (
const void* d)
noexcept
35 return readUnaligned<uint16> (
static_cast<const char*
> (d) +
sizeof (int32));
38 inline uint16 getEventTotalSize (
const void* d)
noexcept
40 return (uint16) (getEventDataSize (d) +
sizeof (int32) +
sizeof (uint16));
43 static int findActualEventLength (
const uint8* data,
int maxBytes)
noexcept
45 auto byte = (
unsigned int) *data;
47 if (
byte == 0xf0 ||
byte == 0xf7)
52 if (data[i++] == 0xf7)
64 return jmin (maxBytes, var.value + 2 + var.bytesUsed);
73 static uint8* findEventAfter (uint8* d, uint8* endData,
int samplePosition)
noexcept
75 while (d < endData && getEventTime (d) <= samplePosition)
76 d += getEventTotalSize (d);
85 data +=
sizeof (int32) +
sizeof (uint16) + size_t (MidiBufferHelpers::getEventDataSize (data));
98 return { data +
sizeof (int32) +
sizeof (uint16),
99 MidiBufferHelpers::getEventDataSize (data),
100 MidiBufferHelpers::getEventTime (data) };
116 auto start = MidiBufferHelpers::findEventAfter (
data.begin(),
data.end(), startSample - 1);
117 auto end = MidiBufferHelpers::findEventAfter (start,
data.end(), startSample + numSamples - 1);
119 data.removeRange ((
int) (start -
data.begin()), (
int) (
end - start));
129 auto numBytes = MidiBufferHelpers::findActualEventLength (
static_cast<const uint8*
> (newData), maxBytes);
134 if (std::numeric_limits<uint16>::max() < numBytes)
140 auto newItemSize = (size_t) numBytes +
sizeof (int32) +
sizeof (uint16);
141 auto offset = (int) (MidiBufferHelpers::findEventAfter (
data.begin(),
data.end(), sampleNumber) -
data.begin());
143 data.insertMultiple (offset, 0, (
int) newItemSize);
145 auto* d =
data.begin() + offset;
146 writeUnaligned<int32> (d, sampleNumber);
148 writeUnaligned<uint16> (d,
static_cast<uint16
> (numBytes));
149 d +=
sizeof (uint16);
150 memcpy (d, newData, (
size_t) numBytes);
156 int startSample,
int numSamples,
int sampleDeltaToAdd)
160 const auto metadata = *i;
162 if (metadata.samplePosition >= startSample + numSamples && numSamples >= 0)
165 addEvent (metadata.data, metadata.numBytes, metadata.samplePosition + sampleDeltaToAdd);
174 for (
auto d =
data.begin(); d <
end; ++n)
175 d += MidiBufferHelpers::getEventTotalSize (d);
182 return data.size() > 0 ? MidiBufferHelpers::getEventTime (
data.begin()) : 0;
187 if (
data.size() == 0)
190 auto endData =
data.end();
192 for (
auto d =
data.begin();;)
194 auto nextOne = d + MidiBufferHelpers::getEventTotalSize (d);
196 if (nextOne >= endData)
197 return MidiBufferHelpers::getEventTime (d);
212JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wdeprecated-declarations")
213JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
222 iterator = buffer.findNextSamplePosition (samplePosition);
227 if (iterator == buffer.cend())
230 const auto metadata = *iterator++;
231 midiData = metadata.data;
232 numBytes = metadata.numBytes;
233 samplePosition = metadata.samplePosition;
239 if (iterator == buffer.cend())
242 const auto metadata = *iterator++;
243 result = metadata.getMessage();
244 samplePosition = metadata.samplePosition;
248JUCE_END_IGNORE_WARNINGS_MSVC
249JUCE_END_IGNORE_WARNINGS_GCC_LIKE
255struct MidiBufferTest final :
public UnitTest
258 :
UnitTest (
"MidiBuffer", UnitTestCategories::midi)
261 void runTest()
override
263 beginTest (
"Clear messages");
267 const auto testBuffer = [&]
278 auto buffer = testBuffer;
279 buffer.
clear (10, 0);
284 auto buffer = testBuffer;
285 buffer.
clear (10, 1);
290 auto buffer = testBuffer;
291 buffer.
clear (10, 10);
296 auto buffer = testBuffer;
297 buffer.
clear (10, 20);
302 auto buffer = testBuffer;
303 buffer.
clear (10, 30);
308 auto buffer = testBuffer;
309 buffer.
clear (10, 300);
316static MidiBufferTest midiBufferTest;
MidiBufferIterator & operator++() noexcept
reference operator*() const noexcept
Iterator(const MidiBuffer &b) noexcept
void setNextSamplePosition(int samplePosition) noexcept
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
int getFirstEventTime() const noexcept
int getLastEventTime() const noexcept
void ensureSize(size_t minimumNumBytes)
int getNumEvents() const noexcept
MidiBufferIterator cbegin() const noexcept
MidiBufferIterator findNextSamplePosition(int samplePosition) const noexcept
MidiBufferIterator cend() const noexcept
bool isEmpty() const noexcept
void swapWith(MidiBuffer &) noexcept
bool addEvent(const MidiMessage &midiMessage, int sampleNumber)
MidiBuffer() noexcept=default
void addEvents(const MidiBuffer &otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd)
MidiBufferIterator begin() const noexcept
MidiBufferIterator end() const noexcept
const uint8 * getRawData() const noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
static VariableLengthValue readVariableLengthValue(const uint8 *data, int maxBytesToUse) noexcept
int getRawDataSize() const noexcept