35 static_assert(std::atomic<std::uint64_t>::is_always_lock_free &&
36 std::atomic<bool>::is_always_lock_free);
114 void* user_data)
noexcept;
120 void* user_data)
noexcept;
167 std::span<const GraphRuntimeNodeBinding>
bindings,
175 const
graph::GraphRuntimePlan&
plan() const noexcept {
return plan_; }
177 std::span<const GraphRuntimeNodeBinding>
bindings() const noexcept {
180 std::uint32_t
node_count() const noexcept {
return plan_.node_count(); }
194 enum class Mode : std::uint8_t {
205 if (node_index + 1 >= input_port_base_.size())
207 return std::span<const InputPortSource>(input_ports_)
208 .subspan(input_port_base_[node_index],
209 input_port_base_[node_index + 1] - input_port_base_[node_index]);
213 return sole_audio_output_;
218 return sole_audio_output_ports_;
223 std::uint64_t
id() const noexcept {
228 bool compute_valid() const noexcept;
229 void resolve_input_ports();
231 graph::GraphRuntimePlan plan_;
234 graph::GraphRuntimeBufferAssignment assignment_;
235 bool parallel_safe_ = false;
239 bool sole_audio_output_ = false;
240 std::uint32_t sole_audio_output_ports_ = 0;
241 std::
vector<InputPortSource> input_ports_;
243 std::uint64_t id_ = 0;
282 bool ok() const noexcept {
319 std::span<const
std::uint32_t> connection_delay_samples);
323 std::uint32_t
max_frames() const noexcept {
return max_frames_; }
327 if (index >= slot_count_)
return nullptr;
328 return storage_.data() +
static_cast<std::size_t
>(index) * max_frames_;
330 const float*
slot_data(std::uint32_t index)
const noexcept {
331 if (index >= slot_count_)
return nullptr;
332 return storage_.data() +
static_cast<std::size_t
>(index) * max_frames_;
349 if (index >= ring_.size())
return {};
350 RingSlot& r = ring_[index];
351 if (!r.state)
return {};
352 return DelayRing{r.state->storage.data(),
353 static_cast<std::uint32_t
>(r.state->storage.size()),
355 &r.state->write_pos};
364 std::uint32_t source_index)
const noexcept;
367 std::uint32_t source_index)
noexcept;
388 return bound_snapshot_id_ != 0 && bound_snapshot_id_ == snapshot.id();
407 return bound_nodes_[index];
423 std::uint32_t frames)
noexcept;
427 if (slot_count_ < snapshot.buffer_slot_count() || frames > max_frames_) {
430 const auto& assignment = snapshot.buffer_assignment();
431 if (assignment.has_delay &&
432 ring_.size() != snapshot.plan().connections.size()) {
441 struct DelayRingState {
442 std::vector<float> storage;
446 std::uint32_t delay = 0;
447 std::shared_ptr<DelayRingState>
state;
450 void unbind() noexcept;
452 std::vector<
float> storage_;
453 std::uint32_t slot_count_ = 0;
454 std::uint32_t max_frames_ = 0;
455 std::vector<RingSlot> ring_;
457 struct HostInputAlias {
458 const float** view =
nullptr;
459 const float* slot =
nullptr;
460 std::uint32_t channel = 0;
463 std::vector<BoundNode> bound_nodes_;
464 std::vector<const float*> bound_inputs_;
465 std::vector<float*> bound_outputs_;
466 std::uint64_t bound_snapshot_id_ = 0;
467 std::vector<HostInputAlias> host_input_aliases_;
468 std::uint32_t host_input_node_ = 0;
469 std::uint32_t host_input_channels_ = 0;
470 bool host_input_aliasable_ =
false;
498 bool reset(std::span<const std::size_t> event_capacities,
508 return node_index < node_count_ ? &slots_[node_index]->in_buffer :
nullptr;
511 return node_index < node_count_ ? &slots_[node_index]->out_buffer :
nullptr;
518 return node_index < node_count_ ? &slots_[node_index]->in_mpe :
nullptr;
521 return node_index < node_count_ ? &slots_[node_index]->out_mpe :
nullptr;
528 return node_index < node_count_ && slots_[node_index]->in_incomplete;
531 if (node_index < node_count_) slots_[node_index]->in_incomplete = v;
534 return node_index < node_count_ && slots_[node_index]->out_incomplete;
537 if (node_index < node_count_) slots_[node_index]->out_incomplete = v;
552 bool in_incomplete =
false;
553 bool out_incomplete =
false;
555 std::vector<std::unique_ptr<Slot>> slots_;
556 std::uint32_t node_count_ = 0;
611 std::span<const GraphRuntimeNodeBinding> bindings, std::uint32_t
max_frames);
616 std::uint32_t
max_frames() const noexcept {
return max_frames_; }
618 return prepared_stats_;
622 return node_index < node_count_ ? events_[node_index].get() :
nullptr;
626 float&
slew_last(std::uint32_t conn_index)
noexcept {
return slew_last_[conn_index]; }
628 return slew_primed_[conn_index] != 0;
631 slew_primed_[conn_index] = v ? 1 : 0;
638 return node_index < node_count_ ? node_dense_count_[node_index] : 0;
640 std::uint32_t
dense_param_id(std::uint32_t node_index, std::uint32_t i)
const noexcept {
641 return dense_params_[node_dense_first_[node_index] + i].param_id;
643 float*
dense_buffer(std::uint32_t node_index, std::uint32_t i)
noexcept {
644 return dense_storage_.data() + dense_params_[node_dense_first_[node_index] + i].offset;
655 std::span<float>
dense_lo(std::uint32_t node_index)
noexcept {
656 return dense_span(dense_lo_, node_index);
658 std::span<float>
dense_hi(std::uint32_t node_index)
noexcept {
659 return dense_span(dense_hi_, node_index);
662 return dense_span(dense_replace_, node_index);
664 std::span<std::uint8_t>
dense_add(std::uint32_t node_index)
noexcept {
665 return dense_span(dense_add_, node_index);
668 return dense_span(dense_touched_, node_index);
670 std::span<AudioRateModulationView>
dense_views(std::uint32_t node_index)
noexcept {
671 return dense_span(dense_views_, node_index);
674 return node_index < node_count_ ? node_dense_view_count_[node_index] : 0;
677 if (node_index < node_count_)
678 node_dense_view_count_[node_index] = count;
683 std::span<SparseAccum>
sparse_accum(std::uint32_t node_index)
noexcept {
684 if (node_index >= node_count_)
return {};
685 return {sparse_accum_storage_.data() + node_sparse_first_[node_index],
686 node_sparse_count_[node_index]};
690 std::uint32_t frames)
const noexcept {
692 frames <= max_frames_;
697 std::uint32_t param_id = 0;
698 std::uint32_t offset = 0;
703 std::span<T> dense_span(std::vector<T>& v, std::uint32_t node_index)
noexcept {
704 if (node_index >= node_count_)
return {};
705 return {v.data() + node_dense_first_[node_index], node_dense_count_[node_index]};
709 std::vector<std::unique_ptr<state::ParameterEventQueue>> events_;
710 std::vector<float> slew_last_;
711 std::vector<std::uint8_t> slew_primed_;
712 std::vector<DenseParam> dense_params_;
713 std::vector<std::uint32_t> node_dense_first_;
714 std::vector<std::uint32_t> node_dense_count_;
715 std::vector<float> dense_storage_;
719 std::vector<float> dense_lo_;
720 std::vector<float> dense_hi_;
721 std::vector<std::uint8_t> dense_replace_;
722 std::vector<std::uint8_t> dense_add_;
723 std::vector<std::uint32_t> dense_touched_;
724 std::vector<AudioRateModulationView> dense_views_;
727 std::vector<std::uint32_t> node_dense_view_count_;
729 std::vector<SparseAccum> sparse_accum_storage_;
730 std::vector<std::uint32_t> node_sparse_first_;
731 std::vector<std::uint32_t> node_sparse_count_;
732 std::uint32_t node_count_ = 0;
733 std::uint32_t connection_count_ = 0;
734 std::uint32_t max_frames_ = 0;
735 PreparedStats prepared_stats_{};
753 std::span<const graph::GraphTimedCommand> commands = {},
754 std::span<GraphRuntimeCommandDecision> command_results = {},
755 GraphRuntimeCommandHandler command_handler = {},
756 GraphRuntimeEventSink event_sink = {})
noexcept;
758 template<std::size_t CommandCapacity,
759 std::size_t EventCapacity,
760 std::size_t MidiOutputCapacity>
766 static_assert(CommandCapacity <= kMaxInlineCommandCapacity,
767 "Use a smaller queue capacity or an explicit scratch path");
768 if (!block.validate())
return fail_invalid_block();
769 if (!snapshot.
valid())
return fail_invalid_snapshot();
771 std::array<graph::GraphTimedCommand, CommandCapacity> commands{};
772 std::array<GraphRuntimeCommandDecision, CommandCapacity> command_results{};
774 GraphRuntimeEventSink sink{
776 [](
void* user_data,
const graph::GraphEvent& event)
noexcept {
777 auto* typed =
static_cast<
778 graph::GraphRuntimeQueues<CommandCapacity, EventCapacity, MidiOutputCapacity>*
>(
780 return typed->push_event_from_realtime(event);
783 return process(block, snapshot,
784 std::span<const graph::GraphTimedCommand>(
785 commands.data(), command_count),
786 std::span<GraphRuntimeCommandDecision>(
787 command_results.data(), command_count),
811 GraphRuntimeExecutorResult
815 std::span<const graph::GraphTimedCommand> commands = {},
816 std::span<GraphRuntimeCommandDecision> command_results = {},
817 GraphRuntimeCommandHandler command_handler = {},
818 GraphRuntimeEventSink event_sink = {},
819 std::span<const std::uint8_t> skip_mask = {},
820 GraphRuntimeAudioEdgeProbe* audio_probe =
nullptr)
noexcept;
852 std::span<const graph::GraphTimedCommand> commands = {},
853 std::span<GraphRuntimeCommandDecision> command_results = {},
854 GraphRuntimeCommandHandler command_handler = {},
855 GraphRuntimeEventSink event_sink = {})
noexcept;
871 parallel_min_work_units_.store(channel_samples, std::memory_order_relaxed);
874 return parallel_min_work_units_.load(std::memory_order_relaxed);
882 node_load_timing_.store(enabled, std::memory_order_relaxed);
885 return node_load_timing_.load(std::memory_order_relaxed);
898 std::span<const
graph::GraphTimedCommand> commands,
904 std::atomic<
std::uint64_t> blocks_processed_{0};
905 std::atomic<std::uint64_t> nodes_processed_{0};
906 std::atomic<std::uint64_t> commands_drained_{0};
907 std::atomic<std::uint64_t> commands_accepted_{0};
908 std::atomic<std::uint64_t> commands_rejected_{0};
909 std::atomic<std::uint64_t> events_dropped_{0};
910 std::atomic<std::uint64_t> invalid_blocks_{0};
911 std::atomic<std::uint64_t> invalid_snapshots_{0};
912 std::atomic<std::uint64_t> command_scratch_failures_{0};
913 std::atomic<std::uint64_t> node_failures_{0};
914 std::atomic<std::uint64_t> parallel_levels_dispatched_{0};
915 std::atomic<std::uint64_t> serial_levels_run_{0};
917 std::atomic<std::uint64_t> parallel_min_work_units_{0};
918 std::atomic<bool> node_load_timing_{
true};
Measures the CPU load of an audio processing callback.
Definition load_measurer.hpp:182
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
Definition graph_runtime_probe.hpp:20
Fixed-capacity graph command/event queues for realtime graph runtimes.
Definition graph_runtime_queue.hpp:111
std::uint32_t drain_commands_for_block(std::span< GraphTimedCommand > out, std::uint32_t block_frames) noexcept
Definition graph_runtime_queue.hpp:135
Collection of timestamped MIDI events within a single audio buffer period.
Definition buffer.hpp:31
A time-ordered list of per-note expression events for one block.
Definition mpe_buffer.hpp:51
A time-ordered list of UMP events for one audio block.
Definition ump_buffer.hpp:41
Definition parameter_event_queue.hpp:82
Sample-accurate MPE expression event stream.
Definition analyzer_provider.hpp:12
Definition graph_runtime_buffer_assignment.hpp:8
std::uint32_t NodeId
Definition graph_types.hpp:7
Definition custom_node_events.hpp:26
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
Definition graph_runtime_executor.hpp:70
bool routed
Definition graph_runtime_executor.hpp:81
const graph::GraphRuntimePlan * plan
Definition graph_runtime_executor.hpp:71
const graph::GraphRuntimeNodePlan * node
Definition graph_runtime_executor.hpp:72
std::span< const AudioRateModulationView > node_audio_rate_modulations
Definition graph_runtime_executor.hpp:106
state::ParameterEventQueue * node_param_events
Definition graph_runtime_executor.hpp:103
midi::MidiBuffer * node_midi_in
Definition graph_runtime_executor.hpp:93
midi::MidiBuffer * node_midi_out
Definition graph_runtime_executor.hpp:94
midi::MpeBuffer * node_mpe_in
Definition graph_runtime_executor.hpp:97
audio::BufferView< const float > node_inputs
Definition graph_runtime_executor.hpp:85
std::span< graph::SpectralFrameBatchView *const > spectral_outputs
Definition graph_runtime_executor.hpp:108
const graph::SpectralFrameBatchView * spectral_input
Definition graph_runtime_executor.hpp:107
std::uint32_t node_index
Definition graph_runtime_executor.hpp:73
std::span< const GraphRuntimeCommandDecision > command_results
Definition graph_runtime_executor.hpp:74
audio::BufferView< float > node_outputs
Definition graph_runtime_executor.hpp:86
Definition graph_runtime_queue.hpp:68
Definition graph_runtime_buffer_assignment.hpp:42
Definition graph_runtime_levelization.hpp:25
Definition graph_runtime_plan.hpp:113
Definition graph_runtime_plan.hpp:169
Definition graph_runtime_queue.hpp:50
Snapshot-owned payload and descriptors; callback borrows never own storage.
Definition spectral_frame.hpp:228
Sample-accurate MIDI 2.0 UMP packet stream.