OpenShot Library | OpenShotAudio  0.2.2
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 
23 namespace juce
24 {
25 
26 namespace MidiBufferHelpers
27 {
28  inline int getEventTime (const void* d) noexcept
29  {
30  return readUnaligned<int32> (d);
31  }
32 
33  inline uint16 getEventDataSize (const void* d) noexcept
34  {
35  return readUnaligned<uint16> (static_cast<const char*> (d) + sizeof (int32));
36  }
37 
38  inline uint16 getEventTotalSize (const void* d) noexcept
39  {
40  return (uint16) (getEventDataSize (d) + sizeof (int32) + sizeof (uint16));
41  }
42 
43  static int findActualEventLength (const uint8* data, int maxBytes) noexcept
44  {
45  auto byte = (unsigned int) *data;
46 
47  if (byte == 0xf0 || byte == 0xf7)
48  {
49  int i = 1;
50 
51  while (i < maxBytes)
52  if (data[i++] == 0xf7)
53  break;
54 
55  return i;
56  }
57 
58  if (byte == 0xff)
59  {
60  if (maxBytes == 1)
61  return 1;
62 
63  int n;
64  auto bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n);
65  return jmin (maxBytes, n + 2 + bytesLeft);
66  }
67 
68  if (byte >= 0x80)
69  return jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte));
70 
71  return 0;
72  }
73 
74  static uint8* findEventAfter (uint8* d, uint8* endData, int samplePosition) noexcept
75  {
76  while (d < endData && getEventTime (d) <= samplePosition)
77  d += getEventTotalSize (d);
78 
79  return d;
80  }
81 }
82 
83 //==============================================================================
86 
87 MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept : data (other.data) {}
88 
90 {
91  data = other.data;
92  return *this;
93 }
94 
95 MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept
96 {
97  addEvent (message, 0);
98 }
99 
100 void MidiBuffer::swapWith (MidiBuffer& other) noexcept { data.swapWith (other.data); }
101 void MidiBuffer::clear() noexcept { data.clearQuick(); }
102 void MidiBuffer::ensureSize (size_t minimumNumBytes) { data.ensureStorageAllocated ((int) minimumNumBytes); }
103 bool MidiBuffer::isEmpty() const noexcept { return data.size() == 0; }
104 
105 void MidiBuffer::clear (int startSample, int numSamples)
106 {
107  auto start = MidiBufferHelpers::findEventAfter (data.begin(), data.end(), startSample - 1);
108  auto end = MidiBufferHelpers::findEventAfter (start, data.end(), startSample + numSamples - 1);
109 
110  data.removeRange ((int) (start - data.begin()), (int) (end - data.begin()));
111 }
112 
113 void MidiBuffer::addEvent (const MidiMessage& m, int sampleNumber)
114 {
115  addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber);
116 }
117 
118 void MidiBuffer::addEvent (const void* newData, int maxBytes, int sampleNumber)
119 {
120  auto numBytes = MidiBufferHelpers::findActualEventLength (static_cast<const uint8*> (newData), maxBytes);
121 
122  if (numBytes > 0)
123  {
124  auto newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16);
125  auto offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin());
126 
127  data.insertMultiple (offset, 0, (int) newItemSize);
128 
129  auto* d = data.begin() + offset;
130  writeUnaligned<int32> (d, sampleNumber);
131  d += sizeof (int32);
132  writeUnaligned<uint16> (d, static_cast<uint16> (numBytes));
133  d += sizeof (uint16);
134  memcpy (d, newData, (size_t) numBytes);
135  }
136 }
137 
138 void MidiBuffer::addEvents (const MidiBuffer& otherBuffer,
139  int startSample, int numSamples, int sampleDeltaToAdd)
140 {
141  Iterator i (otherBuffer);
142  i.setNextSamplePosition (startSample);
143 
144  const uint8* eventData;
145  int eventSize, position;
146 
147  while (i.getNextEvent (eventData, eventSize, position)
148  && (position < startSample + numSamples || numSamples < 0))
149  {
150  addEvent (eventData, eventSize, position + sampleDeltaToAdd);
151  }
152 }
153 
154 int MidiBuffer::getNumEvents() const noexcept
155 {
156  int n = 0;
157  auto end = data.end();
158 
159  for (auto d = data.begin(); d < end; ++n)
160  d += MidiBufferHelpers::getEventTotalSize (d);
161 
162  return n;
163 }
164 
165 int MidiBuffer::getFirstEventTime() const noexcept
166 {
167  return data.size() > 0 ? MidiBufferHelpers::getEventTime (data.begin()) : 0;
168 }
169 
170 int MidiBuffer::getLastEventTime() const noexcept
171 {
172  if (data.size() == 0)
173  return 0;
174 
175  auto endData = data.end();
176 
177  for (auto d = data.begin();;)
178  {
179  auto nextOne = d + MidiBufferHelpers::getEventTotalSize (d);
180 
181  if (nextOne >= endData)
182  return MidiBufferHelpers::getEventTime (d);
183 
184  d = nextOne;
185  }
186 }
187 
188 //==============================================================================
190  : buffer (b), data (b.data.begin())
191 {
192 }
193 
195 
196 void MidiBuffer::Iterator::setNextSamplePosition (int samplePosition) noexcept
197 {
198  data = buffer.data.begin();
199  auto dataEnd = buffer.data.end();
200 
201  while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition)
202  data += MidiBufferHelpers::getEventTotalSize (data);
203 }
204 
205 bool MidiBuffer::Iterator::getNextEvent (const uint8*& midiData, int& numBytes, int& samplePosition) noexcept
206 {
207  if (data >= buffer.data.end())
208  return false;
209 
210  samplePosition = MidiBufferHelpers::getEventTime (data);
211  auto itemSize = MidiBufferHelpers::getEventDataSize (data);
212  numBytes = itemSize;
213  midiData = data + sizeof (int32) + sizeof (uint16);
214  data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize;
215 
216  return true;
217 }
218 
219 bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept
220 {
221  if (data >= buffer.data.end())
222  return false;
223 
224  samplePosition = MidiBufferHelpers::getEventTime (data);
225  auto itemSize = MidiBufferHelpers::getEventDataSize (data);
226  result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition);
227  data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize;
228 
229  return true;
230 }
231 
232 } // namespace juce
ElementType * data() noexcept
Returns a pointer to the first element in the array.
Definition: juce_Array.h:364
void ensureStorageAllocated(int minNumElements)
Increases the array's internal storage to hold a minimum number of elements.
Definition: juce_Array.h:1066
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
ElementType * end() noexcept
Returns a pointer to the element which follows the last element in the array.
Definition: juce_Array.h:348
void removeRange(int startIndex, int numberToRemove)
Removes a range of elements from the array.
Definition: juce_Array.h:920
ElementType * begin() noexcept
Returns a pointer to the first element in the array.
Definition: juce_Array.h:332
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:484
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.
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...
const uint8 * getRawData() const noexcept
Returns a pointer to the raw midi data.
int getRawDataSize() const noexcept
Returns the number of bytes of data in the message.