Audio plugin host https://kx.studio/carla
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.

288 lines
8.0KB

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