|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2022 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- The code included in this file is provided under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license. Permission
- To use, copy, modify, and/or distribute this software for any purpose with or
- without fee is hereby granted provided that the above copyright notice and
- this permission notice appear in all copies.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- //==============================================================================
- /**
- A view of MIDI message data stored in a contiguous buffer.
-
- Instances of this class do *not* own the midi data bytes that they point to.
- Instead, they expect the midi data to live in a separate buffer that outlives
- the MidiMessageMetadata instance.
-
- @tags{Audio}
- */
- struct MidiMessageMetadata final
- {
- MidiMessageMetadata() noexcept = default;
-
- MidiMessageMetadata (const uint8* dataIn, int numBytesIn, int positionIn) noexcept
- : data (dataIn), numBytes (numBytesIn), samplePosition (positionIn)
- {
- }
-
- /** Constructs a new MidiMessage instance from the data that this object is viewing.
-
- Note that MidiMessage owns its data storage, whereas MidiMessageMetadata does not.
- */
- MidiMessage getMessage() const { return MidiMessage (data, numBytes, samplePosition); }
-
- /** Pointer to the first byte of a MIDI message. */
- const uint8* data = nullptr;
-
- /** The number of bytes in the MIDI message. */
- int numBytes = 0;
-
- /** The MIDI message's timestamp. */
- int samplePosition = 0;
- };
-
- //==============================================================================
- /**
- An iterator to move over contiguous raw MIDI data, which Allows iterating
- over a MidiBuffer using C++11 range-for syntax.
-
- In the following example, we log all three-byte messages in a midi buffer.
- @code
- void processBlock (AudioBuffer<float>&, MidiBuffer& midiBuffer) override
- {
- for (const MidiMessageMetadata metadata : midiBuffer)
- if (metadata.numBytes == 3)
- Logger::writeToLog (metadata.getMessage().getDescription());
- }
- @endcode
-
- @tags{Audio}
- */
- class JUCE_API MidiBufferIterator
- {
- using Ptr = const uint8*;
-
- public:
- MidiBufferIterator() = default;
-
- /** Constructs an iterator pointing at the message starting at the byte `dataIn`.
- `dataIn` must point to the start of a valid MIDI message. If it does not,
- calling other member functions on the iterator will result in undefined
- behaviour.
- */
- explicit MidiBufferIterator (const uint8* dataIn) noexcept
- : data (dataIn)
- {
- }
-
- using difference_type = std::iterator_traits<Ptr>::difference_type;
- using value_type = MidiMessageMetadata;
- using reference = MidiMessageMetadata;
- using pointer = void;
- using iterator_category = std::input_iterator_tag;
-
- /** Make this iterator point to the next message in the buffer. */
- MidiBufferIterator& operator++() noexcept;
-
- /** Create a copy of this object, make this iterator point to the next message in
- the buffer, then return the copy.
- */
- MidiBufferIterator operator++ (int) noexcept;
-
- /** Return true if this iterator points to the same message as another
- iterator instance, otherwise return false.
- */
- bool operator== (const MidiBufferIterator& other) const noexcept { return data == other.data; }
-
- /** Return false if this iterator points to the same message as another
- iterator instance, otherwise returns true.
- */
- bool operator!= (const MidiBufferIterator& other) const noexcept { return ! operator== (other); }
-
- /** Return an instance of MidiMessageMetadata which describes the message to which
- the iterator is currently pointing.
- */
- reference operator*() const noexcept;
-
- private:
- Ptr data = nullptr;
- };
-
- //==============================================================================
- /**
- Holds a sequence of time-stamped midi events.
-
- Analogous to the AudioBuffer, this holds a set of midi events with
- integer time-stamps. The buffer is kept sorted in order of the time-stamps.
-
- If you're working with a sequence of midi events that may need to be manipulated
- or read/written to a midi file, then MidiMessageSequence is probably a more
- appropriate container. MidiBuffer is designed for lower-level streams of raw
- midi data.
-
- @see MidiMessage
-
- @tags{Audio}
- */
- class JUCE_API MidiBuffer
- {
- public:
- //==============================================================================
- /** Creates an empty MidiBuffer. */
- MidiBuffer() noexcept = default;
-
- /** Creates a MidiBuffer containing a single midi message. */
- explicit MidiBuffer (const MidiMessage& message) noexcept;
-
- //==============================================================================
- /** Removes all events from the buffer. */
- void clear() noexcept;
-
- /** Removes all events between two times from the buffer.
-
- All events for which (start <= event position < start + numSamples) will
- be removed.
- */
- void clear (int start, int numSamples);
-
- /** Returns true if the buffer is empty.
- To actually retrieve the events, use a MidiBufferIterator object
- */
- bool isEmpty() const noexcept;
-
- /** Counts the number of events in the buffer.
-
- This is actually quite a slow operation, as it has to iterate through all
- the events, so you might prefer to call isEmpty() if that's all you need
- to know.
- */
- int getNumEvents() const noexcept;
-
- /** Adds an event to the buffer.
-
- The sample number will be used to determine the position of the event in
- the buffer, which is always kept sorted. The MidiMessage's timestamp is
- ignored.
-
- If an event is added whose sample position is the same as one or more events
- already in the buffer, the new event will be placed after the existing ones.
-
- To retrieve events, use a MidiBufferIterator object.
-
- Returns true on success, or false on failure.
- */
- bool addEvent (const MidiMessage& midiMessage, int sampleNumber);
-
- /** Adds an event to the buffer from raw midi data.
-
- The sample number will be used to determine the position of the event in
- the buffer, which is always kept sorted.
-
- If an event is added whose sample position is the same as one or more events
- already in the buffer, the new event will be placed after the existing ones.
-
- The event data will be inspected to calculate the number of bytes in length that
- the midi event really takes up, so maxBytesOfMidiData may be longer than the data
- that actually gets stored. E.g. if you pass in a note-on and a length of 4 bytes,
- it'll actually only store 3 bytes. If the midi data is invalid, it might not
- add an event at all.
-
- To retrieve events, use a MidiBufferIterator object.
-
- Returns true on success, or false on failure.
- */
- bool addEvent (const void* rawMidiData,
- int maxBytesOfMidiData,
- int sampleNumber);
-
- /** Adds some events from another buffer to this one.
-
- @param otherBuffer the buffer containing the events you want to add
- @param startSample the lowest sample number in the source buffer for which
- events should be added. Any source events whose timestamp is
- less than this will be ignored
- @param numSamples the valid range of samples from the source buffer for which
- events should be added - i.e. events in the source buffer whose
- timestamp is greater than or equal to (startSample + numSamples)
- will be ignored. If this value is less than 0, all events after
- startSample will be taken.
- @param sampleDeltaToAdd a value which will be added to the source timestamps of the events
- that are added to this buffer
- */
- void addEvents (const MidiBuffer& otherBuffer,
- int startSample,
- int numSamples,
- int sampleDeltaToAdd);
-
- /** Returns the sample number of the first event in the buffer.
- If the buffer's empty, this will just return 0.
- */
- int getFirstEventTime() const noexcept;
-
- /** Returns the sample number of the last event in the buffer.
- If the buffer's empty, this will just return 0.
- */
- int getLastEventTime() const noexcept;
-
- //==============================================================================
- /** Exchanges the contents of this buffer with another one.
-
- This is a quick operation, because no memory allocating or copying is done, it
- just swaps the internal state of the two buffers.
- */
- void swapWith (MidiBuffer&) noexcept;
-
- /** Preallocates some memory for the buffer to use.
- This helps to avoid needing to reallocate space when the buffer has messages
- added to it.
- */
- void ensureSize (size_t minimumNumBytes);
-
- /** Get a read-only iterator pointing to the beginning of this buffer. */
- MidiBufferIterator begin() const noexcept { return cbegin(); }
-
- /** Get a read-only iterator pointing one past the end of this buffer. */
- MidiBufferIterator end() const noexcept { return cend(); }
-
- /** Get a read-only iterator pointing to the beginning of this buffer. */
- MidiBufferIterator cbegin() const noexcept { return MidiBufferIterator (data.begin()); }
-
- /** Get a read-only iterator pointing one past the end of this buffer. */
- MidiBufferIterator cend() const noexcept { return MidiBufferIterator (data.end()); }
-
- /** Get an iterator pointing to the first event with a timestamp greater-than or
- equal-to `samplePosition`.
- */
- MidiBufferIterator findNextSamplePosition (int samplePosition) const noexcept;
-
- //==============================================================================
- #ifndef DOXYGEN
- /** This class is now deprecated in favour of MidiBufferIterator.
-
- Used to iterate through the events in a MidiBuffer.
-
- Note that altering the buffer while an iterator is using it will produce
- undefined behaviour.
-
- @see MidiBuffer
- */
- class [[deprecated]] JUCE_API Iterator
- {
- public:
- //==============================================================================
- /** Creates an Iterator for this MidiBuffer. */
- Iterator (const MidiBuffer& b) noexcept;
-
- //==============================================================================
- /** Repositions the iterator so that the next event retrieved will be the first
- one whose sample position is at greater than or equal to the given position.
- */
- void setNextSamplePosition (int samplePosition) noexcept;
-
- /** Retrieves a copy of the next event from the buffer.
-
- @param result on return, this will be the message. The MidiMessage's timestamp
- is set to the same value as samplePosition.
- @param samplePosition on return, this will be the position of the event, as a
- sample index in the buffer
- @returns true if an event was found, or false if the iterator has reached
- the end of the buffer
- */
- bool getNextEvent (MidiMessage& result,
- int& samplePosition) noexcept;
-
- /** Retrieves the next event from the buffer.
-
- @param midiData on return, this pointer will be set to a block of data containing
- the midi message. Note that to make it fast, this is a pointer
- directly into the MidiBuffer's internal data, so is only valid
- temporarily until the MidiBuffer is altered.
- @param numBytesOfMidiData on return, this is the number of bytes of data used by the
- midi message
- @param samplePosition on return, this will be the position of the event, as a
- sample index in the buffer
- @returns true if an event was found, or false if the iterator has reached
- the end of the buffer
- */
- bool getNextEvent (const uint8* &midiData,
- int& numBytesOfMidiData,
- int& samplePosition) noexcept;
-
- private:
- //==============================================================================
- const MidiBuffer& buffer;
- MidiBufferIterator iterator;
- };
- #endif
-
- /** The raw data holding this buffer.
- Obviously access to this data is provided at your own risk. Its internal format could
- change in future, so don't write code that relies on it!
- */
- Array<uint8> data;
-
- private:
- JUCE_LEAK_DETECTOR (MidiBuffer)
- };
-
- } // namespace juce
|