Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::midi::MidiBuffer Class Reference

Collection of timestamped MIDI events within a single audio buffer period. More...

#include <buffer.hpp>

Classes

class  SysexPayload
struct  SysexEvent

Public Member Functions

 MidiBuffer ()=default
 MidiBuffer (const MidiBuffer &other)
MidiBuffer & operator= (const MidiBuffer &other)
 MidiBuffer (MidiBuffer &&other) noexcept
MidiBuffer & operator= (MidiBuffer &&other) noexcept
bool add (const MidiEvent &event)
 Append a MIDI event to the buffer.
bool add (MidiEvent &&event)
 Append a MIDI event to the buffer.
void clear ()
 Remove all events.
bool empty () const
std::size_t size () const
void reserve_events (std::size_t capacity)
void reserve_sysex (std::size_t capacity)
void reserve (std::size_t event_capacity, std::size_t sysex_capacity=0, std::size_t sysex_copy_payload_capacity=0)
 Preallocate storage for realtime callers that append during process().
void set_realtime_capacity_limit (bool enabled=true)
 When enabled, add() and move-based add_sysex() drop once reserved capacity is full instead of growing vectors.
bool realtime_capacity_limited () const
std::size_t event_capacity () const
std::size_t sysex_capacity () const
std::size_t sysex_copy_payload_capacity () const
std::uint32_t dropped_event_count () const
std::uint32_t dropped_sysex_count () const
void sort ()
 Sort events by sample_offset for sample-accurate processing.
auto begin ()
auto end ()
auto begin () const
auto end () const
const MidiEvent & operator[] (std::size_t index) const
void attach_ump (class UmpBuffer *ump)
 Attach a UmpBuffer sidecar carrying MIDI 2.0 packets that can't be represented as choc::midi::ShortMessage (UMP type-4 channel voice, type-3/5 data, type-0 utility, etc.).
const class UmpBuffer * ump () const
 Attached UmpBuffer or nullptr.
class UmpBuffer * ump ()
bool add_sysex (std::vector< uint8_t > data, int32_t sample_offset=0, double ts=0.0)
bool add_sysex (SysexEvent &&event)
bool add_sysex_copy (const uint8_t *data, std::size_t size, int32_t sample_offset=0, double ts=0.0)
void reserve_sysex_copy_payloads (std::size_t payload_count, std::size_t payload_capacity)
void clear_sysex ()
std::size_t sysex_size () const
const std::vector< SysexEvent > & sysex () const
std::vector< SysexEvent > & sysex ()

Detailed Description

Collection of timestamped MIDI events within a single audio buffer period.

Events are appended via add() and should be sorted by sample_offset (call sort()) before iterating in the audio callback. Supports range-based for loops.

Realtime contract: the buffer is safe for audio-thread appends only after the owner has called reserve() with the worst-case block capacities and set_realtime_capacity_limit(true). In that mode add() and SysEx append helpers drop and count overflow instead of growing storage. Without that preparation, vector growth remains possible and callers must treat mutation as control/offline-thread work.

buf.add(MidiEvent::note_on(0, 60, 100));
buf.sort();
for (const auto& ev : buf) { /* process */ }
void sort()
Sort events by sample_offset for sample-accurate processing.
Definition buffer.hpp:177
bool add(const MidiEvent &event)
Append a MIDI event to the buffer.
Definition buffer.hpp:98
static MidiEvent note_on(uint8_t channel, uint8_t note, uint8_t velocity)
Create a Note On event.
Definition message.hpp:46

Constructor & Destructor Documentation

◆ MidiBuffer() [1/3]

pulp::midi::MidiBuffer::MidiBuffer ( )
default

◆ MidiBuffer() [2/3]

pulp::midi::MidiBuffer::MidiBuffer ( const MidiBuffer & other)
inline

◆ MidiBuffer() [3/3]

pulp::midi::MidiBuffer::MidiBuffer ( MidiBuffer && other)
inlinenoexcept

Member Function Documentation

◆ add() [1/2]

bool pulp::midi::MidiBuffer::add ( const MidiEvent & event)
inline

Append a MIDI event to the buffer.

◆ add() [2/2]

bool pulp::midi::MidiBuffer::add ( MidiEvent && event)
inline

Append a MIDI event to the buffer.

◆ add_sysex() [1/2]

bool pulp::midi::MidiBuffer::add_sysex ( std::vector< uint8_t > data,
int32_t sample_offset = 0,
double ts = 0.0 )
inline

◆ add_sysex() [2/2]

bool pulp::midi::MidiBuffer::add_sysex ( SysexEvent && event)
inline

◆ add_sysex_copy()

bool pulp::midi::MidiBuffer::add_sysex_copy ( const uint8_t * data,
std::size_t size,
int32_t sample_offset = 0,
double ts = 0.0 )
inline

◆ attach_ump()

void pulp::midi::MidiBuffer::attach_ump ( class UmpBuffer * ump)
inline

Attach a UmpBuffer sidecar carrying MIDI 2.0 packets that can't be represented as choc::midi::ShortMessage (UMP type-4 channel voice, type-3/5 data, type-0 utility, etc.).

