///|
/// 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.
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)
///|
/// Runtime-updatable numeric graph parameter slots.
pub(all) enum GraphParamSlot {
Value0
Value1
Value2
Value3
DelaySamples
} derive(Eq, Debug)
///|
pub impl Show for GraphParamSlot with fn output(self, logger) {
logger.write_string(@debug.to_string(self))
}
///|
/// Unified runtime control kinds for compiled graphs.
pub(all) enum GraphControlKind {
GateOn
GateOff
SetParam
} derive(Eq)
///|
/// Runtime control message for a compiled graph.
pub struct GraphControl {
priv raw : @model.GraphControl
}
///|
fn GraphControl::from_model(raw : @model.GraphControl) -> GraphControl {
{ raw, }
}
///|
fn GraphControl::raw(self : GraphControl) -> @model.GraphControl {
self.raw
}
///|
pub fn GraphControl::kind(self : GraphControl) -> GraphControlKind {
graph_control_kind_from_model(self.raw.kind())
}
///|
pub fn GraphControl::node_index(self : GraphControl) -> Int {
self.raw.node_index()
}
///|
pub fn GraphControl::slot(self : GraphControl) -> GraphParamSlot {
graph_param_slot_from_model(self.raw.slot())
}
///|
pub fn GraphControl::value(self : GraphControl) -> Double {
self.raw.value()
}
///|
/// Flat graph node representation for compiled DSP graphs.
pub struct DspNode {
priv raw : @model.DspNode
}
///|
fn DspNode::from_model(raw : @model.DspNode) -> DspNode {
{ raw, }
}
///|
fn DspNode::raw(self : DspNode) -> @model.DspNode {
self.raw
}
///|
/// Structural equality for authoring graph nodes.
pub impl Eq for DspNode with fn equal(self, other) {
self.raw == other.raw
}
///|
pub fn DspNode::kind(self : DspNode) -> DspNodeKind {
dsp_node_kind_from_model(self.raw.kind())
}
///|
pub fn DspNode::input0(self : DspNode) -> Int {
self.raw.input0()
}
///|
pub fn DspNode::input1(self : DspNode) -> Int {
self.raw.input1()
}
///|
pub fn DspNode::value0(self : DspNode) -> Double {
self.raw.value0()
}
///|
pub fn DspNode::value1(self : DspNode) -> Double {
self.raw.value1()
}
///|
pub fn DspNode::value2(self : DspNode) -> Double {
self.raw.value2()
}
///|
pub fn DspNode::value3(self : DspNode) -> Double {
self.raw.value3()
}
///|
pub fn DspNode::waveform(self : DspNode) -> Waveform {
self.raw.waveform()
}
///|
pub fn DspNode::filter_mode(self : DspNode) -> BiquadMode {
self.raw.filter_mode()
}
///|
pub fn DspNode::delay_max_samples(self : DspNode) -> Int {
self.raw.delay_max_samples()
}
///|
pub fn DspNode::delay_samples(self : DspNode) -> Int {
self.raw.delay_samples()
}
///|
pub fn DspNode::seed(self : DspNode) -> UInt {
self.raw.seed()
}
///|
/// Create a constant-value node.
pub fn DspNode::constant(value : Double) -> DspNode {
DspNode::from_model(@model.DspNode::constant(value))
}
///|
/// Create an oscillator node with a fixed frequency.
pub fn DspNode::oscillator(waveform : Waveform, freq : Double) -> DspNode {
DspNode::from_model(@model.DspNode::oscillator(waveform, freq))
}
///|
/// Create an oscillator node that reads frequency from another node (FM mode).
pub fn DspNode::oscillator_from(input : Int, waveform : Waveform) -> DspNode {
DspNode::from_model(@model.DspNode::oscillator_from(input, waveform))
}
///|
/// Create a white-noise source node.
pub fn DspNode::noise(seed : UInt) -> DspNode {
DspNode::from_model(@model.DspNode::noise(seed))
}
///|
/// Create an ADSR envelope source node.
pub fn DspNode::adsr(
attack_ms~ : Double,
decay_ms~ : Double,
sustain~ : Double,
release_ms~ : Double,
) -> DspNode {
DspNode::from_model(
@model.DspNode::adsr(attack_ms~, decay_ms~, sustain~, release_ms~),
)
}
///|
/// Create a fixed-parameter biquad node from one upstream node.
pub fn DspNode::biquad(
input~ : Int,
mode~ : BiquadMode,
cutoff_hz~ : Double,
q~ : Double,
) -> DspNode {
DspNode::from_model(@model.DspNode::biquad(input~, mode~, cutoff_hz~, q~))
}
///|
/// Create a fixed-delay node from one upstream node.
pub fn DspNode::delay(
input~ : Int,
max_delay_samples~ : Int,
delay_samples? : Int = graph_default_delay_samples(max_delay_samples),
feedback? : Double = 0.0,
) -> DspNode {
DspNode::from_model(
@model.DspNode::delay(input~, max_delay_samples~, delay_samples~, feedback~),
)
}
///|
/// Create an in-place gain node from one upstream node.
pub fn DspNode::gain(input : Int, amount : Double) -> DspNode {
DspNode::from_model(@model.DspNode::gain(input, amount))
}
///|
/// Create a gain node with envelope modulation from two upstream nodes.
pub fn DspNode::envelope_gain(
input~ : Int,
envelope~ : Int,
amount~ : Double,
) -> DspNode {
DspNode::from_model(@model.DspNode::envelope_gain(input~, envelope~, amount~))
}
///|
/// Create a sample-wise multiply node from two upstream nodes.
pub fn DspNode::mul(left : Int, right : Int) -> DspNode {
DspNode::from_model(@model.DspNode::mul(left, right))
}
///|
/// Create a mix node from two upstream nodes.
pub fn DspNode::mix(left : Int, right : Int) -> DspNode {
DspNode::from_model(@model.DspNode::mix(left, right))
}
///|
/// Create a clip node from one upstream node.
pub fn DspNode::clip(input : Int, threshold : Double) -> DspNode {
DspNode::from_model(@model.DspNode::clip(input, threshold))
}
///|
/// Mark the final output node.
pub fn DspNode::output(input : Int) -> DspNode {
DspNode::from_model(@model.DspNode::output(input))
}
///|
/// Create a terminal stereo pan node from one mono upstream node.
pub fn DspNode::pan(input : Int, position : Double) -> DspNode {
DspNode::from_model(@model.DspNode::pan(input, position))
}
///|
/// Create a stereo gain node from one stereo upstream node.
pub fn DspNode::stereo_gain(input~ : Int, amount~ : Double) -> DspNode {
DspNode::from_model(@model.DspNode::stereo_gain(input~, amount~))
}
///|
/// Create a stereo clip node from one stereo upstream node.
pub fn DspNode::stereo_clip(input~ : Int, threshold~ : Double) -> DspNode {
DspNode::from_model(@model.DspNode::stereo_clip(input~, threshold~))
}
///|
/// Create a stereo biquad node from one stereo upstream node.
pub fn DspNode::stereo_biquad(
input~ : Int,
mode~ : BiquadMode,
cutoff_hz~ : Double,
q~ : Double,
) -> DspNode {
DspNode::from_model(
@model.DspNode::stereo_biquad(input~, mode~, cutoff_hz~, q~),
)
}
///|
/// Create a stereo delay node from one stereo upstream node.
pub fn DspNode::stereo_delay(
input~ : Int,
max_delay_samples~ : Int,
delay_samples? : Int = graph_default_delay_samples(max_delay_samples),
feedback? : Double = 0.0,
) -> DspNode {
DspNode::from_model(
@model.DspNode::stereo_delay(
input~,
max_delay_samples~,
delay_samples~,
feedback~,
),
)
}
///|
/// Create a fixed-policy stereo-to-mono fold-down node.
pub fn DspNode::stereo_mixdown(input : Int) -> DspNode {
DspNode::from_model(@model.DspNode::stereo_mixdown(input))
}
///|
/// Mark the final stereo output node.
pub fn DspNode::stereo_output(input : Int) -> DspNode {
DspNode::from_model(@model.DspNode::stereo_output(input))
}
///|
/// Create a runtime gate-on control targeting an original authoring index.
pub fn GraphControl::gate_on(node_index : Int) -> GraphControl {
{ raw: @model.GraphControl::gate_on(node_index), }
}
///|
/// Create a runtime gate-off control targeting an original authoring index.
pub fn GraphControl::gate_off(node_index : Int) -> GraphControl {
{ raw: @model.GraphControl::gate_off(node_index), }
}
///|
/// Create a runtime numeric parameter update targeting an original authoring
/// index.
pub fn GraphControl::set_param(
node_index : Int,
slot : GraphParamSlot,
value : Double,
) -> GraphControl {
{ raw: @model.GraphControl::set_param(node_index, slot.to_model(), value), }
}
///|
fn node_with_offset_inputs(node : DspNode, offset : Int) -> DspNode {
DspNode::from_model(@model.node_with_offset_inputs(node.raw(), offset))
}
///|
/// Structural check: does this node kind accept SetParam on the given slot?
pub fn node_accepts_slot(node : DspNode, slot : GraphParamSlot) -> Bool {
@model.node_accepts_slot(node.raw(), slot.to_model())
}
///|
fn graph_default_delay_samples(value : Int) -> Int {
if value > 0 {
value
} else {
0
}
}
///|
fn dsp_node_kind_from_model(kind : @model.DspNodeKind) -> DspNodeKind {
match kind {
@model.DspNodeKind::Constant => DspNodeKind::Constant
@model.DspNodeKind::Oscillator => DspNodeKind::Oscillator
@model.DspNodeKind::Noise => DspNodeKind::Noise
@model.DspNodeKind::Adsr => DspNodeKind::Adsr
@model.DspNodeKind::Biquad => DspNodeKind::Biquad
@model.DspNodeKind::Delay => DspNodeKind::Delay
@model.DspNodeKind::Gain => DspNodeKind::Gain
@model.DspNodeKind::Mul => DspNodeKind::Mul
@model.DspNodeKind::Mix => DspNodeKind::Mix
@model.DspNodeKind::Clip => DspNodeKind::Clip
@model.DspNodeKind::Output => DspNodeKind::Output
@model.DspNodeKind::Pan => DspNodeKind::Pan
@model.DspNodeKind::StereoGain => DspNodeKind::StereoGain
@model.DspNodeKind::StereoClip => DspNodeKind::StereoClip
@model.DspNodeKind::StereoBiquad => DspNodeKind::StereoBiquad
@model.DspNodeKind::StereoDelay => DspNodeKind::StereoDelay
@model.DspNodeKind::StereoMixDown => DspNodeKind::StereoMixDown
@model.DspNodeKind::StereoOutput => DspNodeKind::StereoOutput
}
}
///|
fn GraphParamSlot::to_model(self : GraphParamSlot) -> @model.GraphParamSlot {
match self {
Value0 => @model.GraphParamSlot::Value0
Value1 => @model.GraphParamSlot::Value1
Value2 => @model.GraphParamSlot::Value2
Value3 => @model.GraphParamSlot::Value3
DelaySamples => @model.GraphParamSlot::DelaySamples
}
}
///|
fn graph_param_slot_from_model(slot : @model.GraphParamSlot) -> GraphParamSlot {
match slot {
@model.GraphParamSlot::Value0 => GraphParamSlot::Value0
@model.GraphParamSlot::Value1 => GraphParamSlot::Value1
@model.GraphParamSlot::Value2 => GraphParamSlot::Value2
@model.GraphParamSlot::Value3 => GraphParamSlot::Value3
@model.GraphParamSlot::DelaySamples => GraphParamSlot::DelaySamples
}
}
///|
fn graph_control_kind_from_model(
kind : @model.GraphControlKind,
) -> GraphControlKind {
match kind {
@model.GraphControlKind::GateOn => GraphControlKind::GateOn
@model.GraphControlKind::GateOff => GraphControlKind::GateOff
@model.GraphControlKind::SetParam => GraphControlKind::SetParam
}
}