Skip to main content

Graph

Struct Graph 

Source
pub struct Graph { /* private fields */ }
Expand description

A real-time-safe directed acyclic graph of audio nodes.

A Graph moves through three phases:

  1. Build — call Graph::add_node to register nodes and Graph::link to wire output ports to input ports.
  2. Compile — call Graph::compile with a GraphConfig. This runs the topological sort, rejects cycles, and pre-allocates every scratch frame.
  3. Run — call Graph::process_cycle once per audio cycle on the RT thread. Use Graph::feed to seed external inputs before a cycle and Graph::read_output / Graph::read_input to tap results after.

See the crate-level documentation for the real-time safety contract.

Implementations§

Source§

impl Graph

Source

pub fn new() -> Self

Creates an empty graph.

Source

pub fn add_node(&mut self, node: Box<dyn AudioNode>) -> NodeId

Adds a node to the graph and returns its stable NodeId.

The returned id equals the node’s index in insertion order and never changes for the lifetime of the graph. Scratch frames for the node’s ports are allocated later in Graph::compile.

Links an output port to an input port, validating both endpoints and their compatibility.

The from port must be an output and the to port an input; their channel counts and sample formats must match. The edge is stored but the graph is not recompiled — call Graph::compile (or design the full topology before compiling) before processing.

§Errors

Returns GraphError::NodeNotFound if either node does not exist, GraphError::PortNotFound if a port index is out of range, GraphError::PortDirectionMismatch if the directions are wrong, or GraphError::PortIncompatible if channel/format differ.

Source

pub fn compile(&mut self, config: GraphConfig) -> Result<(), GraphError>

Compiles the graph: topologically sorts the nodes and pre-allocates every scratch frame.

This is the only place allocation is permitted. After compile succeeds, Graph::process_cycle is guaranteed to be allocation-free.

§Errors

Returns GraphError::AlreadyCompiled if called twice, or GraphError::CycleDetected if the topology contains a cycle.

Source

pub fn process_cycle( &mut self, ctx: &mut ProcessContext, ) -> Result<(), GraphError>

Processes one audio cycle on the real-time thread.

For each node in dependency order this copies connected upstream outputs into the node’s input scratch (or zeroes unconnected inputs), then invokes the node’s process. The whole pass is bounded and allocation-free: every slice is pre-sized by Graph::compile and only bounded for loops / slice copies are used.

§Real-time safety

This method performs no allocation, locking, panicking, or system call. The single Err(NotCompiled) return on the uncompiled path is a stack-only branch (the variant carries no heap data); on the happy path the method returns Ok(()).

§Errors

Returns GraphError::NotCompiled if Graph::compile has not been called.

Source

pub fn feed(&mut self, node: NodeId, port: PortIdx, src: &AudioFrame)

Seeds a node’s output port from an external frame, before a cycle.

Performs a bounded copy into the pre-sized scratch slot — no reallocation. Used to inject audio into a source node’s output before calling Graph::process_cycle. Out-of-range node/port is a silent no-op (never panics).

Source

pub fn read_output(&self, node: NodeId, port: PortIdx) -> Option<&AudioFrame>

Borrows a node’s output frame after a cycle (tapping a node’s output).

Returns None if the node or port is out of range — never panics.

Source

pub fn read_input(&self, node: NodeId, port: PortIdx) -> Option<&AudioFrame>

Borrows the input frame that reached a node after a cycle.

Sinks have zero outputs, so callers read a sink’s consumed audio through its input slot. Returns None if the node or port is out of range.

Source

pub fn node_count(&self) -> usize

Returns the number of nodes in the graph.

Returns the number of links in the graph.

Source

pub fn is_compiled(&self) -> bool

Returns true if the graph has been compiled.

Source

pub fn config(&self) -> GraphConfig

Returns the compile-time GraphConfig.

Before Graph::compile this returns the default (zeroed) config.

Trait Implementations§

Source§

impl Default for Graph

Source§

fn default() -> Self

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

Auto Trait Implementations§

§

impl !RefUnwindSafe for Graph

§

impl !Sync for Graph

§

impl !UnwindSafe for Graph

§

impl Freeze for Graph

§

impl Send for Graph

§

impl Unpin for Graph

§

impl UnsafeUnpin for Graph

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> 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, 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.