32 enum class Kind : uint8_t {
73 events_.push_back(std::move(e));
81 if (!can_append(
events.size())) {
82 record_drops(
events.size());
85 events_.insert(events_.end(),
events.begin(),
events.end());
93 bool empty()
const {
return events_.empty(); }
94 std::size_t
size()
const {
return events_.size(); }
95 std::size_t
capacity()
const {
return events_.capacity(); }
103 limit_to_reserved_capacity_ = enabled;
110 const std::size_t count = events_.size();
111 if (count < 2)
return;
112 sort_index_.resize(count);
113 for (std::size_t i = 0; i < count; ++i) sort_index_[i] = i;
114 const auto& source = events_;
115 std::sort(sort_index_.begin(), sort_index_.end(),
116 [&source](std::size_t a, std::size_t b) {
117 if (source[a].sample_offset != source[b].sample_offset) {
118 return source[a].sample_offset < source[b].sample_offset;
122 sort_reorder_.resize(count);
123 for (std::size_t i = 0; i < count; ++i) {
124 sort_reorder_[i] = std::move(events_[sort_index_[i]]);
126 events_.swap(sort_reorder_);
129 auto begin() {
return events_.begin(); }
130 auto end() {
return events_.end(); }
131 auto begin()
const {
return events_.begin(); }
132 auto end()
const {
return events_.end(); }
137 bool can_append(std::size_t count = 1)
const {
138 return !limit_to_reserved_capacity_
139 || count <= events_.capacity() - events_.size();
144 void record_drops(std::size_t count) {
145 const auto max = std::numeric_limits<std::uint32_t>::max();
146 const auto available =
static_cast<std::uint64_t
>(max - dropped_events_);
147 const auto increment = std::min<std::uint64_t>(count, available);
148 dropped_events_ +=
static_cast<std::uint32_t
>(increment);
151 static constexpr std::size_t kInitialCapacity = 128;
152 std::vector<MpeExpressionEvent> events_;
153 std::vector<std::size_t> sort_index_;
154 std::vector<MpeExpressionEvent> sort_reorder_;
155 bool limit_to_reserved_capacity_ =
false;
156 std::uint32_t dropped_events_ = 0;
165 int32_t& current_sample_offset,
166 bool* expression_event_dropped =
nullptr) {
169 expression_event_dropped](
171 std::array<MpeExpressionEvent, 2>
events{};
172 std::size_t count = 0;
174 events[count++] = {current_sample_offset, K::NoteOff, *note_off};
177 events[count++] = {current_sample_offset, K::NoteOn, *note_on};
180 std::span<const MpeExpressionEvent>{
events.data(), count});
184 if (!appended && note_on && expression_event_dropped)
185 *expression_event_dropped =
true;
190 if (!out.
add({current_sample_offset, K::PitchBend, s}) &&
191 expression_event_dropped) {
192 *expression_event_dropped =
true;
195 tracker.
on_pressure = [&out, ¤t_sample_offset,
197 if (!out.
add({current_sample_offset, K::Pressure, s}) &&
198 expression_event_dropped) {
199 *expression_event_dropped =
true;
202 tracker.
on_timbre = [&out, ¤t_sample_offset,
204 if (!out.
add({current_sample_offset, K::Timbre, s}) &&
205 expression_event_dropped) {
206 *expression_event_dropped =
true;
A time-ordered list of per-note expression events for one block.
Definition mpe_buffer.hpp:51
bool add(MpeExpressionEvent &&e)
Definition mpe_buffer.hpp:68
bool add(const MpeExpressionEvent &e)
Definition mpe_buffer.hpp:60
bool empty() const
Definition mpe_buffer.hpp:93
const MpeExpressionEvent & operator[](std::size_t i) const
Definition mpe_buffer.hpp:134
auto end() const
Definition mpe_buffer.hpp:132
auto end()
Definition mpe_buffer.hpp:130
auto begin() const
Definition mpe_buffer.hpp:131
auto begin()
Definition mpe_buffer.hpp:129
std::size_t size() const
Definition mpe_buffer.hpp:94
std::size_t capacity() const
Definition mpe_buffer.hpp:95
void clear()
Definition mpe_buffer.hpp:89
void set_realtime_capacity_limit(bool enabled=true)
Definition mpe_buffer.hpp:102
MpeBuffer(bool reserve_storage=true)
Definition mpe_buffer.hpp:55
void sort()
Definition mpe_buffer.hpp:106
bool add_batch(std::span< const MpeExpressionEvent > events)
Append a group atomically.
Definition mpe_buffer.hpp:80
void reserve(std::size_t capacity)
Definition mpe_buffer.hpp:97
std::uint32_t dropped_event_count() const
Definition mpe_buffer.hpp:96
Tracks MPE voice state across channels.
Definition mpe_voice_tracker.hpp:67
std::function< void(const MpeNoteState &)> on_pressure
Definition mpe_voice_tracker.hpp:238
std::function< void(const MpeNoteState &)> on_pitch_bend
Definition mpe_voice_tracker.hpp:237
std::function< void(const MpeNoteState &)> on_timbre
Definition mpe_voice_tracker.hpp:239
std::function< bool(const MpeNoteState *note_off, const MpeNoteState *note_on)> on_note_lifecycle
Transactional note-lifecycle sink.
Definition mpe_voice_tracker.hpp:233
MPE (MIDI Polyphonic Expression) voice tracker.
Definition child_process_manager.hpp:18
Definition custom_node_events.hpp:26
void bind_tracker_to_buffer(MpeVoiceTracker &tracker, MpeBuffer &out, int32_t ¤t_sample_offset, bool *expression_event_dropped=nullptr)
Convenience: install tracker callbacks that forward events to out with the given sample offset.
Definition mpe_buffer.hpp:163
A single per-note expression event.
Definition mpe_buffer.hpp:31
Kind
Definition mpe_buffer.hpp:32
@ NoteOn
Definition mpe_buffer.hpp:33
@ NoteOff
Definition mpe_buffer.hpp:34
@ Pressure
Definition mpe_buffer.hpp:36
@ PitchBend
Definition mpe_buffer.hpp:35
@ Timbre
Definition mpe_buffer.hpp:37
Kind kind
Definition mpe_buffer.hpp:41
int32_t sample_offset
Sample position within the current block.
Definition mpe_buffer.hpp:40
MpeNoteState state
Snapshot at event time.
Definition mpe_buffer.hpp:42
Per-note state maintained by MpeVoiceTracker.
Definition mpe_voice_tracker.hpp:44