pub struct Graph { /* private fields */ }Expand description
A real-time-safe directed acyclic graph of audio nodes.
A Graph moves through three phases:
- Build — call
Graph::add_nodeto register nodes andGraph::linkto wire output ports to input ports. - Compile — call
Graph::compilewith aGraphConfig. This runs the topological sort, rejects cycles, and pre-allocates every scratch frame. - Run — call
Graph::process_cycleonce per audio cycle on the RT thread. UseGraph::feedto seed external inputs before a cycle andGraph::read_output/Graph::read_inputto tap results after.
See the crate-level documentation for the real-time safety contract.
Implementations§
Source§impl Graph
impl Graph
Sourcepub fn add_node(&mut self, node: Box<dyn AudioNode>) -> NodeId
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.
Sourcepub fn link(
&mut self,
from: (NodeId, PortIdx),
to: (NodeId, PortIdx),
) -> Result<LinkId, GraphError>
pub fn link( &mut self, from: (NodeId, PortIdx), to: (NodeId, PortIdx), ) -> Result<LinkId, GraphError>
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.
Sourcepub fn compile(&mut self, config: GraphConfig) -> Result<(), GraphError>
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.
Sourcepub fn process_cycle(&self, ctx: &mut ProcessContext) -> Result<(), GraphError>
pub fn process_cycle(&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.
§Safety (caller invariant)
This method takes &self (not &mut self) so it can be called on a
Graph loaded from a shared handle such as ArcSwap<Graph>. The
interior mutability of the scratch cell is sound only because the
caller guarantees the real-time thread is single and exclusive — no
other process_cycle, compile, feed, or read_* may run
concurrently on the same Graph. In practice the control thread
builds and compiles a new Graph before swapping it in, so the old
instance being processed is never touched from another thread.
§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.
Sourcepub fn feed(&mut self, node: NodeId, port: PortIdx, src: &AudioFrame)
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).
Sourcepub fn read_output(&self, node: NodeId, port: PortIdx) -> Option<&AudioFrame>
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.
Sourcepub fn read_input(&self, node: NodeId, port: PortIdx) -> Option<&AudioFrame>
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.
Sourcepub fn node_count(&self) -> usize
pub fn node_count(&self) -> usize
Returns the number of nodes in the graph.
Sourcepub fn link_count(&self) -> usize
pub fn link_count(&self) -> usize
Returns the number of links in the graph.
Sourcepub fn is_compiled(&self) -> bool
pub fn is_compiled(&self) -> bool
Returns true if the graph has been compiled.
Sourcepub fn config(&self) -> GraphConfig
pub fn config(&self) -> GraphConfig
Returns the compile-time GraphConfig.
Before Graph::compile this returns the default (zeroed) config.
Source§impl Graph
impl Graph
Sourcepub fn from_snapshot(
snapshot: &TopologySnapshot,
factory: &mut dyn FnMut(NodeId) -> Option<Box<dyn AudioNode>>,
) -> Result<Graph, GraphError>
Available on crate feature topology only.
pub fn from_snapshot( snapshot: &TopologySnapshot, factory: &mut dyn FnMut(NodeId) -> Option<Box<dyn AudioNode>>, ) -> Result<Graph, GraphError>
topology only.Builds a NEW Graph from a TopologySnapshot plus a node factory.
This is a non-RT, control-thread operation. For each
NodeSnapshot the factory is asked to supply a concrete
Box<dyn AudioNode> for that node’s id; the snapshot’s port metadata is
informational (the real node’s ports, as reported by its
inputs() / outputs(), are what link validates against). Edges are
re-linked by remapping each snapshot NodeId to its new id in the
rebuilt graph.
The returned graph is not compiled — the caller compiles it with
their own GraphConfig.
§Errors
Returns GraphError::NodeNotFound if the factory returns None for a
node the snapshot requires, or if an edge references a node id the
factory did not supply. Returns the underlying GraphError from
Graph::link if a rebuilt edge fails port validation.
Sourcepub fn subscribe_topology(&mut self) -> Receiver<TopologyEvent>
Available on crate feature topology only.
pub fn subscribe_topology(&mut self) -> Receiver<TopologyEvent>
topology only.Subscribes to topology events via a std::sync::mpsc channel (non-RT).
Returns a Receiver that receives a
TopologyEvent whenever the graph mutates on the control thread (a
node is added/removed or a link is added/removed). The RT
Graph::process_cycle path never
emits events.
Senders whose receivers have been dropped are pruned automatically on the next emission.
§Real-time safety (G3)
Subscription is a control-thread mutation of the subscriber set, so it
takes &mut self — an exclusive borrow. process_cycle is now &self
(Phase-C prep), so this &mut self is the stronger constraint: it is
statically impossible to hold the &mut self needed to subscribe while
a &self process_cycle borrow is live on the same binding. Combined
with the single-RT-thread invariant on GraphScratch, the RT path is
never disrupted by a concurrent subscription on the same Graph.
Source§impl Graph
impl Graph
Sourcepub fn partition_hints(
&self,
boundaries: &[(NodeId, PortIdx, RemoteNode)],
) -> Vec<PartitionHint>
Available on crate feature distributed only.
pub fn partition_hints( &self, boundaries: &[(NodeId, PortIdx, RemoteNode)], ) -> Vec<PartitionHint>
distributed only.Derives partition hints from a set of (node, port, remote) boundary
declarations.
Every node present in this graph is treated as a local node (the graph
is the local partition). Each declared port becomes a
BoundaryPort with
PortKind::Network. The port’s direction is
resolved from the node’s own port descriptors: output ports are
checked first, so a port index valid on both sides is treated as an
output. A declaration whose port is out of range on both sides is
skipped (the method never panics).
This is a hint generator — sonicbrew’s session-store (M07) decides
the actual partitioning. Exactly one PartitionHint is returned,
describing this single local partition.
Trait Implementations§
Source§impl SnapshotSource for Graph
Available on crate feature topology only.
impl SnapshotSource for Graph
topology only.