2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
30 #include "juce_MidiBuffer.h"
33 //==============================================================================
34 MidiBuffer::MidiBuffer() noexcept
39 MidiBuffer::MidiBuffer (const MidiMessage
& message
) noexcept
42 addEvent (message
, 0);
45 MidiBuffer::MidiBuffer (const MidiBuffer
& other
) noexcept
47 bytesUsed (other
.bytesUsed
)
51 MidiBuffer
& MidiBuffer::operator= (const MidiBuffer
& other
) noexcept
53 bytesUsed
= other
.bytesUsed
;
59 void MidiBuffer::swapWith (MidiBuffer
& other
) noexcept
61 data
.swapWith (other
.data
);
62 std::swap (bytesUsed
, other
.bytesUsed
);
65 MidiBuffer::~MidiBuffer()
69 inline uint8
* MidiBuffer::getData() const noexcept
71 return static_cast <uint8
*> (data
.getData());
74 inline int MidiBuffer::getEventTime (const void* const d
) noexcept
76 return *static_cast <const int*> (d
);
79 inline uint16
MidiBuffer::getEventDataSize (const void* const d
) noexcept
81 return *reinterpret_cast <const uint16
*> (static_cast <const char*> (d
) + sizeof (int));
84 inline uint16
MidiBuffer::getEventTotalSize (const void* const d
) noexcept
86 return getEventDataSize (d
) + sizeof (int) + sizeof (uint16
);
89 void MidiBuffer::clear() noexcept
94 void MidiBuffer::clear (const int startSample
, const int numSamples
)
96 uint8
* const start
= findEventAfter (getData(), startSample
- 1);
97 uint8
* const end
= findEventAfter (start
, startSample
+ numSamples
- 1);
101 const int bytesToMove
= bytesUsed
- (int) (end
- getData());
104 memmove (start
, end
, bytesToMove
);
106 bytesUsed
-= (int) (end
- start
);
110 void MidiBuffer::addEvent (const MidiMessage
& m
, const int sampleNumber
)
112 addEvent (m
.getRawData(), m
.getRawDataSize(), sampleNumber
);
115 namespace MidiBufferHelpers
117 int findActualEventLength (const uint8
* const data
, const int maxBytes
) noexcept
119 unsigned int byte
= (unsigned int) *data
;
122 if (byte
== 0xf0 || byte
== 0xf7)
124 const uint8
* d
= data
+ 1;
126 while (d
< data
+ maxBytes
)
130 size
= (int) (d
- data
);
132 else if (byte
== 0xff)
135 const int bytesLeft
= MidiMessage::readVariableLengthVal (data
+ 1, n
);
136 size
= jmin (maxBytes
, n
+ 2 + bytesLeft
);
138 else if (byte
>= 0x80)
140 size
= jmin (maxBytes
, MidiMessage::getMessageLengthFromFirstByte ((uint8
) byte
));
147 void MidiBuffer::addEvent (const void* const newData
, const int maxBytes
, const int sampleNumber
)
149 const int numBytes
= MidiBufferHelpers::findActualEventLength (static_cast <const uint8
*> (newData
), maxBytes
);
153 int spaceNeeded
= bytesUsed
+ numBytes
+ sizeof (int) + sizeof (uint16
);
154 data
.ensureSize ((spaceNeeded
+ spaceNeeded
/ 2 + 8) & ~7);
156 uint8
* d
= findEventAfter (getData(), sampleNumber
);
157 const int bytesToMove
= bytesUsed
- (int) (d
- getData());
160 memmove (d
+ numBytes
+ sizeof (int) + sizeof (uint16
), d
, bytesToMove
);
162 *reinterpret_cast <int*> (d
) = sampleNumber
;
164 *reinterpret_cast <uint16
*> (d
) = (uint16
) numBytes
;
165 d
+= sizeof (uint16
);
167 memcpy (d
, newData
, numBytes
);
169 bytesUsed
+= numBytes
+ sizeof (int) + sizeof (uint16
);
173 void MidiBuffer::addEvents (const MidiBuffer
& otherBuffer
,
174 const int startSample
,
175 const int numSamples
,
176 const int sampleDeltaToAdd
)
178 Iterator
i (otherBuffer
);
179 i
.setNextSamplePosition (startSample
);
181 const uint8
* eventData
;
182 int eventSize
, position
;
184 while (i
.getNextEvent (eventData
, eventSize
, position
)
185 && (position
< startSample
+ numSamples
|| numSamples
< 0))
187 addEvent (eventData
, eventSize
, position
+ sampleDeltaToAdd
);
191 void MidiBuffer::ensureSize (size_t minimumNumBytes
)
193 data
.ensureSize (minimumNumBytes
);
196 bool MidiBuffer::isEmpty() const noexcept
198 return bytesUsed
== 0;
201 int MidiBuffer::getNumEvents() const noexcept
204 const uint8
* d
= getData();
205 const uint8
* const end
= d
+ bytesUsed
;
209 d
+= getEventTotalSize (d
);
216 int MidiBuffer::getFirstEventTime() const noexcept
218 return bytesUsed
> 0 ? getEventTime (data
.getData()) : 0;
221 int MidiBuffer::getLastEventTime() const noexcept
226 const uint8
* d
= getData();
227 const uint8
* const endData
= d
+ bytesUsed
;
231 const uint8
* const nextOne
= d
+ getEventTotalSize (d
);
233 if (nextOne
>= endData
)
234 return getEventTime (d
);
240 uint8
* MidiBuffer::findEventAfter (uint8
* d
, const int samplePosition
) const noexcept
242 const uint8
* const endData
= getData() + bytesUsed
;
244 while (d
< endData
&& getEventTime (d
) <= samplePosition
)
245 d
+= getEventTotalSize (d
);
250 //==============================================================================
251 MidiBuffer::Iterator::Iterator (const MidiBuffer
& buffer_
) noexcept
253 data (buffer_
.getData())
257 MidiBuffer::Iterator::~Iterator() noexcept
261 //==============================================================================
262 void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition
) noexcept
264 data
= buffer
.getData();
265 const uint8
* dataEnd
= data
+ buffer
.bytesUsed
;
267 while (data
< dataEnd
&& getEventTime (data
) < samplePosition
)
268 data
+= getEventTotalSize (data
);
271 bool MidiBuffer::Iterator::getNextEvent (const uint8
* &midiData
, int& numBytes
, int& samplePosition
) noexcept
273 if (data
>= buffer
.getData() + buffer
.bytesUsed
)
276 samplePosition
= getEventTime (data
);
277 numBytes
= getEventDataSize (data
);
278 data
+= sizeof (int) + sizeof (uint16
);
285 bool MidiBuffer::Iterator::getNextEvent (MidiMessage
& result
, int& samplePosition
) noexcept
287 if (data
>= buffer
.getData() + buffer
.bytesUsed
)
290 samplePosition
= getEventTime (data
);
291 const int numBytes
= getEventDataSize (data
);
292 data
+= sizeof (int) + sizeof (uint16
);
293 result
= MidiMessage (data
, numBytes
, samplePosition
);