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.

MidiBuffer.h 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. ==============================================================================
  3. This file is part of the Water library.
  4. Copyright (c) 2016 ROLI Ltd.
  5. Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
  6. Permission is granted to use this software under the terms of the ISC license
  7. http://www.isc.org/downloads/software-support-policy/isc-license/
  8. Permission to use, copy, modify, and/or distribute this software for any
  9. purpose with or without fee is hereby granted, provided that the above
  10. copyright notice and this permission notice appear in all copies.
  11. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  12. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  13. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  14. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  15. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  16. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  17. OF THIS SOFTWARE.
  18. ==============================================================================
  19. */
  20. #ifndef WATER_MIDIBUFFER_H_INCLUDED
  21. #define WATER_MIDIBUFFER_H_INCLUDED
  22. #include "../containers/Array.h"
  23. namespace water {
  24. //==============================================================================
  25. /**
  26. Holds a sequence of time-stamped midi events.
  27. Analogous to the AudioSampleBuffer, this holds a set of midi events with
  28. integer time-stamps. The buffer is kept sorted in order of the time-stamps.
  29. If you're working with a sequence of midi events that may need to be manipulated
  30. or read/written to a midi file, then MidiMessageSequence is probably a more
  31. appropriate container. MidiBuffer is designed for lower-level streams of raw
  32. midi data.
  33. @see MidiMessage
  34. */
  35. class MidiBuffer
  36. {
  37. public:
  38. //==============================================================================
  39. /** Creates an empty MidiBuffer. */
  40. MidiBuffer() noexcept;
  41. /** Creates a MidiBuffer containing a single midi message. */
  42. explicit MidiBuffer (const MidiMessage& message) noexcept;
  43. /** Creates a copy of another MidiBuffer. */
  44. MidiBuffer (const MidiBuffer&) noexcept;
  45. /** Makes a copy of another MidiBuffer. */
  46. MidiBuffer& operator= (const MidiBuffer&) noexcept;
  47. /** Destructor */
  48. ~MidiBuffer();
  49. //==============================================================================
  50. /** Removes all events from the buffer. */
  51. void clear() noexcept;
  52. /** Removes all events between two times from the buffer.
  53. All events for which (start <= event position < start + numSamples) will
  54. be removed.
  55. */
  56. void clear (int start, int numSamples);
  57. /** Returns true if the buffer is empty.
  58. To actually retrieve the events, use a MidiBuffer::Iterator object
  59. */
  60. bool isEmpty() const noexcept;
  61. /** Counts the number of events in the buffer.
  62. This is actually quite a slow operation, as it has to iterate through all
  63. the events, so you might prefer to call isEmpty() if that's all you need
  64. to know.
  65. */
  66. int getNumEvents() const noexcept;
  67. /** Adds an event to the buffer.
  68. The sample number will be used to determine the position of the event in
  69. the buffer, which is always kept sorted. The MidiMessage's timestamp is
  70. ignored.
  71. If an event is added whose sample position is the same as one or more events
  72. already in the buffer, the new event will be placed after the existing ones.
  73. To retrieve events, use a MidiBuffer::Iterator object
  74. */
  75. void addEvent (const MidiMessage& midiMessage, int sampleNumber);
  76. /** Adds an event to the buffer from raw midi data.
  77. The sample number will be used to determine the position of the event in
  78. the buffer, which is always kept sorted.
  79. If an event is added whose sample position is the same as one or more events
  80. already in the buffer, the new event will be placed after the existing ones.
  81. The event data will be inspected to calculate the number of bytes in length that
  82. the midi event really takes up, so maxBytesOfMidiData may be longer than the data
  83. that actually gets stored. E.g. if you pass in a note-on and a length of 4 bytes,
  84. it'll actually only store 3 bytes. If the midi data is invalid, it might not
  85. add an event at all.
  86. To retrieve events, use a MidiBuffer::Iterator object
  87. */
  88. void addEvent (const void* rawMidiData,
  89. int maxBytesOfMidiData,
  90. int sampleNumber);
  91. /** Adds some events from another buffer to this one.
  92. @param otherBuffer the buffer containing the events you want to add
  93. @param startSample the lowest sample number in the source buffer for which
  94. events should be added. Any source events whose timestamp is
  95. less than this will be ignored
  96. @param numSamples the valid range of samples from the source buffer for which
  97. events should be added - i.e. events in the source buffer whose
  98. timestamp is greater than or equal to (startSample + numSamples)
  99. will be ignored. If this value is less than 0, all events after
  100. startSample will be taken.
  101. @param sampleDeltaToAdd a value which will be added to the source timestamps of the events
  102. that are added to this buffer
  103. */
  104. void addEvents (const MidiBuffer& otherBuffer,
  105. int startSample,
  106. int numSamples,
  107. int sampleDeltaToAdd);
  108. /** Returns the sample number of the first event in the buffer.
  109. If the buffer's empty, this will just return 0.
  110. */
  111. int getFirstEventTime() const noexcept;
  112. /** Returns the sample number of the last event in the buffer.
  113. If the buffer's empty, this will just return 0.
  114. */
  115. int getLastEventTime() const noexcept;
  116. //==============================================================================
  117. /** Exchanges the contents of this buffer with another one.
  118. This is a quick operation, because no memory allocating or copying is done, it
  119. just swaps the internal state of the two buffers.
  120. */
  121. void swapWith (MidiBuffer&) noexcept;
  122. /** Preallocates some memory for the buffer to use.
  123. This helps to avoid needing to reallocate space when the buffer has messages
  124. added to it.
  125. */
  126. void ensureSize (size_t minimumNumBytes);
  127. //==============================================================================
  128. /**
  129. Used to iterate through the events in a MidiBuffer.
  130. Note that altering the buffer while an iterator is using it isn't a
  131. safe operation.
  132. @see MidiBuffer
  133. */
  134. class Iterator
  135. {
  136. public:
  137. //==============================================================================
  138. /** Creates an Iterator for this MidiBuffer. */
  139. Iterator (const MidiBuffer&) noexcept;
  140. /** Destructor. */
  141. ~Iterator() noexcept;
  142. //==============================================================================
  143. /** Repositions the iterator so that the next event retrieved will be the first
  144. one whose sample position is at greater than or equal to the given position.
  145. */
  146. void setNextSamplePosition (int samplePosition) noexcept;
  147. /** Retrieves a copy of the next event from the buffer.
  148. @param result on return, this will be the message. The MidiMessage's timestamp
  149. is set to the same value as samplePosition.
  150. @param samplePosition on return, this will be the position of the event, as a
  151. sample index in the buffer
  152. @returns true if an event was found, or false if the iterator has reached
  153. the end of the buffer
  154. */
  155. bool getNextEvent (MidiMessage& result,
  156. int& samplePosition) noexcept;
  157. /** Retrieves the next event from the buffer.
  158. @param midiData on return, this pointer will be set to a block of data containing
  159. the midi message. Note that to make it fast, this is a pointer
  160. directly into the MidiBuffer's internal data, so is only valid
  161. temporarily until the MidiBuffer is altered.
  162. @param numBytesOfMidiData on return, this is the number of bytes of data used by the
  163. midi message
  164. @param samplePosition on return, this will be the position of the event, as a
  165. sample index in the buffer
  166. @returns true if an event was found, or false if the iterator has reached
  167. the end of the buffer
  168. */
  169. bool getNextEvent (const uint8* &midiData,
  170. int& numBytesOfMidiData,
  171. int& samplePosition) noexcept;
  172. private:
  173. //==============================================================================
  174. const MidiBuffer& buffer;
  175. const uint8* data;
  176. CARLA_DECLARE_NON_COPYABLE (Iterator)
  177. };
  178. /** The raw data holding this buffer.
  179. Obviously access to this data is provided at your own risk. Its internal format could
  180. change in future, so don't write code that relies on it!
  181. */
  182. Array<uint8> data;
  183. };
  184. }
  185. #endif // WATER_MIDIBUFFER_H_INCLUDED