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.

juce_MidiBuffer.cpp 7.4KB

11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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 int32*> (d);
  22. }
  23. inline uint16 getEventDataSize (const void* const d) noexcept
  24. {
  25. return *reinterpret_cast<const uint16*> (static_cast<const char*> (d) + sizeof (int32));
  26. }
  27. inline uint16 getEventTotalSize (const void* const d) noexcept
  28. {
  29. return getEventDataSize (d) + sizeof (int32) + 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. static uint8* findEventAfter (uint8* d, uint8* endData, const int samplePosition) noexcept
  56. {
  57. while (d < endData && getEventTime (d) <= samplePosition)
  58. d += getEventTotalSize (d);
  59. return d;
  60. }
  61. }
  62. //==============================================================================
  63. MidiBuffer::MidiBuffer() noexcept {}
  64. MidiBuffer::~MidiBuffer() {}
  65. MidiBuffer::MidiBuffer (const MidiBuffer& other) noexcept : data (other.data) {}
  66. MidiBuffer& MidiBuffer::operator= (const MidiBuffer& other) noexcept
  67. {
  68. data = other.data;
  69. return *this;
  70. }
  71. MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept
  72. {
  73. addEvent (message, 0);
  74. }
  75. void MidiBuffer::swapWith (MidiBuffer& other) noexcept { data.swapWith (other.data); }
  76. void MidiBuffer::clear() noexcept { data.clearQuick(); }
  77. void MidiBuffer::ensureSize (size_t minimumNumBytes) { data.ensureStorageAllocated ((int) minimumNumBytes); }
  78. bool MidiBuffer::isEmpty() const noexcept { return data.size() == 0; }
  79. void MidiBuffer::clear (const int startSample, const int numSamples)
  80. {
  81. uint8* const start = MidiBufferHelpers::findEventAfter (data.begin(), data.end(), startSample - 1);
  82. uint8* const end = MidiBufferHelpers::findEventAfter (start, data.end(), startSample + numSamples - 1);
  83. data.removeRange ((int) (start - data.begin()), (int) (end - data.begin()));
  84. }
  85. void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber)
  86. {
  87. addEvent (m.getRawData(), m.getRawDataSize(), sampleNumber);
  88. }
  89. void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const int sampleNumber)
  90. {
  91. const int numBytes = MidiBufferHelpers::findActualEventLength (static_cast<const uint8*> (newData), maxBytes);
  92. if (numBytes > 0)
  93. {
  94. const size_t newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16);
  95. const int offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin());
  96. data.insertMultiple (offset, 0, (int) newItemSize);
  97. uint8* const d = data.begin() + offset;
  98. *reinterpret_cast<int32*> (d) = sampleNumber;
  99. *reinterpret_cast<uint16*> (d + 4) = (uint16) numBytes;
  100. memcpy (d + 6, newData, (size_t) numBytes);
  101. }
  102. }
  103. void MidiBuffer::addEvents (const MidiBuffer& otherBuffer,
  104. const int startSample,
  105. const int numSamples,
  106. const int sampleDeltaToAdd)
  107. {
  108. Iterator i (otherBuffer);
  109. i.setNextSamplePosition (startSample);
  110. const uint8* eventData;
  111. int eventSize, position;
  112. while (i.getNextEvent (eventData, eventSize, position)
  113. && (position < startSample + numSamples || numSamples < 0))
  114. {
  115. addEvent (eventData, eventSize, position + sampleDeltaToAdd);
  116. }
  117. }
  118. int MidiBuffer::getNumEvents() const noexcept
  119. {
  120. int n = 0;
  121. const uint8* const end = data.end();
  122. for (const uint8* d = data.begin(); d < end; ++n)
  123. d += MidiBufferHelpers::getEventTotalSize (d);
  124. return n;
  125. }
  126. int MidiBuffer::getFirstEventTime() const noexcept
  127. {
  128. return data.size() > 0 ? MidiBufferHelpers::getEventTime (data.begin()) : 0;
  129. }
  130. int MidiBuffer::getLastEventTime() const noexcept
  131. {
  132. if (data.size() == 0)
  133. return 0;
  134. const uint8* const endData = data.end();
  135. for (const uint8* d = data.begin();;)
  136. {
  137. const uint8* const nextOne = d + MidiBufferHelpers::getEventTotalSize (d);
  138. if (nextOne >= endData)
  139. return MidiBufferHelpers::getEventTime (d);
  140. d = nextOne;
  141. }
  142. }
  143. //==============================================================================
  144. MidiBuffer::Iterator::Iterator (const MidiBuffer& b) noexcept
  145. : buffer (b), data (b.data.begin())
  146. {
  147. }
  148. MidiBuffer::Iterator::~Iterator() noexcept
  149. {
  150. }
  151. void MidiBuffer::Iterator::setNextSamplePosition (const int samplePosition) noexcept
  152. {
  153. data = buffer.data.begin();
  154. const uint8* const dataEnd = buffer.data.end();
  155. while (data < dataEnd && MidiBufferHelpers::getEventTime (data) < samplePosition)
  156. data += MidiBufferHelpers::getEventTotalSize (data);
  157. }
  158. bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, int& samplePosition) noexcept
  159. {
  160. if (data >= buffer.data.end())
  161. return false;
  162. samplePosition = MidiBufferHelpers::getEventTime (data);
  163. const int itemSize = MidiBufferHelpers::getEventDataSize (data);
  164. numBytes = itemSize;
  165. midiData = data + sizeof (int32) + sizeof (uint16);
  166. data += sizeof (int32) + sizeof (uint16) + itemSize;
  167. return true;
  168. }
  169. bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePosition) noexcept
  170. {
  171. if (data >= buffer.data.end())
  172. return false;
  173. samplePosition = MidiBufferHelpers::getEventTime (data);
  174. const int itemSize = MidiBufferHelpers::getEventDataSize (data);
  175. result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition);
  176. data += sizeof (int32) + sizeof (uint16) + itemSize;
  177. return true;
  178. }