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.

299 lines
8.3KB

  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. namespace MidiBufferHelpers
  20. {
  21. inline int getEventTime (const void* const d) noexcept
  22. {
  23. return *static_cast <const int*> (d);
  24. }
  25. inline uint16 getEventDataSize (const void* const d) noexcept
  26. {
  27. return *reinterpret_cast <const uint16*> (static_cast <const char*> (d) + sizeof (int));
  28. }
  29. inline uint16 getEventTotalSize (const void* const d) noexcept
  30. {
  31. return getEventDataSize (d) + sizeof (int) + sizeof (uint16);
  32. }
  33. }
  34. //==============================================================================
  35. MidiBuffer::MidiBuffer() noexcept
  36. : bytesUsed (0)
  37. {
  38. }
  39. MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept
  40. : bytesUsed (0)
  41. {
  42. addEvent (message, 0);
  43. }
  44. MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept
  45. : data (other.data),
  46. bytesUsed (other.bytesUsed)
  47. {
  48. }
  49. MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) noexcept
  50. {
  51. bytesUsed = other.bytesUsed;
  52. data = other.data;
  53. return *this;
  54. }
  55. void MidiBuffer::swapWith (MidiBuffer& other) noexcept
  56. {
  57. data.swapWith (other.data);
  58. std::swap (bytesUsed, other.bytesUsed);
  59. }
  60. MidiBuffer::~MidiBuffer()
  61. {
  62. }
  63. inline uint8* MidiBuffer::getData() const noexcept
  64. {
  65. return static_cast <uint8*> (data.getData());
  66. }
  67. void MidiBuffer::clear() noexcept
  68. {
  69. bytesUsed = 0;
  70. }
  71. void MidiBuffer::clear (const int startSample, const int numSamples)
  72. {
  73. uint8* const start = findEventAfter (getData(), startSample - 1);
  74. uint8* const end = findEventAfter (start, startSample + numSamples - 1);
  75. if (end > start)
  76. {
  77. const int bytesToMove = bytesUsed - (int) (end - getData());
  78. if (bytesToMove > 0)
  79. memmove (start, end, bytesToMove);
  80. bytesUsed -= (int) (end - start);
  81. }
  82. }
  83. void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber)
  84. {
  85. addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber);
  86. }
  87. namespace MidiBufferHelpers
  88. {
  89. int findActualEventLength (const uint8* const data, const int maxBytes) noexcept
  90. {
  91. unsigned int byte = (unsigned int) *data;
  92. int size = 0;
  93. if (byte == 0xf0 || byte == 0xf7)
  94. {
  95. const uint8* d = data + 1;
  96. while (d < data + maxBytes)
  97. if (*d++ == 0xf7)
  98. break;
  99. size = (int) (d - data);
  100. }
  101. else if (byte == 0xff)
  102. {
  103. int n;
  104. const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n);
  105. size = jmin (maxBytes, n + 2 + bytesLeft);
  106. }
  107. else if (byte >= 0x80)
  108. {
  109. size = jmin (maxBytes, MidiMessage::getMessageLengthFromFirstByte ((uint8) byte));
  110. }
  111. return size;
  112. }
  113. }
  114. void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const int sampleNumber)
  115. {
  116. const int numBytes = MidiBufferHelpers::findActualEventLength (static_cast <const uint8*> (newData), maxBytes);
  117. if (numBytes > 0)
  118. {
  119. int spaceNeeded = bytesUsed + numBytes + sizeof (int) + sizeof (uint16);
  120. data.ensureSize ((spaceNeeded + spaceNeeded / 2 + 8) & ~7);
  121. uint8* d = findEventAfter (getData(), sampleNumber);
  122. const int bytesToMove = bytesUsed - (int) (d - getData());
  123. if (bytesToMove > 0)
  124. memmove (d + numBytes + sizeof (int) + sizeof (uint16), d, bytesToMove);
  125. *reinterpret_cast <int*> (d) = sampleNumber;
  126. d += sizeof (int);
  127. *reinterpret_cast <uint16*> (d) = (uint16) numBytes;
  128. d += sizeof (uint16);
  129. memcpy (d, newData, numBytes);
  130. bytesUsed += numBytes + sizeof (int) + sizeof (uint16);
  131. }
  132. }
  133. void MidiBuffer::addEvents (const MidiBuffer& otherBuffer,
  134. const int startSample,
  135. const int numSamples,
  136. const int sampleDeltaToAdd)
  137. {
  138. Iterator i (otherBuffer);
  139. i.setNextSamplePosition (startSample);
  140. const uint8* eventData;
  141. int eventSize, position;
  142. while (i.getNextEvent (eventData, eventSize, position)
  143. && (position < startSample + numSamples || numSamples < 0))
  144. {
  145. addEvent (eventData, eventSize, position + sampleDeltaToAdd);
  146. }
  147. }
  148. void MidiBuffer::ensureSize (size_t minimumNumBytes)
  149. {
  150. data.ensureSize (minimumNumBytes);
  151. }
  152. bool MidiBuffer::isEmpty() const noexcept
  153. {
  154. return bytesUsed == 0;
  155. }
  156. int MidiBuffer::getNumEvents() const noexcept
  157. {
  158. int n = 0;
  159. const uint8* d = getData();
  160. const uint8* const end = d + bytesUsed;
  161. while (d < end)
  162. {
  163. d += MidiBufferHelpers::getEventTotalSize (d);
  164. ++n;
  165. }
  166. return n;
  167. }
  168. int MidiBuffer::getFirstEventTime() const noexcept
  169. {
  170. return bytesUsed > 0 ? MidiBufferHelpers::getEventTime (data.getData()) : 0;
  171. }
  172. int MidiBuffer::getLastEventTime() const noexcept
  173. {
  174. if (bytesUsed == 0)
  175. return 0;
  176. const uint8* d = getData();
  177. const uint8* const endData = d + bytesUsed;
  178. for (;;)
  179. {
  180. const uint8* const nextOne = d + MidiBufferHelpers::getEventTotalSize (d);
  181. if (nextOne >= endData)
  182. return MidiBufferHelpers::getEventTime (d);
  183. d = nextOne;
  184. }
  185. }
  186. uint8* MidiBuffer::findEventAfter (uint8* d, const int samplePosition) const noexcept
  187. {
  188. const uint8* const endData = getData() + bytesUsed;
  189. while (d < endData && MidiBufferHelpers::getEventTime (d) <= samplePosition)
  190. d += MidiBufferHelpers::getEventTotalSize (d);
  191. return d;
  192. }
  193. //==============================================================================
  194. MidiBuffer::Iterator::Iterator (const MidiBuffer& buffer_) noexcept
  195. : buffer (buffer_),
  196. data (buffer_.getData())
  197. {
  198. }
  199. MidiBuffer::Iterator::~Iterator() noexcept
  200. {
  201. }
  202. //==============================================================================
  203. void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept
  204. {
  205. data = buffer.getData();
  206. const uint8* dataEnd = data + buffer.bytesUsed;
  207. while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition)
  208. data += MidiBufferHelpers::getEventTotalSize (data);
  209. }
  210. bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, int& samplePosition) noexcept
  211. {
  212. if (data >= buffer.getData() + buffer.bytesUsed)
  213. return false;
  214. samplePosition = MidiBufferHelpers::getEventTime (data);
  215. numBytes = MidiBufferHelpers::getEventDataSize (data);
  216. data += sizeof (int) + sizeof (uint16);
  217. midiData = data;
  218. data += numBytes;
  219. return true;
  220. }
  221. bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept
  222. {
  223. if (data >= buffer.getData() + buffer.bytesUsed)
  224. return false;
  225. samplePosition = MidiBufferHelpers::getEventTime (data);
  226. const int numBytes = MidiBufferHelpers::getEventDataSize (data);
  227. data += sizeof (int) + sizeof (uint16);
  228. result = MidiMessage (data, numBytes, samplePosition);
  229. data += numBytes;
  230. return true;
  231. }
  232. END_JUCE_NAMESPACE