Skip to main content

ModNode

Enum ModNode 

Source
pub enum ModNode {
    None,
    Lfo {
        wave: Waveform,
        rate: f64,
        uid: Uid,
    },
    Env {
        attack: f64,
        decay: f64,
        uid: Uid,
    },
    Rand {
        rate: f64,
        glide: f64,
        uid: Uid,
    },
    Follow {
        sens: f64,
        release: f64,
        uid: Uid,
    },
    Euclid {
        rate: f64,
        steps: f64,
        pulses: f64,
        uid: Uid,
    },
    Op {
        kind: ModOp,
        p0: f64,
        p1: f64,
        input: Box<ModNode>,
        uid: Uid,
    },
    Pair {
        kind: PairOp,
        a: Box<ModNode>,
        b: Box<ModNode>,
        uid: Uid,
    },
}
Expand description

A modulation-slot term: what drives a processor’s mod input.

Modulation is a recursive sort with a depth bound, not a flat list of leaves: ModNode::Op wraps one modulation term in a CV processor and ModNode::Pair combines two, so s&h rand → quantize → slew is a term the grammar writes, the taste model reads and the rack draws.

The bound is crate::prior::PatchGrammarPrior::max_mod_depth. Without it the mod sort has no parsimony pressure at all — nothing in the audio tree’s prior mass objects to a forty-node CV chain that moves one knob.

§What quiver ships that is deliberately not here

  • StepSequencer — its eight step values are steps: [f64; 8] internal state with no ports (utilities.rs, and its own comment says so). It would need eight genome sites baked at compile time and could not be edited live, which breaks both the four-knob faceplate budget and the “every knob is a trace address you can turn” contract the instrument rests on.
  • Quantizer — subsumed by ScaleQuantizer, which is the same module with a scale rather than raw semitones.
  • Comparator — its useful output is a gate, and PairOp’s logic ops already make gates out of the sources that matter.
  • Multiple, PrecisionAdder — the tree already fans out, and quiver’s gather already sums several cables into one port.
  • Attenuverter — this is mod_depth. It is already in every mod cable, one per slot.
  • EdgeDetector — a primitive the clocked modules use internally.
  • ChordMemory, Arpeggiator — polyphonic pitch generators; the instrument already has an arpeggiator in the keybed and a per-voice one would fight it.
  • MidSideEncode/Decode — needs a stereo sort the grammar has no way to name.
  • SamplePlayer — no asset pipeline, and it would make this something other than a synth.
  • Crosstalk, GroundLoop, Oversampler, UnitDelay, Mixer — analog imperfection, a wrapper, a one-sample primitive, and a module Crossfader already covers.

Default is ModNode::None, which is what #[serde(default)] on the modulation slots that the v2 palette added to already-shipped variants resolves to — see AudioNode::Delay.

Variants§

§

None

No modulation attached.

§

Lfo

A low-frequency oscillator.

Fields

§wave: Waveform

LFO waveform.

§rate: f64

Normalized rate (0-1).

§uid: Uid

Stable identity for this node; see Uid.

§

Env

An attack/decay envelope retriggered by the note gate.

Fields

§attack: f64

Normalized attack time (0-1).

§decay: f64

Normalized decay time (0-1).

§uid: Uid

Stable identity for this node; see Uid.

§

Rand

A random stepped source (noise sampled-and-held on an internal clock) — the classic S&H burble.

Fields

§rate: f64

Normalized clock rate (0-1).

§glide: f64

Normalized slew between steps (0 = hard steps, 1 = a drift).

§uid: Uid

Stable identity for this node; see Uid.

§

Follow

An envelope follower riding the owning module’s own input — the patch’s dynamics fed back into its timbre (a filter that opens on the transient, a fold that hardens when the note is loud).

Deliberately a leaf: it takes no audio subterm of its own, so the grammar gains a modulation source without gaining a second recursion or a second audio-sort site. Its source is whatever the compiler has already built for the module below it.

Fields

§sens: f64

Normalized sensitivity (detector output gain).

