OpenShot Audio Library | OpenShotAudio  0.3.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 
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
MidiBuffer & operator=(const MidiBuffer &) noexcept
void setNextSamplePosition(int samplePosition) noexcept
void swapWith(MidiBuffer &) noexcept
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
int getFirstEventTime() const noexcept
int getRawDataSize() const noexcept
Iterator(const MidiBuffer &) noexcept
bool isEmpty() const noexcept
int getNumEvents() const noexcept
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
static int readVariableLengthVal(const uint8 *data, int &numBytesUsed) noexcept
const uint8 * getRawData() const noexcept
Array< uint8 > data
int getLastEventTime() const noexcept
void addEvent(const MidiMessage &midiMessage, int sampleNumber)
void addEvents(const MidiBuffer &otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd)
void clear() noexcept
void ensureSize(size_t minimumNumBytes)