The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
8.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. MidiBuffer::MidiBuffer() noexcept
  21. : bytesUsed (0)
  22. {
  23. }
  24. MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept
  25. : bytesUsed (0)
  26. {
  27. addEvent (message, 0);
  28. }
  29. MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept
  30. : data (other.data),
  31. bytesUsed (other.bytesUsed)
  32. {
  33. }
  34. MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) noexcept
  35. {
  36. bytesUsed = other.bytesUsed;
  37. data = other.data;
  38. return *this;
  39. }
  40. void MidiBuffer::swapWith (MidiBuffer& other) noexcept
  41. {
  42. data.swapWith (other.data);
  43. std::swap (bytesUsed, other.bytesUsed);
  44. }
  45. MidiBuffer::~MidiBuffer()
  46. {
  47. }
  48. inline uint8* MidiBuffer::getData() const noexcept
  49. {
  50. return static_cast <uint8*> (data.getData());
  51. }
  52. inline int MidiBuffer::getEventTime (const void* const d) noexcept
  53. {
  54. return *static_cast <const int*> (d);
  55. }
  56. inline uint16 MidiBuffer::getEventDataSize (const void* const d) noexcept
  57. {
  58. return *reinterpret_cast <const uint16*> (static_cast <const char*> (d) + sizeof (int));
  59. }
  60. inline uint16 MidiBuffer::getEventTotalSize (const void* const d) noexcept
  61. {
  62. return getEventDataSize (d) + sizeof (int) + sizeof (uint16);
  63. }
  64. void MidiBuffer::clear() noexcept
  65. {
  66. bytesUsed = 0;
  67. }
  68. void MidiBuffer::clear (const int startSample, const int numSamples)
  69. {
  70. uint8* const start = findEventAfter (getData(), startSample - 1);
  71. uint8* const end = findEventAfter (start, startSample + numSamples - 1);
  72. if (end > start)
  73. {
  74. const int bytesToMove = bytesUsed - (int) (end - getData());
  75. if (bytesToMove > 0)
  76. memmove (start, end, bytesToMove);
  77. bytesUsed -= (int) (end - start);
  78. }
  79. }
  80. void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber)
  81. {
  82. addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber);
  83. }
  84. namespace MidiBufferHelpers
  85. {
  86. int findActualEventLength (const uint8* const data, const int maxBytes) noexcept
  87. {
  88. unsigned int byte = (unsigned int) *data;
  89. int size = 0;
  90. if (byte == 0xf0 || byte == 0xf7)
  91. {
  92. const uint8* d = data + 1;
  93. while (d < data + maxBytes)
  94. if (*d++ == 0xf7)
  95. break;
  96. size = (int) (d - data);
  97. }
  98. else if (byte == 0xff)
  99. {
  100. int n;
  101. const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n);
  102. size = jmin (maxBytes, n + 2 + bytesLeft);
  103. }
  104. else if (byte >= 0x80)
  105. {
  106. size = jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte));
  107. }
  108. return size;
  109. }
  110. }
  111. void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const int sampleNumber)
  112. {
  113. const int numBytes = MidiBufferHelpers::findActualEventLength (static_cast <const uint8*> (newData), maxBytes);
  114. if (numBytes > 0)
  115. {
  116. int spaceNeeded = bytesUsed + numBytes + sizeof (int) + sizeof (uint16);
  117. data.ensureSize ((spaceNeeded + spaceNeeded / 2 + 8) & ~7);
  118. uint8* d = findEventAfter (getData(), sampleNumber);
  119. const int bytesToMove = bytesUsed - (int) (d - getData());
  120. if (bytesToMove > 0)
  121. memmove (d + numBytes + sizeof (int) + sizeof (uint16), d, bytesToMove);
  122. *reinterpret_cast <int*> (d) = sampleNumber;
  123. d += sizeof (int);
  124. *reinterpret_cast <uint16*> (d) = (uint16) numBytes;
  125. d += sizeof (uint16);
  126. memcpy (d, newData, numBytes);
  127. bytesUsed += numBytes + sizeof (int) + sizeof (uint16);
  128. }
  129. }
  130. void MidiBuffer::addEvents (const MidiBuffer& otherBuffer,
  131. const int startSample,
  132. const int numSamples,
  133. const int sampleDeltaToAdd)
  134. {
  135. Iterator i (otherBuffer);
  136. i.setNextSamplePosition (startSample);
  137. const uint8* eventData;
  138. int eventSize, position;
  139. while (i.getNextEvent (eventData, eventSize, position)
  140. && (position < startSample + numSamples || numSamples < 0))
  141. {
  142. addEvent (eventData, eventSize, position + sampleDeltaToAdd);
  143. }
  144. }
  145. void MidiBuffer::ensureSize (size_t minimumNumBytes)
  146. {
  147. data.ensureSize (minimumNumBytes);
  148. }
  149. bool MidiBuffer::isEmpty() const noexcept
  150. {
  151. return bytesUsed == 0;
  152. }
  153. int MidiBuffer::getNumEvents() const noexcept
  154. {
  155. int n = 0;
  156. const uint8* d = getData();
  157. const uint8* const end = d + bytesUsed;
  158. while (d < end)
  159. {
  160. d += getEventTotalSize (d);
  161. ++n;
  162. }
  163. return n;
  164. }
  165. int MidiBuffer::getFirstEventTime() const noexcept
  166. {
  167. return bytesUsed > 0 ? getEventTime (data.getData()) : 0;
  168. }
  169. int MidiBuffer::getLastEventTime() const noexcept
  170. {
  171. if (bytesUsed == 0)
  172. return 0;
  173. const uint8* d = getData();
  174. const uint8* const endData = d + bytesUsed;
  175. for (;;)
  176. {
  177. const uint8* const nextOne = d + getEventTotalSize (d);
  178. if (nextOne >= endData)
  179. return getEventTime (d);
  180. d = nextOne;
  181. }
  182. }
  183. uint8* MidiBuffer::findEventAfter (uint8* d, const int samplePosition) const noexcept
  184. {
  185. const uint8* const endData = getData() + bytesUsed;
  186. while (d < endData && getEventTime (d) <= samplePosition)
  187. d += getEventTotalSize (d);
  188. return d;
  189. }
  190. //==============================================================================
  191. MidiBuffer::Iterator::Iterator (const MidiBuffer& buffer_) noexcept
  192. : buffer (buffer_),
  193. data (buffer_.getData())
  194. {
  195. }
  196. MidiBuffer::Iterator::~Iterator() noexcept
  197. {
  198. }
  199. //==============================================================================
  200. void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept
  201. {
  202. data = buffer.getData();
  203. const uint8* dataEnd = data + buffer.bytesUsed;
  204. while (data < dataEnd && getEventTime (data) < samplePosition)
  205. data += getEventTotalSize (data);
  206. }
  207. bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, int& samplePosition) noexcept
  208. {
  209. if (data >= buffer.getData() + buffer.bytesUsed)
  210. return false;
  211. samplePosition = getEventTime (data);
  212. numBytes = getEventDataSize (data);
  213. data += sizeof (int) + sizeof (uint16);
  214. midiData = data;
  215. data += numBytes;
  216. return true;
  217. }
  218. bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept
  219. {
  220. if (data >= buffer.getData() + buffer.bytesUsed)
  221. return false;
  222. samplePosition = getEventTime (data);
  223. const int numBytes = getEventDataSize (data);
  224. data += sizeof (int) + sizeof (uint16);
  225. result = MidiMessage (data, numBytes, samplePosition);
  226. data += numBytes;
  227. return true;
  228. }
  229. END_JUCE_NAMESPACE