Sign in

    dowdiness/moondsp/graph does not have a README file

    GraphControllable

    pub trait GraphControllable {
    fn apply_control(Self, GraphControl) -> Result[Unit, GraphControlError]
    fn apply_controls(Self, Array[GraphControl]) -> Result[Unit, GraphControlError]
    }

    Capability trait for runtime control of compiled DSP graphs.

    Both mono and stereo compiled graphs, their hot-swap wrappers, and their topology controllers share the same control interface. This trait captures that shared interface so consumer code can be written generically over any controllable graph.

    The process method is intentionally excluded because mono and stereo graphs have different output arity (one buffer vs. two).

    Visibility: pub, not pub(open). The trait is intended for the six canonical wrapper types defined in this package; external types should compose with these wrappers rather than implement the trait directly. If a downstream use case for an external impl emerges, the contract to honour is: (a) apply_control returns the same GraphControlError variants the canonical wrappers do, (b) apply_controls is transactional — validate the whole batch first, then apply, leaving the graph unchanged on the first error.

    WHY 12 near-identical impl blocks below: MoonBit has no blanket impls or default trait methods. Each of the 6 wrapper types (CompiledDsp, CompiledStereoDsp, CompiledDspHotSwap, CompiledStereoDspHotSwap, CompiledDspTopologyController, CompiledStereoDspTopologyController) must declare both methods individually. The compiled wrappers delegate to graph/internal/runtime; staging wrappers delegate to their local state. This is irreducible boilerplate under the current type system.

    GraphDebuggable

    pub(open) trait GraphDebuggable {
    fn enable_debug_validation(Self) -> Unit
    fn disable_debug_validation(Self) -> Unit
    fn last_validation_errors(Self) -> Array[GraphValidationError]
    }

    NodeEditable

    pub(open) trait NodeEditable : NodeSpanning + NodeFoldable {
    fn can_insert_after(Self) -> Bool
    fn can_delete(Self) -> Bool
    }

    Capability trait for topology editing queries.

    NodeFoldable

    pub(open) trait NodeFoldable : NodeSpanning {
    fn is_foldable(Self) -> Bool
    fn fold_value(Self, Double, Double) -> Double
    }

    Capability trait for compile-time constant folding.

    NodeSpanning

    pub(open) trait NodeSpanning {
    fn signal_shape(Self) -> Int
    }

    Capability trait for signal shape queries.

    NodeStateful

    pub(open) trait NodeStateful : NodeSpanning {
    fn is_stateful(Self) -> Bool
    }

    Capability trait for stateful node identification.

    GraphTemplateDocError

    pub(all) suberror GraphTemplateDocError {
    LengthMismatch(Int, Int)
    DuplicateNodeId(String)
    MissingNodeId(String)
    RetiredNodeId(String)
    Topology(GraphTopologyEditError)
    } derive(
    Debug
    )

    CompiledDsp

    type CompiledDsp

    Executable buffer-based DSP graph compiled from DspNodes.

    Public facade wrapper; implementation lives in graph/internal/runtime.

    CompiledDsp::apply_control

    fn CompiledDsp::apply_control(self : CompiledDsp, control : GraphControl) -> Result[Unit, GraphControlError]

    Apply one runtime control message, returning a specific rejection reason.

    CompiledDsp::apply_controls

    fn CompiledDsp::apply_controls(self : CompiledDsp, controls : Array[GraphControl]) -> Result[Unit, GraphControlError]

    Apply a runtime control batch transactionally.

    CompiledDsp::can_set_param_bool

    fn CompiledDsp::can_set_param_bool(self : CompiledDsp, node_index : Int, slot : GraphParamSlot, value : Double) -> Bool

    Allocation-conscious parameter validation for prevalidated host paths.

    CompiledDsp::compile

    Compile a declarative mono graph into an executable buffer graph.

    Accepts a CompiledTemplate (the runtime exchange boundary per ADR-0010) and returns None if the template's topology is rejected (e.g., no reachable Output, invalid feedback cycle, missing node inputs). Produce the input via CompiledTemplate::analyze(nodes) or GraphBuilder::analyze.

    CompiledDsp::compile_result

    fn CompiledDsp::compile_result(compiled_template : CompiledTemplate, context :
    DspContext
    ) -> Result[CompiledDsp, GraphCompileError]

    Compile a declarative mono graph and return a typed rejection reason when compilation fails.

    CompiledDsp::gate_off

    fn CompiledDsp::gate_off(self : CompiledDsp, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger gate_off() on an ADSR node using its original authoring index.

    CompiledDsp::gate_off_bool

    fn CompiledDsp::gate_off_bool(self : CompiledDsp, node_index : Int) -> Bool

    Allocation-conscious gate-off primitive for prevalidated host paths.

    CompiledDsp::gate_on

    fn CompiledDsp::gate_on(self : CompiledDsp, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger gate_on() on an ADSR node using its original authoring index.

    CompiledDsp::gate_on_bool

    fn CompiledDsp::gate_on_bool(self : CompiledDsp, node_index : Int) -> Bool

    Allocation-conscious gate-on primitive for prevalidated host paths.

    CompiledDsp::has_feedback_edges

    fn CompiledDsp::has_feedback_edges(self : CompiledDsp) -> Bool

    True when the compiled graph contains feedback (back) edges that require per-sample processing with self-registers.

    CompiledDsp::is_voice_finished

    fn CompiledDsp::is_voice_finished(self : CompiledDsp) -> Bool

    Returns true when a voice using this compiled graph can be safely reclaimed.

    Two-stage check:
    1. All ADSR nodes must be in Idle stage (envelope has finished)
    2. The last output buffer must be silent (all samples below threshold)

    WHY two stages: ADSR-only detection would cut voices with downstream delay or feedback tails that are still audible. Energy-only detection would keep voices alive during sustain (where output is non-zero but expected).

    CompiledDsp::last_sanitized_count

    fn CompiledDsp::last_sanitized_count(self : CompiledDsp) -> Int

    Number of non-finite samples replaced with 0.0 during the most recent process() call. Returns 0 if output was clean.

    CompiledDsp::process

    Run the compiled graph for one buffer and write the final output into output.

    CompiledDsp::reset_runtime_state

    fn CompiledDsp::reset_runtime_state(self : CompiledDsp) -> Unit

    Reset mutable runtime state and restore compile-time node parameters.

    CompiledDsp::set_param

    fn CompiledDsp::set_param(self : CompiledDsp, node_index : Int, slot : GraphParamSlot, value : Double) -> Result[Unit, GraphControlError]

    Update a runtime parameter on a compiled node using its original authoring index.

    CompiledDsp::set_param_bool

    fn CompiledDsp::set_param_bool(self : CompiledDsp, node_index : Int, slot : GraphParamSlot, value : Double) -> Bool

    Allocation-conscious parameter primitive for prevalidated host paths.

    CompiledDsp::validate_controls

    fn CompiledDsp::validate_controls(self : CompiledDsp, controls : Array[GraphControl]) -> Result[Unit, GraphControlError]

    Validate a runtime control batch without mutating the compiled graph.

    CompiledDspHotSwap

    type CompiledDspHotSwap

    Block-boundary mono graph hot-swap wrapper for CompiledDsp.

    Public facade wrapper; implementation lives in graph/internal/staging.

    CompiledDspHotSwap::apply_control

    fn CompiledDspHotSwap::apply_control(self : CompiledDspHotSwap, control : GraphControl) -> Result[Unit, GraphControlError]

    Apply one runtime control message through a mono hot-swap wrapper.

    CompiledDspHotSwap::apply_controls

    fn CompiledDspHotSwap::apply_controls(self : CompiledDspHotSwap, controls : Array[GraphControl]) -> Result[Unit, GraphControlError]

    Apply a runtime control batch transactionally through a mono hot-swap wrapper.

    CompiledDspHotSwap::from_graph

    fn CompiledDspHotSwap::from_graph(active : CompiledDsp, crossfade_samples? : Int) -> CompiledDspHotSwap

    Create a hot-swap wrapper around an active mono compiled graph.

    CompiledDspHotSwap::gate_off

    fn CompiledDspHotSwap::gate_off(self : CompiledDspHotSwap, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger runtime gate-off through a mono hot-swap wrapper.

    CompiledDspHotSwap::gate_on

    fn CompiledDspHotSwap::gate_on(self : CompiledDspHotSwap, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger runtime gate-on through a mono hot-swap wrapper.

    CompiledDspHotSwap::process

    Process one block, crossfading between the active and pending graphs when a swap is in flight.

    CompiledDspHotSwap::queue_swap

    fn CompiledDspHotSwap::queue_swap(self : CompiledDspHotSwap, next : CompiledDsp) -> Result[Unit, HotSwapQueueError]

    Queue a replacement graph for the next process(...) call.

    Returns an error when the replacement graph is incompatible with the active graph's compile-time sample rate or block capacity.

    CompiledDspHotSwap::set_param

    fn CompiledDspHotSwap::set_param(self : CompiledDspHotSwap, node_index : Int, slot : GraphParamSlot, value : Double) -> Result[Unit, GraphControlError]

    Update a runtime parameter through a mono hot-swap wrapper.

    CompiledDspTopologyController

    type CompiledDspTopologyController

    Mono topology-edit wrapper that recompiles authoring nodes and stages the replacement through the internal hot-swap graph.

    Public facade wrapper; implementation lives in graph/internal/staging.

    CompiledDspTopologyController::apply_control

    Apply one runtime control message through a mono topology controller.

    CompiledDspTopologyController::apply_controls

    Apply a runtime control batch transactionally through a mono topology controller.

    CompiledDspTopologyController::from_nodes

    Build a topology-edit wrapper from authoring-order mono nodes.

    CompiledDspTopologyController::gate_off

    fn CompiledDspTopologyController::gate_off(self : CompiledDspTopologyController, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger runtime gate-off through a mono topology controller.

    CompiledDspTopologyController::gate_on

    fn CompiledDspTopologyController::gate_on(self : CompiledDspTopologyController, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger runtime gate-on through a mono topology controller.

    CompiledDspTopologyController::process

    Process one block through the active or crossfading mono graph.

    CompiledDspTopologyController::queue_topology_edit

    Queue one topology edit for the next hot-swap recompilation.

    CompiledDspTopologyController::queue_topology_edits

    Queue an ordered topology-edit batch.

    The batch is transactional: invalid node indices or a recompilation failure reject the whole edit set and leave the current graph unchanged.

    CompiledDspTopologyController::set_param

    fn CompiledDspTopologyController::set_param(self : CompiledDspTopologyController, node_index : Int, slot : GraphParamSlot, value : Double) -> Result[Unit, GraphControlError]

    Update a runtime parameter through a mono topology controller.

    CompiledStereoDsp

    type CompiledStereoDsp

    Executable terminal-stereo graph compiled from DspNodes.

    Public facade wrapper; implementation lives in graph/internal/runtime.

    CompiledStereoDsp::apply_control

    fn CompiledStereoDsp::apply_control(self : CompiledStereoDsp, control : GraphControl) -> Result[Unit, GraphControlError]

    Apply one runtime control message, returning a specific rejection reason.

    CompiledStereoDsp::apply_controls

    fn CompiledStereoDsp::apply_controls(self : CompiledStereoDsp, controls : Array[GraphControl]) -> Result[Unit, GraphControlError]

    Apply a runtime control batch transactionally.

    CompiledStereoDsp::compile

    Compile a declarative terminal-stereo graph into an executable stereo graph.

    Accepts a CompiledTemplate (the runtime exchange boundary per ADR-0010) and returns None if the template's topology is rejected — including the stereo-specific requirement of a single reachable StereoOutput.

    CompiledStereoDsp::compile_result

    Compile a declarative terminal-stereo graph and return a typed rejection reason when compilation fails.

    CompiledStereoDsp::gate_off

    fn CompiledStereoDsp::gate_off(self : CompiledStereoDsp, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger gate_off() on a stereo-graph ADSR node using its original authoring index.

    CompiledStereoDsp::gate_on

    fn CompiledStereoDsp::gate_on(self : CompiledStereoDsp, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger gate_on() on a stereo-graph ADSR node using its original authoring index.

    CompiledStereoDsp::has_feedback_edges

    fn CompiledStereoDsp::has_feedback_edges(self : CompiledStereoDsp) -> Bool

    CompiledStereoDsp::last_sanitized_count

    fn CompiledStereoDsp::last_sanitized_count(self : CompiledStereoDsp) -> Int

    CompiledStereoDsp::process

    Run the compiled stereo graph for one buffer and write the final output into explicit left and right buffers.

    CompiledStereoDsp::set_param

    fn CompiledStereoDsp::set_param(self : CompiledStereoDsp, node_index : Int, slot : GraphParamSlot, value : Double) -> Result[Unit, GraphControlError]

    Update a runtime parameter on a compiled stereo node using its original authoring index.

    CompiledStereoDsp::validate_controls

    fn CompiledStereoDsp::validate_controls(self : CompiledStereoDsp, controls : Array[GraphControl]) -> Result[Unit, GraphControlError]

    Validate a runtime control batch without mutating the compiled graph.

    CompiledStereoDspHotSwap

    type CompiledStereoDspHotSwap

    Block-boundary stereo graph hot-swap wrapper for CompiledStereoDsp.

    Public facade wrapper; implementation lives in graph/internal/staging.

    CompiledStereoDspHotSwap::apply_control

    fn CompiledStereoDspHotSwap::apply_control(self : CompiledStereoDspHotSwap, control : GraphControl) -> Result[Unit, GraphControlError]

    Apply one runtime control message through a stereo hot-swap wrapper.

    CompiledStereoDspHotSwap::apply_controls

    fn CompiledStereoDspHotSwap::apply_controls(self : CompiledStereoDspHotSwap, controls : Array[GraphControl]) -> Result[Unit, GraphControlError]

    Apply a runtime control batch transactionally through a stereo hot-swap wrapper.

    CompiledStereoDspHotSwap::from_graph

    fn CompiledStereoDspHotSwap::from_graph(active : CompiledStereoDsp, crossfade_samples? : Int) -> CompiledStereoDspHotSwap

    Create a hot-swap wrapper around an active stereo compiled graph.

    CompiledStereoDspHotSwap::gate_off

    fn CompiledStereoDspHotSwap::gate_off(self : CompiledStereoDspHotSwap, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger runtime gate-off through a stereo hot-swap wrapper.

    CompiledStereoDspHotSwap::gate_on

    fn CompiledStereoDspHotSwap::gate_on(self : CompiledStereoDspHotSwap, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger runtime gate-on through a stereo hot-swap wrapper.

    CompiledStereoDspHotSwap::process

    Process one block, crossfading between the active and pending stereo graphs when a swap is in flight.

    CompiledStereoDspHotSwap::queue_swap

    Queue a replacement stereo graph for the next process(...) call.

    Returns an error when the replacement graph is incompatible with the active graph's compile-time sample rate or block capacity.

    CompiledStereoDspHotSwap::set_param

    fn CompiledStereoDspHotSwap::set_param(self : CompiledStereoDspHotSwap, node_index : Int, slot : GraphParamSlot, value : Double) -> Result[Unit, GraphControlError]

    Update a runtime parameter through a stereo hot-swap wrapper.

    CompiledStereoDspTopologyController

    type CompiledStereoDspTopologyController

    Terminal-stereo topology-edit wrapper that recompiles authoring nodes and stages the replacement through the internal hot-swap graph.

    Public facade wrapper; implementation lives in graph/internal/staging.

    CompiledStereoDspTopologyController::apply_control

    Apply one runtime control message through a stereo topology controller.

    CompiledStereoDspTopologyController::apply_controls

    Apply a runtime control batch transactionally through a stereo topology controller.

    CompiledStereoDspTopologyController::from_nodes

    Build a topology-edit wrapper from authoring-order terminal-stereo nodes.

    CompiledStereoDspTopologyController::gate_off

    fn CompiledStereoDspTopologyController::gate_off(self : CompiledStereoDspTopologyController, node_index : Int) -> Result[Unit, GraphControlError]

    Trigger runtime gate-off through a stereo topology controller.

    CompiledStereoDspTopologyController::gate_on

    Trigger runtime gate-on through a stereo topology controller.

    CompiledStereoDspTopologyController::process

    Process one block through the active or crossfading stereo graph.

    CompiledStereoDspTopologyController::queue_topology_edit

    Queue one topology edit for the next stereo hot-swap recompilation.

    CompiledStereoDspTopologyController::queue_topology_edits

    Queue an ordered stereo topology-edit batch.

    The batch is transactional: invalid node indices or a recompilation failure reject the whole edit set and leave the current graph unchanged.

    CompiledStereoDspTopologyController::set_param

    fn CompiledStereoDspTopologyController::set_param(self : CompiledStereoDspTopologyController, node_index : Int, slot : GraphParamSlot, value : Double) -> Result[Unit, GraphControlError]

    Update a runtime parameter through a stereo topology controller.

    CompiledTemplate

    pub struct CompiledTemplate {
    // private fields
    }

    Topology artifact: template snapshot paired with its optimize_graph result. Holds the minimum needed to answer post-optimization topology questions ("is this node live?", "how many ADSRs were eliminated?") without allocating runtime buffers or per-voice state.

    WHY a separate artifact from CompiledDsp: CompiledDsp conflates topology with runtime state. Binding validation and pool-level orphan gates only need topology — making that a lightweight standalone type avoids paying for buffers we never use, and keeps the API mono/stereo-agnostic (the same CompiledTemplate shape applies to any graph variant).

    This public facade keeps Array[DspNode] -> CompiledTemplate as the canonical authoring/runtime crossing while the implementation lives in graph/internal/template over the raw graph model.

    CompiledTemplate::adsr_authoring_indices

    fn CompiledTemplate::adsr_authoring_indices(self : CompiledTemplate) -> FixedArray[Int]

    Authoring indices of ADSR nodes that survived optimize_graph, in authoring order. Used by voice/ to gate the surviving ADSRs on note_on / note_off — they call CompiledDsp::gate_on/gate_off which take authoring indices and remap through index_map internally.

    WHY authoring indices, not runtime: CompiledDsp::gate_on/gate_off expect the original authoring index; returning runtime indices would cause voice/ to double-map and target wrong nodes.

    WHY a separate accessor instead of exposing length/node_at: keeps the accessor surface minimal (principle 7). Specific validation patterns get their own public method; generic introspection waits for a concrete consumer.

    CompiledTemplate::analyze

    fn CompiledTemplate::analyze(template : Array[DspNode]) -> CompiledTemplate

    Snapshot the template and run optimize_graph once.

    WHY defensive copy: the caller's template array is mutable from outside. Without a snapshot, any post-analyze mutation of the source array would corrupt the authoring snapshot we rely on for every subsequent query. optimize_graph itself does not mutate its input, so the copy is only guarding against caller-side mutation.

    WHY no DspContext: optimize_graph is a pure function of Array[DspNode]; sample rate and block size do not affect which nodes survive dead-code elimination. Omitting the context makes analyze infallible and cheap.

    CompiledTemplate::orphan_adsr_count

    fn CompiledTemplate::orphan_adsr_count(self : CompiledTemplate) -> Int

    Count Adsr nodes in the template snapshot whose compiled index is < 0 (eliminated by optimize_graph as dead code). On a CompiledDsp, gate_on for an orphan ADSR returns Err(OrphanNode) — VoicePool::new and set_template reject templates where this count is > 0 so the per-note gate loop can .unwrap() instead of branching on every voice trigger.

    Parameterless because the template snapshot is owned by self; callers do not need to remember which template was compiled.

    ControlBinding

    pub struct ControlBinding {
    key : String
    node_index : Int
    slot : GraphParamSlot
    } derive(Eq,
    Debug
    )

    ControlBinding::ControlBinding

    #alias(new)
    fn ControlBinding::ControlBinding(key~ : String, node_index~ : Int, slot~ : GraphParamSlot) -> ControlBinding

    ControlBindingBuilder

    pub struct ControlBindingBuilder {
    // private fields
    } derive(
    Debug
    )

    ControlBindingBuilder::ControlBindingBuilder

    #alias(new)
    fn ControlBindingBuilder::ControlBindingBuilder() -> ControlBindingBuilder

    ControlBindingBuilder::bind

    fn ControlBindingBuilder::bind(self : ControlBindingBuilder, key~ : String, node_index~ : Int, slot~ : GraphParamSlot) -> ControlBindingBuilder

    Add a binding. Mutates internal array, returns self for chaining.

    ControlBindingBuilder::build

    Validate all bindings against the compiled template and transition to the proven-valid ControlBindingMap. Per-binding checks in order: node index bounds, slot compatibility with the authoring node kind, post-optimization liveness (rejects bindings on nodes eliminated by optimize_graph), and key uniqueness. Returns the first error found.

    ControlBindingError

    pub(all) enum ControlBindingError {
    InvalidNodeIndex(Int)
    InvalidSlotForNode(Int, GraphParamSlot)
    DuplicateKey(String)
    OrphanBinding(String, Int)
    } derive(Eq,
    Debug
    )

    ControlBindingMap

    pub struct ControlBindingMap {
    // private fields
    } derive(Eq,
    Debug
    )

    Proven-valid control bindings. Validated against a specific CompiledTemplate at build time (bounds + slot compatibility + orphan detection + key uniqueness).

    No public constructor — only reachable through ControlBindingBuilder::build().

    WARNING: A ControlBindingMap's validity is tied to the template it was built against. After VoicePool::set_template swaps to a new template, bindings validated against the prior template remain type-level valid but may silently retarget the wrong kind of node or no-op against nodes the new template's optimize_graph eliminated. Rebuild the ControlBindingMap whenever the template changes. Structural staleness detection is tracked as a follow-up.

    ControlBindingMap::default_value

    fn ControlBindingMap::default_value(self : ControlBindingMap, key : String) -> Double?

    Read the default captured when these bindings were validated.

    ControlBindingMap::length

    fn ControlBindingMap::length(self : ControlBindingMap) -> Int

    Number of validated bindings in this map.

    ControlBindingMap::resolve_controls

    fn ControlBindingMap::resolve_controls(self : ControlBindingMap, controls : Map[String, Double]) -> Array[GraphControl]

    Convert pattern controls to graph controls using the validated bindings. Emits GraphControl::set_param for each bound key found in the input map, in binding insertion order. Missing keys are skipped; unrecognized keys are ignored. Values are passed through without domain validation.

    DspNode

    pub struct DspNode {
    // private fields
    }

    Flat graph node representation for compiled DSP graphs.
    impl Eq for DspNode

    DspNode::adsr

    fn DspNode::adsr(attack_ms~ : Double, decay_ms~ : Double, sustain~ : Double, release_ms~ : Double) -> DspNode

    Create an ADSR envelope source node.

    DspNode::biquad

    fn DspNode::biquad(input~ : Int, mode~ :
    BiquadMode
    , cutoff_hz~ : Double, q~ : Double) -> DspNode

    Create a fixed-parameter biquad node from one upstream node.

    DspNode::clip

    fn DspNode::clip(input : Int, threshold : Double) -> DspNode

    Create a clip node from one upstream node.

    DspNode::constant

    fn DspNode::constant(value : Double) -> DspNode

    Create a constant-value node.

    DspNode::delay

    fn DspNode::delay(input~ : Int, max_delay_samples~ : Int, delay_samples? : Int, feedback? : Double) -> DspNode

    Create a fixed-delay node from one upstream node.

    DspNode::delay_max_samples

    fn DspNode::delay_max_samples(self : DspNode) -> Int

    DspNode::delay_samples

    fn DspNode::delay_samples(self : DspNode) -> Int

    DspNode::envelope_gain

    fn DspNode::envelope_gain(input~ : Int, envelope~ : Int, amount~ : Double) -> DspNode

    Create a gain node with envelope modulation from two upstream nodes.

    DspNode::filter_mode

    DspNode::gain

    fn DspNode::gain(input : Int, amount : Double) -> DspNode

    Create an in-place gain node from one upstream node.

    DspNode::input0

    fn DspNode::input0(self : DspNode) -> Int

    DspNode::input1

    fn DspNode::input1(self : DspNode) -> Int

    DspNode::kind

    fn DspNode::kind(self : DspNode) -> DspNodeKind

    DspNode::mix

    fn DspNode::mix(left : Int, right : Int) -> DspNode

    Create a mix node from two upstream nodes.

    DspNode::mul

    fn DspNode::mul(left : Int, right : Int) -> DspNode

    Create a sample-wise multiply node from two upstream nodes.

    DspNode::noise

    fn DspNode::noise(seed : UInt) -> DspNode

    Create a white-noise source node.

    DspNode::oscillator

    fn DspNode::oscillator(waveform :
    Waveform
    , freq : Double) -> DspNode

    Create an oscillator node with a fixed frequency.

    DspNode::oscillator_from

    fn DspNode::oscillator_from(input : Int, waveform :
    Waveform
    ) -> DspNode

    Create an oscillator node that reads frequency from another node (FM mode).

    DspNode::output

    fn DspNode::output(input : Int) -> DspNode

    Mark the final output node.

    DspNode::pan

    fn DspNode::pan(input : Int, position : Double) -> DspNode

    Create a terminal stereo pan node from one mono upstream node.

    DspNode::seed

    fn DspNode::seed(self : DspNode) -> UInt

    DspNode::stereo_biquad

    fn DspNode::stereo_biquad(input~ : Int, mode~ :
    BiquadMode
    , cutoff_hz~ : Double, q~ : Double) -> DspNode

    Create a stereo biquad node from one stereo upstream node.

    DspNode::stereo_clip

    fn DspNode::stereo_clip(input~ : Int, threshold~ : Double) -> DspNode

    Create a stereo clip node from one stereo upstream node.

    DspNode::stereo_delay

    fn DspNode::stereo_delay(input~ : Int, max_delay_samples~ : Int, delay_samples? : Int, feedback? : Double) -> DspNode

    Create a stereo delay node from one stereo upstream node.

    DspNode::stereo_gain

    fn DspNode::stereo_gain(input~ : Int, amount~ : Double) -> DspNode

    Create a stereo gain node from one stereo upstream node.

    DspNode::stereo_mixdown

    fn DspNode::stereo_mixdown(input : Int) -> DspNode

    Create a fixed-policy stereo-to-mono fold-down node.

    DspNode::stereo_output

    fn DspNode::stereo_output(input : Int) -> DspNode

    Mark the final stereo output node.

    DspNode::value0

    fn DspNode::value0(self : DspNode) -> Double

    DspNode::value1

    fn DspNode::value1(self : DspNode) -> Double

    DspNode::value2

    fn DspNode::value2(self : DspNode) -> Double

    DspNode::value3

    fn DspNode::value3(self : DspNode) -> Double

    DspNode::waveform

    DspNodeKind

    pub(all) enum DspNodeKind {
    Constant
    Oscillator
    Noise
    Adsr
    Biquad
    Delay
    Gain
    Mul
    Mix
    Clip
    Output
    Pan
    StereoGain
    StereoClip
    StereoBiquad
    StereoDelay
    StereoMixDown
    StereoOutput
    } derive(Eq,
    Debug
    )

    Public graph facade wrappers for the raw graph model in graph/internal/model.

    These wrappers preserve source compatibility for callers that write @graph.DspNode::constant(...) while keeping the extracted model package hidden behind the facade.

    Minimal Phase 2 graph node kinds for compiled mono DSP graphs.

    GraphBuilder

    pub struct GraphBuilder {
    // private fields
    }

    A tagless interpretation that builds an Array[DspNode] graph.

    Each GraphBuilder value carries a mutable node array and the index of the "current" node within that array. Source nodes (constant, noise, adsr) start a fresh array, unary ops append to the existing array, and binary ops merge two arrays when they originate from different sources.

    GraphBuilder::analyze

    Produce a CompiledTemplate from the builder's current node list. Sugar over CompiledTemplate::analyze(self.nodes()) — exists because GraphBuilder is the canonical entry point and the runtime boundary is CompiledTemplate. See ADR-0010.

    GraphBuilder::nodes

    fn GraphBuilder::nodes(self : GraphBuilder) -> Array[DspNode]

    Return the accumulated node array.

    GraphCompileError

    pub(all) enum GraphCompileError {
    InvalidSampleRate(Double)
    MissingOutput(DspNodeKind)
    MultipleOutputs(DspNodeKind)
    WrongOutputKind(Int, DspNodeKind, DspNodeKind)
    InvalidInput(Int, DspNodeKind, GraphTopologyInputSlot, Int)
    InvalidParamValue(Int, DspNodeKind, GraphParamSlot, Double)
    InvalidDelaySamples(Int, Int, Int)
    UnreachableNode(Int)
    InvalidFeedbackEdge(Int, Int, Int)
    DuplicateFeedbackInput(Int, GraphTopologyInputSlot)
    InvalidTerminalShape(DspNodeKind)
    InternalRejected(DspNodeKind)
    } derive(
    Debug
    )

    Typed rejection reason for graph compilation.

    Node indices reported by public compile_result entry points are original authoring indices when they can be mapped from the analyzed template.

    GraphControl

    pub struct GraphControl {
    // private fields
    }

    Runtime control message for a compiled graph.

    GraphControl::gate_off

    fn GraphControl::gate_off(node_index : Int) -> GraphControl

    Create a runtime gate-off control targeting an original authoring index.

    GraphControl::gate_on

    fn GraphControl::gate_on(node_index : Int) -> GraphControl

    Create a runtime gate-on control targeting an original authoring index.

    GraphControl::kind

    GraphControl::node_index

    fn GraphControl::node_index(self : GraphControl) -> Int

    GraphControl::set_param

    fn GraphControl::set_param(node_index : Int, slot : GraphParamSlot, value : Double) -> GraphControl

    Create a runtime numeric parameter update targeting an original authoring index.

    GraphControl::slot

    GraphControl::value

    fn GraphControl::value(self : GraphControl) -> Double

    GraphControlError

    pub(all) enum GraphControlError {
    InvalidNodeIndex(Int)
    OrphanNode(Int)
    InvalidGateNode(Int, DspNodeKind)
    InvalidSlotForNode(Int, DspNodeKind, GraphParamSlot)
    InvalidParamValue(Int, DspNodeKind, GraphParamSlot, Double)
    MissingRuntimeState(Int, DspNodeKind)
    } derive(
    Debug
    )

    Failure reason for runtime graph control APIs.

    GraphControlKind

    pub(all) enum GraphControlKind {
    GateOn
    GateOff
    SetParam
    } derive(Eq)

    Unified runtime control kinds for compiled graphs.

    GraphIndexMap

    pub struct GraphIndexMap {
    // private fields
    }

    Stable-ID to authoring-index lookup produced by GraphTemplateDoc.

    Public facade wrapper; implementation lives in graph/internal/authoring.

    GraphIndexMap::bind_control

    GraphIndexMap::insert_chain

    GraphIndexMap::insert_node

    GraphIndexMap::length

    fn GraphIndexMap::length(self : GraphIndexMap) -> Int

    GraphIndexMap::node_id_at

    GraphIndexMap::node_index

    GraphIndexMap::replace_node

    GraphIndexMap::set_param

    GraphParamSlot

    pub(all) enum GraphParamSlot {
    Value0
    Value1
    Value2
    Value3
    DelaySamples
    } derive(Eq,
    Debug
    )

    Runtime-updatable numeric graph parameter slots.

    GraphTemplateDoc

    pub struct GraphTemplateDoc {
    // private fields
    }

    Identity-bearing authoring wrapper for graph templates.

    Runtime graph compilation remains index-based. GraphTemplateDoc owns the stable authoring IDs and exposes GraphIndexMap at the boundary where controls, bindings, and topology edits are translated to existing indices.

    Public facade wrapper; implementation lives in graph/internal/authoring.

    GraphTemplateDoc::analyze

    GraphTemplateDoc::compile

    GraphTemplateDoc::compile_stereo

    GraphTemplateDoc::contains_node

    GraphTemplateDoc::contains_retired_node

    GraphTemplateDoc::index_map

    GraphTemplateDoc::length

    fn GraphTemplateDoc::length(self : GraphTemplateDoc) -> Int

    GraphTemplateDoc::node_id_at

    GraphTemplateDoc::node_index

    GraphTemplateDoc::nodes

    GraphTemplateDoc::replace_node

    GraphTopologyEdit

    pub(all) enum GraphTopologyEdit {
    ReplaceNode(Int, DspNode)
    RewireInput(Int, GraphTopologyInputSlot, Int)
    InsertNode(Int, GraphTopologyInputSlot, DspNode)
    DeleteNode(Int, Int, GraphTopologyInputSlot, Int)
    InsertChain(Int, GraphTopologyInputSlot, Array[DspNode])
    DeleteChain(Int, Int, Int, GraphTopologyInputSlot, Int)
    }

    Declarative topology edit applied in authoring order before recompilation.

    Each variant carries exactly the fields it needs — no sentinel values.

    GraphTopologyEdit::delete_chain

    fn GraphTopologyEdit::delete_chain(start_node : Int, end_node : Int, retarget_node : Int, input_slot : GraphTopologyInputSlot, replacement_source : Int) -> GraphTopologyEdit

    Delete a contiguous chain of unary authoring-order nodes and retarget one downstream input to a replacement upstream source.

    All nodes from start_node through end_node (inclusive) must be unary and each must feed exactly one downstream consumer. The retarget input of retarget_node is rerouted to replacement_source, and every node in the chain is removed with index compaction.

    GraphTopologyEdit::delete_node

    fn GraphTopologyEdit::delete_node(delete_node_index : Int, retarget_node_index : Int, retarget_input_slot : GraphTopologyInputSlot, replacement_source_index : Int) -> GraphTopologyEdit

    Delete one unary authoring-order node and retarget one downstream input to a replacement upstream source.

    This first slice is the inverse of append-only InsertNode: it only supports deleting unary nodes on the mono path, and the caller must provide the downstream target plus the replacement upstream source explicitly.

    GraphTopologyEdit::insert_chain

    fn GraphTopologyEdit::insert_chain(retarget_node : Int, input_slot : GraphTopologyInputSlot, chain_nodes : Array[DspNode]) -> GraphTopologyEdit

    Insert a chain of unary authoring-order nodes and retarget one downstream input to the last node in the chain.

    Each node in the chain is appended at the end of the authoring array. The first chain node inherits the previous upstream source of the retarget input; each subsequent chain node reads from the preceding chain node. The retarget input is then rerouted to the last chain node.

    GraphTopologyEdit::insert_node

    fn GraphTopologyEdit::insert_node(retarget_node_index : Int, retarget_input_slot : GraphTopologyInputSlot, inserted_node : DspNode) -> GraphTopologyEdit

    Insert one unary authoring-order node and retarget one downstream input to the inserted node.

    This first slice appends the inserted node at the end of the authoring array so existing node indices remain stable across the staged replacement. retarget_node_index and retarget_input_slot identify the downstream input that will be rerouted to the inserted node. The inserted node itself inherits that input's previous upstream source as its own input0.

    GraphTopologyEdit::replace_node

    fn GraphTopologyEdit::replace_node(node_index : Int, replacement : DspNode) -> GraphTopologyEdit

    Replace one authoring-order node, including its kind and input wiring.

    GraphTopologyEdit::rewire_input

    fn GraphTopologyEdit::rewire_input(node_index : Int, input_slot : GraphTopologyInputSlot, source_index : Int) -> GraphTopologyEdit

    Rewire one authoring-order node input to a different upstream source.

    GraphTopologyEditError

    pub(all) enum GraphTopologyEditError {
    InvalidNodeIndex(Int)
    InvalidSourceIndex(Int)
    UnsupportedInputSlot(Int, GraphTopologyInputSlot, DspNodeKind)
    UnsupportedInsertTemplate(DspNodeKind)
    EmptyInsertChain
    UnsupportedChainNode(Int, DspNodeKind)
    InvalidDeleteRange(Int, Int)
    ReplacementSourceInDeletedRange(Int)
    DeleteNodeRequiresUnary(Int, DspNodeKind)
    DeleteNodeRequiresSingleConsumer(Int)
    DeleteNodeConsumerMismatch(Int, Int)
    DeleteChainRequiresUnary(Int, DspNodeKind)
    DeleteChainRequiresSingleConsumer(Int)
    DeleteChainConsumerMismatch(Int, Int, Int)
    } derive(
    Debug
    )

    Failure reason for result-typed topology queue APIs.

    GraphTopologyInputSlot

    pub(all) enum GraphTopologyInputSlot {
    Input0
    Input1
    } derive(Eq,
    Debug
    )

    Input slot selector for fixed-length topology rewiring.

    GraphTopologyQueueError

    pub(all) enum GraphTopologyQueueError {
    PendingSwap
    InvalidEdit(Int, GraphTopologyEditError)
    RecompileRejected
    HotSwap(HotSwapQueueError)
    } derive(
    Debug
    )

    Failure reason for result-typed topology queue APIs.

    GraphValidationError

    pub(all) enum GraphValidationError {
    InvalidInput0(Int, Int, Int)
    InvalidInput1(Int, Int, Int)
    InvalidStateIndex(Int, String)
    } derive(Eq,
    Debug
    )

    HotSwapQueueError

    pub(all) enum HotSwapQueueError {
    SampleRateMismatch(Double, Double)
    BlockCapacityMismatch(Int, Int)
    } derive(
    Debug
    )

    Failure reason for result-typed hot-swap queue APIs.

    node_accepts_slot

    fn node_accepts_slot(node : DspNode, slot : GraphParamSlot) -> Bool

    Structural check: does this node kind accept SetParam on the given slot?

    replay

    Walk a DspNode array and reconstruct the DSP graph through the tagless API, enabling round-trip testing (GraphBuilder -> nodes -> replay -> Eval). Returns None for empty arrays or invalid node references.