OpenShot Library | libopenshot-audio 0.2.0
juce_MidiBuffer.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26namespace MidiBufferHelpers
27{
28 inline int getEventTime (const void* const d) noexcept
29 {
30 return readUnaligned<int32> (d);
31 }
32
33 inline uint16 getEventDataSize (const void* const d) noexcept
34 {
35 return readUnaligned<uint16> (static_cast<const char*> (d) + sizeof (int32));
36 }
37
38 inline uint16 getEventTotalSize (const void* const d) noexcept
39 {
40 return (uint16) (getEventDataSize (d) + sizeof (int32) + sizeof (uint16));
41 }
42
43 static int findActualEventLength (const uint8* const data, const int maxBytes) noexcept
44 {
45 unsigned int byte = (unsigned int) *data;
46 int size = 0;
47
48 if (byte == 0xf0 || byte == 0xf7)
49 {
50 const uint8* d = data + 1;
51
52 while (d < data + maxBytes)
53 if (*d++ == 0xf7)
54 break;
55
56 size = (int) (d - data);
57 }
58 else if (byte == 0xff)
59 {
60 if (maxBytes == 1)
61 {
62 size = 1;
63 }
64 else
65 {
66 int n;
67 const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n);
68 size = jmin (maxBytes, n + 2 + bytesLeft);
69 }
70 }
71 else if (byte >= 0x80)
72 {
73 size = jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte));
74 }
75
76 return size;
77 }
78
79 static uint8* findEventAfter (uint8* d, uint8* endData, const int samplePosition) noexcept
80 {
81 while (d < endData && getEventTime (d) <= samplePosition)
82 d += getEventTotalSize (d);
83
84 return d;
85 }
86}
87
88//==============================================================================
91
92MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept : data (other.data) {}
93
95{
96 data = other.data;
97 return *this;
98}
99
100MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept
101{
102 addEvent (message, 0);
103}
104
105void MidiBuffer::swapWith (MidiBuffer& other) noexcept { data.swapWith (other.data); }
106void MidiBuffer::clear() noexcept { data.clearQuick(); }
107void MidiBuffer::ensureSize (size_t minimumNumBytes) { data.ensureStorageAllocated ((int) minimumNumBytes); }
108bool MidiBuffer::isEmpty() const noexcept { return data.size() == 0; }
109
110void MidiBuffer::clear (const int startSample, const int numSamples)
111{
112 uint8* const start = MidiBufferHelpers::findEventAfter (data.begin(), data.end(), startSample - 1);
113 uint8* const end = MidiBufferHelpers::findEventAfter (start, data.end(), startSample + numSamples - 1);
114
115 data.removeRange ((int) (start - data.begin()), (int) (end - data.begin()));
116}
117
118void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber)
119{
120 addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber);
121}
122
123void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const int sampleNumber)
124{
125 const int numBytes = MidiBufferHelpers::findActualEventLength (static_cast<const uint8*> (newData), maxBytes);
126
127 if (numBytes > 0)
128 {
129 const size_t newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16);
130 const int offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin());
131
132 data.insertMultiple (offset, 0, (int) newItemSize);
133
134 uint8* const d = data.begin() + offset;
135 writeUnaligned<int32> (d, sampleNumber);
136 writeUnaligned<uint16> (d + 4, static_cast<uint16> (numBytes));
137 memcpy (d + 6, newData, (size_t) numBytes);
138 }
139}
140
141void MidiBuffer::addEvents (const MidiBuffer& otherBuffer,
142 const int startSample,
143 const int numSamples,
144 const int sampleDeltaToAdd)
145{
146 Iterator i (otherBuffer);
147 i.setNextSamplePosition (startSample);
148
149 const uint8* eventData;
150 int eventSize, position;
151
152 while (i.getNextEvent (eventData, eventSize, position)
153 && (position < startSample + numSamples || numSamples < 0))
154 {
155 addEvent (eventData, eventSize, position + sampleDeltaToAdd);
156 }
157}
158
159int MidiBuffer::getNumEvents() const noexcept
160{
161 int n = 0;
162 const uint8* const end = data.end();
163
164 for (const uint8* d = data.begin(); d < end; ++n)
165 d += MidiBufferHelpers::getEventTotalSize (d);
166
167 return n;
168}
169
171{
172 return data.size() > 0 ? MidiBufferHelpers::getEventTime (data.begin()) : 0;
173}
174
176{
177 if (data.size() == 0)
178 return 0;
179
180 const uint8* const endData = data.end();
181
182 for (const uint8* d = data.begin();;)
183 {
184 const uint8* const nextOne = d + MidiBufferHelpers::getEventTotalSize (d);
185
186 if (nextOne >= endData)
187 return MidiBufferHelpers::getEventTime (d);
188
189 d = nextOne;
190 }
191}
192
193//==============================================================================
195 : buffer (b), data (b.data.begin())
196{
197}
198
200
201void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept
202{
203 data = buffer.data.begin();
204 const uint8* const dataEnd = buffer.data.end();
205
206 while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition)
207 data += MidiBufferHelpers::getEventTotalSize (data);
208}
209
210bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, int& samplePosition) noexcept
211{
212 if (data >= buffer.data.end())
213 return false;
214
215 samplePosition = MidiBufferHelpers::getEventTime (data);
216 const int itemSize = MidiBufferHelpers::getEventDataSize (data);
217 numBytes = itemSize;
218 midiData = data + sizeof (int32) + sizeof (uint16);
219 data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize;
220
221 return true;
222}
223
224bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept
225{
226 if (data >= buffer.data.end())
227 return false;
228
229 samplePosition = MidiBufferHelpers::getEventTime (data);
230 const int itemSize = MidiBufferHelpers::getEventDataSize (data);
231 result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition);
232 data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize;
233
234 return true;
235}
236
237} // namespace juce
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.
Definition juce_Array.h:202
int size() const noexcept
Returns the current number of elements in the array.
Definition juce_Array.h:219
void removeRange(int startIndex, int numberToRemove)
Removes a range of elements from the array.
Definition juce_Array.h:873
ElementType * begin() const noexcept
Returns a pointer to the first element in the array.
Definition juce_Array.h:309
void insertMultiple(int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
Inserts multiple copies of an element into the array at a given position.
Definition juce_Array.h:437
ElementType * data() const noexcept
Returns a pointer to the first element in the array.
Definition juce_Array.h:325
ElementType * end() const noexcept
Returns a pointer to the element which follows the last element in the array.
Definition juce_Array.h:317
Used to iterate through the events in a MidiBuffer.
void setNextSamplePosition(int samplePosition) noexcept
Repositions the iterator so that the next event retrieved will be the first one whose sample position...
~Iterator() noexcept
Destructor.
Iterator(const MidiBuffer &) noexcept
Creates an Iterator for this MidiBuffer.
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
Retrieves a copy of the next event from the buffer.
Holds a sequence of time-stamped midi events.
int getFirstEventTime() const noexcept
Returns the sample number of the first event in the buffer.
MidiBuffer & operator=(const MidiBuffer &) noexcept
Makes a copy of another MidiBuffer.
void addEvent(const MidiMessage &midiMessage, int sampleNumber)
Adds an event to 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.
MidiBuffer() noexcept
Creates an empty MidiBuffer.
int getNumEvents() const noexcept
Counts the number of events in the 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.
~MidiBuffer()
Destructor.
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.
Encapsulates a MIDI message.
static int readVariableLengthVal(const uint8 *data, int &numBytesUsed) noexcept
Reads a midi variable-length integer.
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...
int getRawDataSize() const noexcept
Returns the number of bytes of data in the message.