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.

293 lines
7.6KB

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