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.

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