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
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));
99 MidiBufferHelpers::getEventDataSize (data),
100 MidiBufferHelpers::getEventTime (data) };
106 addEvent (message, 0);
116 auto start = MidiBufferHelpers::findEventAfter (
data.
begin(),
data.
end(), startSample - 1);
117 auto end = MidiBufferHelpers::findEventAfter (start,
data.
end(), startSample + numSamples - 1);
129 auto numBytes = MidiBufferHelpers::findActualEventLength (
static_cast<const uint8*
> (newData), maxBytes);
146 writeUnaligned<int32> (d, sampleNumber);
148 writeUnaligned<uint16> (d,
static_cast<uint16> (numBytes));
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);
175 d += MidiBufferHelpers::getEventTotalSize (d);
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)
216 : buffer (b), iterator (b.data.
begin())
220void MidiBuffer::Iterator::setNextSamplePosition (
int samplePosition)
noexcept
225bool MidiBuffer::Iterator::getNextEvent (
const uint8*& midiData,
int& numBytes,
int& samplePosition)
noexcept
227 if (iterator == buffer.cend())
230 const auto metadata = *iterator++;
231 midiData = metadata.data;
232 numBytes = metadata.numBytes;
233 samplePosition = metadata.samplePosition;
237bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result,
int& samplePosition)
noexcept
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");
265 const auto message = MidiMessage::noteOn (1, 64, 0.5f);
267 const auto testBuffer = [&]
270 buffer.addEvent (message, 0);
271 buffer.addEvent (message, 10);
272 buffer.addEvent (message, 20);
273 buffer.addEvent (message, 30);
278 auto buffer = testBuffer;
279 buffer.clear (10, 0);
280 expectEquals (buffer.getNumEvents(), 4);
284 auto buffer = testBuffer;
285 buffer.clear (10, 1);
286 expectEquals (buffer.getNumEvents(), 3);
290 auto buffer = testBuffer;
291 buffer.clear (10, 10);
292 expectEquals (buffer.getNumEvents(), 3);
296 auto buffer = testBuffer;
297 buffer.clear (10, 20);
298 expectEquals (buffer.getNumEvents(), 2);
302 auto buffer = testBuffer;
303 buffer.clear (10, 30);
304 expectEquals (buffer.getNumEvents(), 1);
308 auto buffer = testBuffer;
309 buffer.clear (10, 300);
310 expectEquals (buffer.getNumEvents(), 1);
316static MidiBufferTest midiBufferTest;
void ensureStorageAllocated(int minNumElements)
Increases the array's internal storage to hold a minimum number of elements.
void clearQuick()
Removes all elements from the array without freeing the array's allocated storage.
int size() const noexcept
Returns the current number of elements in the array.
void removeRange(int startIndex, int numberToRemove)
Removes a range of elements from the array.
ElementType * begin() noexcept
Returns a pointer to the first element in the array.
ElementType * end() noexcept
Returns a pointer to the element which follows the last element in the array.
void insertMultiple(int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
Inserts multiple copies of an element into the array at a given position.
An iterator to move over contiguous raw MIDI data, which Allows iterating over a MidiBuffer using C++...
MidiBufferIterator & operator++() noexcept
Make this iterator point to the next message in the buffer.
reference operator*() const noexcept
Return an instance of MidiMessageMetadata which describes the message to which the iterator is curren...
Holds a sequence of time-stamped midi events.
int getFirstEventTime() const noexcept
Returns the sample number of the first event in the buffer.
int getLastEventTime() const noexcept
Returns the sample number of the last event in the buffer.
void ensureSize(size_t minimumNumBytes)
Preallocates some memory for the buffer to use.
int getNumEvents() const noexcept
Counts the number of events in the buffer.
MidiBufferIterator findNextSamplePosition(int samplePosition) const noexcept
Get an iterator pointing to the first event with a timestamp greater-than or equal-to samplePosition.
MidiBufferIterator cend() const noexcept
Get a read-only iterator pointing one past the end of this buffer.
bool isEmpty() const noexcept
Returns true if the buffer is empty.
void swapWith(MidiBuffer &) noexcept
Exchanges the contents of this buffer with another one.
bool addEvent(const MidiMessage &midiMessage, int sampleNumber)
Adds an event to the buffer.
MidiBuffer() noexcept=default
Creates an empty MidiBuffer.
void clear() noexcept
Removes all events from the buffer.
void addEvents(const MidiBuffer &otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd)
Adds some events from another buffer to this one.
Array< uint8 > data
The raw data holding this buffer.
MidiBufferIterator end() const noexcept
Get a read-only iterator pointing one past the end of this buffer.
Encapsulates a MIDI message.
const uint8 * getRawData() const noexcept
Returns a pointer to the raw midi data.
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
Based on the first byte of a short midi message, this uses a lookup table to return the message lengt...
static VariableLengthValue readVariableLengthValue(const uint8 *data, int maxBytesToUse) noexcept
Reads a midi variable-length integer, with protection against buffer overflow.
int getRawDataSize() const noexcept
Returns the number of bytes of data in the message.
unsigned short uint16
A platform-independent 16-bit unsigned integer type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
signed int int32
A platform-independent 32-bit signed integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
RangedDirectoryIterator begin(const RangedDirectoryIterator &it)
Returns the iterator that was passed in.