108template<std::size_t CommandCapacity = 128,
109 std::size_t EventCapacity = 256,
110 std::size_t MidiOutputCapacity = 256>
112 static_assert(CommandCapacity > 0,
"CommandCapacity must be > 0");
113 static_assert(EventCapacity > 0,
"EventCapacity must be > 0");
114 static_assert(MidiOutputCapacity > 0,
"MidiOutputCapacity must be > 0");
115 static_assert(std::is_nothrow_copy_constructible_v<GraphCommand> &&
116 std::is_nothrow_copy_assignable_v<GraphCommand>,
117 "GraphCommand must stay RT-copyable");
118 static_assert(std::is_nothrow_copy_constructible_v<GraphEvent> &&
119 std::is_nothrow_copy_assignable_v<GraphEvent>,
120 "GraphEvent must stay RT-copyable");
121 static_assert(std::is_nothrow_copy_constructible_v<GraphMidiOutputEvent> &&
122 std::is_nothrow_copy_assignable_v<GraphMidiOutputEvent>,
123 "GraphMidiOutputEvent must stay RT-copyable");
127 if (!commands_.try_push(command)) {
128 dropped_commands_.fetch_add(1, std::memory_order_relaxed);
131 commands_enqueued_.fetch_add(1, std::memory_order_relaxed);
136 std::uint32_t block_frames)
noexcept {
137 std::array<GraphTimedCommand, CommandCapacity> staged{};
138 std::uint32_t staged_count = 0;
139 std::uint32_t order = 0;
140 while (
auto popped = commands_.try_pop()) {
141 if (staged_count >= staged.size()) {
142 dropped_commands_.fetch_add(1, std::memory_order_relaxed);
146 auto command = *popped;
147 staged[staged_count++] = {
149 command_offset(command.timing, block_frames),
154 std::span<GraphTimedCommand> sorted(staged.data(), staged_count);
155 sort_timed_commands(sorted);
157 const auto count =
static_cast<std::uint32_t
>(
158 std::min<std::size_t>(out.size(), staged_count));
159 for (std::uint32_t i = 0; i < count; ++i) {
162 if (staged_count > count) {
163 dropped_commands_.fetch_add(staged_count - count, std::memory_order_relaxed);
165 commands_drained_.fetch_add(count, std::memory_order_relaxed);
170 if (!events_.try_push(event)) {
171 dropped_events_.fetch_add(1, std::memory_order_relaxed);
174 events_enqueued_.fetch_add(1, std::memory_order_relaxed);
179 auto popped = events_.try_pop();
180 if (!popped.has_value())
return false;
186 if (!midi_outputs_.try_push(event)) {
187 dropped_midi_outputs_.fetch_add(1, std::memory_order_relaxed);
190 midi_outputs_enqueued_.fetch_add(1, std::memory_order_relaxed);
195 auto popped = midi_outputs_.try_pop();
196 if (!popped.has_value())
return false;
205 while (commands_.try_pop().has_value()) {}
206 while (events_.try_pop().has_value()) {}
207 while (midi_outputs_.try_pop().has_value()) {}
208 commands_enqueued_.store(0, std::memory_order_relaxed);
209 commands_drained_.store(0, std::memory_order_relaxed);
210 events_enqueued_.store(0, std::memory_order_relaxed);
211 midi_outputs_enqueued_.store(0, std::memory_order_relaxed);
212 dropped_commands_.store(0, std::memory_order_relaxed);
213 dropped_events_.store(0, std::memory_order_relaxed);
214 dropped_midi_outputs_.store(0, std::memory_order_relaxed);
219 commands_enqueued_.load(std::memory_order_relaxed),
220 commands_drained_.load(std::memory_order_relaxed),
221 events_enqueued_.load(std::memory_order_relaxed),
222 midi_outputs_enqueued_.load(std::memory_order_relaxed),
223 dropped_commands_.load(std::memory_order_relaxed),
224 dropped_events_.load(std::memory_order_relaxed),
225 dropped_midi_outputs_.load(std::memory_order_relaxed),
235 std::uint32_t block_frames)
noexcept {
239 return std::min(timing.frame_offset, block_frames - 1);
242 static void sort_timed_commands(std::span<GraphTimedCommand> commands)
noexcept {
243 for (std::size_t i = 1; i < commands.size(); ++i) {
244 auto current = commands[i];
246 while (j > 0 && comes_before(current, commands[j - 1])) {
247 commands[j] = commands[j - 1];
250 commands[
j] = current;
254 static bool comes_before(
const GraphTimedCommand& a,
255 const GraphTimedCommand& b)
noexcept {
256 if (
a.block_offset !=
b.block_offset)
return a.block_offset <
b.block_offset;
257 return a.order <
b.order;
260 runtime::SpscQueue<GraphCommand, CommandCapacity> commands_;
261 runtime::SpscQueue<GraphEvent, EventCapacity> events_;
262 runtime::SpscQueue<GraphMidiOutputEvent, MidiOutputCapacity> midi_outputs_;
264 std::atomic<std::uint64_t> commands_enqueued_{0};
265 std::atomic<std::uint64_t> commands_drained_{0};
266 std::atomic<std::uint64_t> events_enqueued_{0};
267 std::atomic<std::uint64_t> midi_outputs_enqueued_{0};
268 std::atomic<std::uint64_t> dropped_commands_{0};
269 std::atomic<std::uint64_t> dropped_events_{0};
270 std::atomic<std::uint64_t> dropped_midi_outputs_{0};
Fixed-capacity graph command/event queues for realtime graph runtimes.
Definition graph_runtime_queue.hpp:111
static constexpr std::size_t midi_output_capacity() noexcept
Definition graph_runtime_queue.hpp:231
static constexpr std::size_t command_capacity() noexcept
Definition graph_runtime_queue.hpp:229
std::uint32_t drain_commands_for_block(std::span< GraphTimedCommand > out, std::uint32_t block_frames) noexcept
Definition graph_runtime_queue.hpp:135
void reset_offline() noexcept
Offline-only reset.
Definition graph_runtime_queue.hpp:204
bool enqueue_command(const GraphCommand &command) noexcept
Definition graph_runtime_queue.hpp:126
bool push_event_from_realtime(const GraphEvent &event) noexcept
Definition graph_runtime_queue.hpp:169
bool pop_event(GraphEvent &event) noexcept
Definition graph_runtime_queue.hpp:178
GraphRuntimeQueueStats stats() const noexcept
Definition graph_runtime_queue.hpp:217
bool pop_midi_output(GraphMidiOutputEvent &event) noexcept
Definition graph_runtime_queue.hpp:194
bool push_midi_output_from_realtime(const GraphMidiOutputEvent &event) noexcept
Definition graph_runtime_queue.hpp:185
static constexpr std::size_t event_capacity() noexcept
Definition graph_runtime_queue.hpp:230
Definition graph_runtime_buffer_assignment.hpp:8
GraphEventType
Definition graph_runtime_queue.hpp:56
@ NodeReset
Definition graph_runtime_queue.hpp:62
@ CommandRejected
Definition graph_runtime_queue.hpp:58
@ CommandDropped
Definition graph_runtime_queue.hpp:59
@ SnapshotActivated
Definition graph_runtime_queue.hpp:60
@ Diagnostic
Definition graph_runtime_queue.hpp:65
@ TailChanged
Definition graph_runtime_queue.hpp:64
@ CommandAccepted
Definition graph_runtime_queue.hpp:57
@ LatencyChanged
Definition graph_runtime_queue.hpp:63
@ SnapshotDeactivated
Definition graph_runtime_queue.hpp:61
std::uint32_t NodeId
Definition graph_types.hpp:7
GraphCommandType
Definition graph_runtime_queue.hpp:17
@ ActivateSnapshot
Definition graph_runtime_queue.hpp:24
@ ResetNode
Definition graph_runtime_queue.hpp:21
@ DeactivateSnapshot
Definition graph_runtime_queue.hpp:25
@ SetNodeGain
Definition graph_runtime_queue.hpp:18
@ TransportJump
Definition graph_runtime_queue.hpp:23
@ InjectMidi
Definition graph_runtime_queue.hpp:22
@ SetNodeParameter
Definition graph_runtime_queue.hpp:19
@ SetNodeBypass
Definition graph_runtime_queue.hpp:20
GraphCommandTimingType
Definition graph_runtime_queue.hpp:28
@ Immediate
Definition graph_runtime_queue.hpp:29
@ BlockOffset
Definition graph_runtime_queue.hpp:30
std::uint32_t PortIndex
Definition graph_types.hpp:8
@ a
Definition pitch.hpp:29
@ b
Definition pitch.hpp:31
@ j
Definition input_events.hpp:40
Definition graph_runtime_queue.hpp:33
GraphCommandTimingType type
Definition graph_runtime_queue.hpp:34
std::uint32_t frame_offset
Definition graph_runtime_queue.hpp:35
Definition graph_runtime_queue.hpp:38
float value
Definition graph_runtime_queue.hpp:45
GraphCommandType type
Definition graph_runtime_queue.hpp:40
std::uint32_t target_id
Definition graph_runtime_queue.hpp:43
GraphCommandTiming timing
Definition graph_runtime_queue.hpp:44
std::uint64_t sequence_id
Definition graph_runtime_queue.hpp:39
PortIndex port
Definition graph_runtime_queue.hpp:42
bool bool_value
Definition graph_runtime_queue.hpp:46
midi::MidiEvent midi
Definition graph_runtime_queue.hpp:47
NodeId node_id
Definition graph_runtime_queue.hpp:41
Definition graph_runtime_queue.hpp:68
NodeId node_id
Definition graph_runtime_queue.hpp:71
std::uint64_t sequence_id
Definition graph_runtime_queue.hpp:69
float value
Definition graph_runtime_queue.hpp:74
bool bool_value
Definition graph_runtime_queue.hpp:75
GraphEventType type
Definition graph_runtime_queue.hpp:70
std::uint32_t block_offset
Definition graph_runtime_queue.hpp:73
std::uint32_t target_id
Definition graph_runtime_queue.hpp:72
Definition graph_runtime_queue.hpp:78
NodeId node_id
Definition graph_runtime_queue.hpp:80
std::uint32_t block_offset
Definition graph_runtime_queue.hpp:82
PortIndex port
Definition graph_runtime_queue.hpp:81
midi::MidiEvent event
Definition graph_runtime_queue.hpp:83
std::uint64_t sequence_id
Definition graph_runtime_queue.hpp:79
Definition graph_runtime_queue.hpp:86
std::uint64_t dropped_events
Definition graph_runtime_queue.hpp:92
std::uint64_t events_enqueued
Definition graph_runtime_queue.hpp:89
std::uint64_t commands_enqueued
Definition graph_runtime_queue.hpp:87
std::uint64_t midi_outputs_enqueued
Definition graph_runtime_queue.hpp:90
std::uint64_t commands_drained
Definition graph_runtime_queue.hpp:88
std::uint64_t dropped_midi_outputs
Definition graph_runtime_queue.hpp:93
std::uint64_t dropped_commands
Definition graph_runtime_queue.hpp:91
Definition graph_runtime_queue.hpp:50
GraphCommand command
Definition graph_runtime_queue.hpp:51
std::uint32_t order
Definition graph_runtime_queue.hpp:53
std::uint32_t block_offset
Definition graph_runtime_queue.hpp:52
Timestamped MIDI event combining a choc::midi::ShortMessage with timing info.
Definition message.hpp:32