Format adapters set this before process(); plugins opting in to PluginDescriptor::supports_ump read it via ump(). Ownership stays with the caller; the buffer must outlive the process() block.

◆ begin() [1/2]

auto pulp::midi::MidiBuffer::begin ( )
inline

◆ begin() [2/2]

auto pulp::midi::MidiBuffer::begin ( ) const
inline

◆ clear()

void pulp::midi::MidiBuffer::clear ( )
inline

Remove all events.

◆ clear_sysex()

void pulp::midi::MidiBuffer::clear_sysex ( )
inline

◆ dropped_event_count()

std::uint32_t pulp::midi::MidiBuffer::dropped_event_count ( ) const
inline

◆ dropped_sysex_count()

std::uint32_t pulp::midi::MidiBuffer::dropped_sysex_count ( ) const
inline

◆ empty()

bool pulp::midi::MidiBuffer::empty ( ) const
inline

◆ end() [1/2]

auto pulp::midi::MidiBuffer::end ( )
inline

◆ end() [2/2]

auto pulp::midi::MidiBuffer::end ( ) const
inline

◆ event_capacity()

std::size_t pulp::midi::MidiBuffer::event_capacity ( ) const
inline

◆ operator=() [1/2]

MidiBuffer & pulp::midi::MidiBuffer::operator= ( const MidiBuffer & other)
inline

◆ operator=() [2/2]

MidiBuffer & pulp::midi::MidiBuffer::operator= ( MidiBuffer && other)
inlinenoexcept

◆ operator[]()

const MidiEvent & pulp::midi::MidiBuffer::operator[] ( std::size_t index) const
inline

◆ realtime_capacity_limited()

bool pulp::midi::MidiBuffer::realtime_capacity_limited ( ) const
inline

◆ reserve()

void pulp::midi::MidiBuffer::reserve ( std::size_t event_capacity,
std::size_t sysex_capacity = 0,
std::size_t sysex_copy_payload_capacity = 0 )
inline

Preallocate storage for realtime callers that append during process().

◆ reserve_events()

void pulp::midi::MidiBuffer::reserve_events ( std::size_t capacity)
inline

◆ reserve_sysex()

void pulp::midi::MidiBuffer::reserve_sysex ( std::size_t capacity)
inline

◆ reserve_sysex_copy_payloads()

void pulp::midi::MidiBuffer::reserve_sysex_copy_payloads ( std::size_t payload_count,
std::size_t payload_capacity )
inline

◆ set_realtime_capacity_limit()

void pulp::midi::MidiBuffer::set_realtime_capacity_limit ( bool enabled = true)
inline

When enabled, add() and move-based add_sysex() drop once reserved capacity is full instead of growing vectors.

add_sysex_copy() uses reserve_sysex_copy_payloads() storage in this mode and drops when no reserved payload slot can hold the event. Intended for adapter-owned buffers.

◆ size()

std::size_t pulp::midi::MidiBuffer::size ( ) const
inline

◆ sort()

void pulp::midi::MidiBuffer::sort ( )
inline

Sort events by sample_offset for sample-accurate processing.

Call this before iterating in the audio callback. Realtime callers must not append while sorting and should rely on adapters to have bounded the event count before process().

The sort is insertion-stable: events at the same sample offset keep the relative order in which they were add()'ed (a controller appended before a note-on at the same offset stays before it). This preserves the same-offset musical semantics every consumer had, while remaining deterministic run-to-run. Implemented as an index sort with a pre-reserved scratch (an std::sort over indices keyed by (sample_offset, original_index) — a valid strict-weak total order — then a one-pass reorder through the scratch), NOT std::stable_sort (which may allocate a temporary buffer). The comparator never touches variable-length sysex payload bytes. Allocation-free when the scratch was reserved (reserve()/reserve_events() size it to the event capacity); only an unreserved, growing buffer can allocate here.

◆ sysex() [1/2]

std::vector< SysexEvent > & pulp::midi::MidiBuffer::sysex ( )
inline

◆ sysex() [2/2]

const std::vector< SysexEvent > & pulp::midi::MidiBuffer::sysex ( ) const
inline

◆ sysex_capacity()

std::size_t pulp::midi::MidiBuffer::sysex_capacity ( ) const
inline

◆ sysex_copy_payload_capacity()

std::size_t pulp::midi::MidiBuffer::sysex_copy_payload_capacity ( ) const
inline

◆ sysex_size()

std::size_t pulp::midi::MidiBuffer::sysex_size ( ) const
inline

◆ ump() [1/2]

class UmpBuffer * pulp::midi::MidiBuffer::ump ( )
inline

◆ ump() [2/2]

const class UmpBuffer * pulp::midi::MidiBuffer::ump ( ) const
inline

Attached UmpBuffer or nullptr.

A null return means "no UMP events this block", not "UMP unsupported" — that's declared at descriptor time via PluginDescriptor::supports_ump.


The documentation for this class was generated from the following file:
  • /home/runner/work/pulp/pulp/core/midi/include/pulp/midi/buffer.hpp