§release: f64

Normalized release time.

§uid: Uid

Stable identity for this node; see Uid.

§

Euclid

A clocked euclidean gate pattern — pulses spread as evenly as the step count allows. A leaf, like the four above: it generates rather than processes, and its clock is its own.

Fields

§rate: f64

Normalized clock rate (0-1 → 20..300 BPM).

§steps: f64

Normalized step count (0-1 → 2..16 steps).

§pulses: f64

Normalized pulse density (0-1 → 1..steps−1 pulses).

§uid: Uid

Stable identity for this node; see Uid.

§

Op

A unary CV processor wrapping another modulation term.

p0/p1 are the op’s two continuous knobs; which sites they occupy is ModOp::param_sites. The ops that take one parameter pin p1 to 0 and do not encode it.

Fields

§kind: ModOp

Which processor.

§p0: f64

First continuous parameter (root / rise / mode / rate).

§p1: f64

Second continuous parameter (scale / fall); 0 and unused on the one-parameter ops.

§input: Box<ModNode>

The modulation term being processed. Never ModNode::None — a processor with nothing under it is a dead cable, so the grammar renormalizes it away rather than drawing it (see ModNode::normalized).

§uid: Uid

Stable identity for this node; see Uid.

§

Pair

A binary CV combiner over two modulation terms.

Fields

§kind: PairOp

Which combiner.

§a: Box<ModNode>

First input. Never ModNode::None.

§b: Box<ModNode>

Second input. Never ModNode::None; on PairOp::Switch it is also the control.

§uid: Uid

Stable identity for this node; see Uid.

Implementations§

Source§

impl ModNode

Source

pub fn uid(&self) -> Option<Uid>

This term’s stable identity — None for ModNode::None, which is an empty slot rather than a module.

Source

pub fn set_uid(&mut self, id: Uid)

Overwrite this term’s identity (a no-op on ModNode::None).

Source

pub fn children(&self) -> Vec<&ModNode>

Sub-terms in key-index order (Op’s input is /0; a Pair’s two branches are /0 and /1).

Source

pub fn children_mut(&mut self) -> Vec<&mut ModNode>

Mutable Self::children.

Source

pub fn site_count(&self) -> usize

Number of probabilistic-choice sites this mod term occupies.

Source

pub fn depth(&self) -> usize

Nesting depth of this modulation term: an empty slot is 0, a leaf is 1, and every processor above one adds a level.

This is the quantity crate::prior::PatchGrammarPrior::max_mod_depth bounds and that φ’s mod_depth_mean averages.

Source

pub fn size(&self) -> usize

Number of nodes in this modulation term (an empty slot is 0).

Source

pub fn normalized(self) -> ModNode

The canonical form of a hand-built modulation term.

Two normalizations, both of which the prior enforces by construction (it renormalizes the #mod categorical over the non-empty kinds below an Op or inside a Pair) but which an explicit term arriving from the panel through StructOp::SetModTree can violate:

  • A processor over nothing is nothing. Op with an empty input is a quantizer fed 0 V; Pair with two empty inputs is a logic gate fed two zeroes. Both compile to a cable carrying a constant, which is a module on the rack that does nothing. A Pair with one empty input collapses to the other side rather than to nothing — And(x, 0) is identically low and Min(x, 0) throws away the positive half, so there is no reading under which the empty branch is a musical choice.
  • An unused parameter is pinned to 0. ModOp::param_sites does not encode p1 for the one-parameter ops, so a term carrying a non-zero one would not survive its own trace round-trip.

Folding here rather than in the prior is deliberate: the generative model and crate::genome’s encoding are asserted site-for-site identical, so a prior that sampled a degenerate term and then folded it would emit choices the encoding does not.

Trait Implementations§

Source§

impl Clone for ModNode

Source§

fn clone(&self) -> ModNode

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ModNode

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ModNode

Source§

fn default() -> ModNode

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for ModNode

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for ModNode

Source§

fn eq(&self, other: &ModNode) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for ModNode

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for ModNode

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,