Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
798 lines (716 sloc) 29.6 KB
//! The [`Graph`](./struct.Graph.html) type constructs a directed, acyclic graph of DSP `Node`
//! types.
//!
//! It supports multiple input and multiple output nodes per node.
//!
//! `Graph` uses the daggy crate. See more [here](https://crates.io/crates/daggy).
//!
//! The `Graph` type requires that its nodes implement the [`Node`](../node/trait.Node.html) trait.
use crate::node::Node;
use daggy::{self, Walker};
use sample::{self, Frame, Sample};
/// An alias for our Graph's Node Index.
pub type NodeIndex = daggy::NodeIndex<usize>;
/// An alias for our Graph's Edge Index.
pub type EdgeIndex = daggy::EdgeIndex<usize>;
/// An alias for the iterator yielding mutable access to all node weights.
pub type NodesMut<'a, N> = daggy::NodeWeightsMut<'a, N, usize>;
/// Read only access to a **Graph**'s internal node array.
pub type RawNodes<'a, N> = daggy::RawNodes<'a, N, usize>;
/// Read only access to a **Graph**'s internal edge array.
pub type RawEdges<'a, F> = daggy::RawEdges<'a, Connection<F>, usize>;
/// An iterator yielding indices to recently added connections.
pub type EdgeIndices = daggy::EdgeIndices<usize>;
/// An alias for the **Dag** used within our **Graph**.
pub type Dag<F, N> = daggy::Dag<N, Connection<F>, usize>;
/// An alias for the **PetGraph** used by our **Graph**'s internal **Dag**.
pub type PetGraph<F, N> = daggy::PetGraph<N, Connection<F>, usize>;
/// A directed, acyclic DSP graph.
///
/// Designed for easily and safely setting up high performance audio signal generating, processing
/// and mixing. Useful for both simple and highly complex signal graphs.
///
/// There are a variety of use cases for `Graph`:
///
/// - Designing effects.
/// - Creating an audio mixer.
/// - Making a sampler.
/// - Writing a DSP backend for a DAW.
/// - Any kind of modular audio synthesis or processing.
///
/// `Graph` is a wrapper around [daggy](http://mitchmindtree.github.io/daggy/daggy/)'s
/// [`Dag`](http://mitchmindtree.github.io/daggy/daggy/struct.Dag.html) type - an abstraction for
/// working with directed acyclic graph's where high performance node adding and accessing is
/// required.
///
/// An input -> output connection in this `Graph` is represented as a parent -> child connection
/// within the internal `Dag`. The following terms are all equivalent:
///
/// - *input -> output*
/// - *src -> dest*
/// - *parent -> child*
///
/// Audio can be requested from any node in the **Graph** using the
/// [`audio_requested_from`](./struct.Graph.html#method.audio_requested_from) method.
///
/// When [`audio_requested`](../node/trait.Node.html#method.audio_requested) is called on the
/// **Graph**, audio will be requested from the node specified by the index at `maybe_master`. If
/// `maybe_master` is `None`, audio will be requested from the first, input-only node found - that
/// is, the first node that is found with only input connections and no outputs.
///
/// **NodeIndex** is a type that acts as a reference to a node, while **EdgeIndex** is a type that
/// acts as a reference to an edge (which in this case describes a *src -> dest* **Connection**
/// between two nodes). It should be noted that these are only stable across certain operations.
/// **Removing indices may shift other indices of the same type!** Adding nodes or edges to the
/// **Graph** keeps all indices stable, but removing a node or edge will force the last node/edge
/// to shift its index to take its place.
///
/// **Graph** also offers methods for accessing its underlying **Dag** or **PetGraph**.
#[derive(Clone, Debug)]
pub struct Graph<F, N> {
dag: Dag<F, N>,
/// The order in which audio will be requested from each node.
visit_order: Vec<NodeIndex>,
/// The node from which audio will be requested upon a call to `Node::audio_requested`.
maybe_master: Option<NodeIndex>,
/// A buffer to re-use when mixing the dry and wet signals when audio is requested.
dry_buffer: Vec<F>,
}
/// Describes a connection between two Nodes within the Graph: *input -> connection -> output*.
///
/// **Graph**'s API only allows for read-only access to **Connection**s, so you can be sure that
/// their buffers always represent the last frames rendered by their input node.
#[derive(Clone, Debug)]
pub struct Connection<F> {
/// The buffer used to pass audio between nodes.
///
/// After `Graph::audio_requested_from` is called, this buffer will contain the audio rendered
/// by the **Connection**'s input node.
pub buffer: Vec<F>,
}
/// The error returned when adding an edge that would create a cycle.
#[derive(Copy, Clone, Debug)]
pub struct WouldCycle;
/// A walker object for walking over nodes that are inputs to some node.
pub struct Inputs<F, N> {
parents: daggy::Parents<N, Connection<F>, usize>,
}
/// A walker object for walking over nodes that are outputs to some node.
pub struct Outputs<F, N> {
children: daggy::Children<N, Connection<F>, usize>,
}
/// A walker type for walking over a **Graph**'s nodes in the order in which they will visited when
/// audio is requested from the **Graph**.
pub struct VisitOrder {
current_visit_order_idx: usize,
}
/// A walker type for walking over a **Graph**'s nodes in the order in which they will visited when
/// audio is requested from the **Graph**.
pub struct VisitOrderReverse {
current_visit_order_idx: usize,
}
impl<F, N> Graph<F, N>
where
F: Frame,
N: Node<F>,
{
/// Constructor for a new dsp Graph.
///
/// [`with_capacity`](./struct.Graph.html#method.with_capacity) is recommended if you have a
/// rough idea of the number of nodes, connections and frames per buffer upon the **Graph**'s
/// instantiation.
pub fn new() -> Self {
let dag = daggy::Dag::new();
Graph {
dag: dag,
visit_order: Vec::new(),
dry_buffer: Vec::new(),
maybe_master: None,
}
}
/// Constructor for a new dsp Graph with some minimum capacity.
///
/// - **nodes** is the capacity for the underlying **Dag**'s node `Vec`.
/// - **connections** is the capacity for the underlying **Dag**'s edge `Vec`.
/// - **frames_per_buffer** is the capacity for the **Graph**'s `dry_buffer`, which is used
/// for mixing the dry and wet signals when `Node::audio_requested` is called.
pub fn with_capacity(nodes: usize, connections: usize, frames_per_buffer: usize) -> Self {
Graph {
dag: daggy::Dag::with_capacity(nodes, connections),
visit_order: Vec::with_capacity(nodes),
dry_buffer: Vec::with_capacity(frames_per_buffer),
maybe_master: None,
}
}
/// A reference to the underlying **Dag**.
pub fn dag(&self) -> &Dag<F, N> {
&self.dag
}
/// Takes ownership of the **Graph** and returns the underlying **Dag**.
pub fn into_dag(self) -> Dag<F, N> {
let Graph { dag, .. } = self;
dag
}
/// A reference to the internal **Dag**'s underlying **PetGraph**.
pub fn pet_graph(&self) -> &PetGraph<F, N> {
self.dag.graph()
}
/// Takes ownership of the **Graph** and returns the internal **Dag**'s underlying **PetGraph**.
pub fn into_pet_graph(self) -> PetGraph<F, N> {
self.into_dag().into_graph()
}
/// The total number of nodes in the **Graph**.
pub fn node_count(&self) -> usize {
self.dag.node_count()
}
/// The total number of connections in the **Graph**.
pub fn connection_count(&self) -> usize {
self.dag.edge_count()
}
/// Return the **Graph**'s master index if there is one.
///
/// **Graph**'s **Node** implementation will request audio from the node at `maybe_master`
/// when the `Node::audio_requested` method is called.
pub fn master_index(&self) -> Option<NodeIndex> {
self.maybe_master
}
/// Set the master node for the **Graph**.
///
/// **Graph** will check to see if a node exists for the given index before assigning.
///
/// **Graph**'s **Node** implementation will request audio from the node at `maybe_master`
/// when the `Node::audio_requested` method is called.
pub fn set_master(&mut self, maybe_index: Option<NodeIndex>) {
let maybe_index = maybe_index.and_then(|index| {
if self.dag.node_weight(index).is_some() {
Some(index)
} else {
None
}
});
self.maybe_master = maybe_index;
self.prepare_visit_order();
}
/// Add a node to the dsp graph.
///
/// This computes in **O(1)** time.
pub fn add_node(&mut self, node: N) -> NodeIndex {
let idx = self.dag.add_node(node);
idx
}
/// A reference to the node at the given index (or `None` if it doesn't exist).
pub fn node(&self, node: NodeIndex) -> Option<&N> {
self.dag.node_weight(node)
}
/// A mutable reference to the node at the given index (or `None` if it doesn't exist).
pub fn node_mut(&mut self, node: NodeIndex) -> Option<&mut N> {
self.dag.node_weight_mut(node)
}
/// Read only access to the internal node array.
pub fn raw_nodes(&self) -> RawNodes<N> {
self.dag.raw_nodes()
}
/// An iterator yielding mutable access to all nodes.
///
/// The order in which nodes are yielded matches the order of their indices.
pub fn nodes_mut(&mut self) -> NodesMut<N> {
self.dag.node_weights_mut()
}
/// A reference to the connection at the given index (or `None` if it doesn't exist).
pub fn connection(&self, edge: EdgeIndex) -> Option<&Connection<F>> {
self.dag.edge_weight(edge)
}
/// Read only access to the internal edge array.
pub fn raw_edges(&self) -> RawEdges<F> {
self.dag.raw_edges()
}
/// Index the **Graph** by two `NodeIndex`s at once.
///
/// **Panics** if the indices are equal or if they are out of bounds.
pub fn index_twice_mut(&mut self, a: NodeIndex, b: NodeIndex) -> (&mut N, &mut N) {
self.dag.index_twice_mut(a, b)
}
/// Remove a node from the dsp graph.
///
/// Resets the master to None if the index matches the current master index.
///
/// **Note:** This method may shift (and in turn invalidate) previously returned node indices!
///
/// **Graph** will re-prepare its visit order if some node was removed.
pub fn remove_node(&mut self, idx: NodeIndex) -> Option<N> {
if self.maybe_master == Some(idx) {
self.maybe_master = None;
}
self.dag.remove_node(idx).map(|node| {
self.prepare_visit_order();
node
})
}
/// Adds an edge from `src` to `dest`. That is, `src` is now an input to `dest`.
///
/// Returns an error instead if the input would create a cycle in the graph.
///
/// **Graph** will re-prepare its visit order if some connection was successfully added.
///
/// If you're using `add_node` followed by this method, consider using
/// [`add_input`](./struct.Graph.html#method.add_input) or
/// [`add_output`](./struct.Graph.html#method.add_output) instead for greater performance.
/// This is because when adding a new node and edge simultaneously, we don't have to check
/// whether adding the edge would create a cycle.
///
/// **Panics** if there is no node for either `src` or `dest`.
///
/// **Panics** if the Graph is at the maximum number of edges for its index.
pub fn add_connection(
&mut self,
src: NodeIndex,
dest: NodeIndex,
) -> Result<EdgeIndex, WouldCycle> {
self.dag
.add_edge(src, dest, Connection { buffer: Vec::new() })
.map(|edge| {
self.prepare_visit_order();
edge
})
.map_err(|_| WouldCycle)
}
/// The same as [`add_connection`](./struct.Graph.html#method.add_connection) but adds
/// multiple connections to the **Graph**. Rather than checking for introduced cycles and
/// re-preparing the visit order after adding each edge, we only do so after **all** edges are
/// added. Thus, this is a far more efficient alternative to repeatedly calling the
/// `add_connection` method.
///
/// Returns an error instead if any of the connections would create a cycle in the graph.
///
/// **Graph** will re-prepare its visit order if the connections were successfully added.
///
/// If you're using `add_node` followed by this method, consider using
/// [`add_input`](./struct.Graph.html#method.add_input) or
/// [`add_output`](./struct.Graph.html#method.add_output) instead for greater performance.
/// This is because when adding a new node and edge simultaneously, we don't have to check
/// whether adding the edge would create a cycle.
///
/// **Panics** if there is no node for either `src` or `dest`.
///
/// **Panics** if the Graph is at the maximum number of edges for its index.
pub fn add_connections<I>(&mut self, connections: I) -> Result<EdgeIndices, WouldCycle>
where
I: ::std::iter::IntoIterator<Item = (NodeIndex, NodeIndex)>,
{
fn new_connection<F>() -> Connection<F> {
Connection { buffer: Vec::new() }
}
self.dag
.add_edges(
connections
.into_iter()
.map(|(src, dest)| (src, dest, new_connection())),
)
.map(|edges| {
self.prepare_visit_order();
edges
})
.map_err(|_| WouldCycle)
}
/// Find and return the index to the edge that describes the connection where `src` is an input
/// to `dest`.
///
/// Computes in **O(e')** time, where **e'** is the number of edges connected to the nodes `a`
/// and `b`.
pub fn find_connection(&self, src: NodeIndex, dest: NodeIndex) -> Option<EdgeIndex> {
self.dag.find_edge(src, dest)
}
/// Remove the connection described by the edge at the given index.
///
/// Returns true if an edge was removed, returns false if there was no edge at the given index.
///
/// Re-prepares the visit order if some edge was removed.
pub fn remove_edge(&mut self, edge: EdgeIndex) -> bool {
if self.dag.remove_edge(edge).is_some() {
self.prepare_visit_order();
true
} else {
false
}
}
/// Find and remove any connection between a and b if there is one, whether it is *a -> b* or
/// *b -> a*. We know that their may only be one edge as our API does not allow for creating a
/// cyclic graph.
///
/// Returns true if an edge was removed, returns false if there was no edge at the given index.
///
/// Graph will re-prepare its visit order if some edge was removed.
///
/// Note: If you have an index to the edge you want to remove,
/// [`remove_edge`](./struct.Graph.html#method.remove_edge) is a more performant option.
pub fn remove_connection(&mut self, a: NodeIndex, b: NodeIndex) -> bool {
match self
.dag
.find_edge(a, b)
.or_else(|| self.dag.find_edge(b, a))
{
Some(edge) => self.remove_edge(edge),
None => false,
}
}
/// Add a new node weight to the graph as an input to the wait at the given `dest` node index.
///
/// *src -> new edge -> dest*
///
/// Returns an index to both the new `src` node and the edge that represents the new connection
/// between it and the node at `dest`.
///
/// Computes in **O(n)** time where n is the number of nodes. This is because must update the
/// visit order after adding the new connection.
///
/// **Panics** if there is no node for the given `dest` index.
///
/// **Panics** if the Graph is at the maximum number of edges for its index.
pub fn add_input(&mut self, src: N, dest: NodeIndex) -> (EdgeIndex, NodeIndex) {
let indices = self
.dag
.add_parent(dest, Connection { buffer: Vec::new() }, src);
self.prepare_visit_order();
indices
}
/// Add a new node weight to the graph as an output to the wait at the given `src` node index.
///
/// *src -> new edge -> dest*
///
/// Returns an index to both the new `dest` node and the edge that represents the new connection
/// between it and the node at `src`.
///
/// Computes in **O(n)** time where n is the number of nodes. This is because must update the
/// visit order after adding the new connection.
///
/// **Panics** if there is no node for the given `dest` index.
///
/// **Panics** if the Graph is at the maximum number of edges for its index.
pub fn add_output(&mut self, src: NodeIndex, dest: N) -> (EdgeIndex, NodeIndex) {
let indices = self
.dag
.add_child(src, Connection { buffer: Vec::new() }, dest);
self.prepare_visit_order();
indices
}
/// A "walker" object that may be used to step through the inputs of the given node.
///
/// Unlike the `Inputs` type, `WalkInputs` does not borrow the `Graph`.
///
/// Can be converted to an iterator using `.iter()`.
pub fn inputs(&self, idx: NodeIndex) -> Inputs<F, N> {
Inputs {
parents: self.dag.parents(idx),
}
}
/// A "walker" object that may be used to step through the outputs of the given node.
///
/// Unlike the `Outputs` type, `WalkOutputs` does not borrow the **Graph**.
///
/// Can be converted to an iterator using `.iter()`.
pub fn outputs(&self, idx: NodeIndex) -> Outputs<F, N> {
Outputs {
children: self.dag.children(idx),
}
}
/// A "walker" type that may be used to step through all node indices in the order in which
/// they will be visited when audio is requested from the **Graph**.
pub fn visit_order(&self) -> VisitOrder {
VisitOrder {
current_visit_order_idx: 0,
}
}
/// A "walker" type that may be used to step through all node indices in the order in which
/// they will be visited when audio is requested from the **Graph**.
///
/// Unlike the VisitOrder type, VisitOrder does not borrow the **Graph**.
pub fn visit_order_rev(&self) -> VisitOrderReverse {
VisitOrderReverse {
current_visit_order_idx: self.visit_order.len(),
}
}
/// Remove all incoming connections to the node at the given index.
///
/// Return the number of connections removed.
pub fn remove_all_input_connections(&mut self, idx: NodeIndex) -> usize {
let mut inputs = self.inputs(idx);
let mut num = 0;
while let Some(connection) = inputs.next_edge(&self) {
self.remove_edge(connection);
num += 1;
}
num
}
/// Remove all outgoing connections from the node at the given index.
///
/// Return the number of connections removed.
pub fn remove_all_output_connections(&mut self, idx: NodeIndex) -> usize {
let mut outputs = self.outputs(idx);
let mut num = 0;
while let Some(connection) = outputs.next_edge(&self) {
self.remove_edge(connection);
num += 1;
}
num
}
/// Clear all dsp nodes that have no inputs or outputs.
///
/// Returns the number of nodes removed.
///
/// Note: this may shift (and in turn invalidate) previously returned node and edge indices!
pub fn clear_disconnected(&mut self) -> usize {
let mut num_removed = 0;
for i in 0..self.dag.node_count() {
let idx = NodeIndex::new(i);
let num_inputs = self.inputs(idx).count(self);
let num_outputs = self.outputs(idx).count(self);
if num_inputs == 0 && num_outputs == 0 {
if self.maybe_master == Some(idx) {
self.maybe_master = None;
}
self.dag.remove_node(idx);
num_removed += 1;
}
}
num_removed
}
/// Clear all dsp nodes.
pub fn clear(&mut self) {
self.dag.clear();
self.visit_order.clear();
self.maybe_master = None;
}
/// Prepare the buffers for all nodes within the Graph.
pub fn prepare_buffers(&mut self, buffer_size: usize) {
// Initialise the dry signal buffer.
resize_buffer_to(&mut self.dry_buffer, buffer_size);
// Initialise all connection buffers.
for connection in self.dag.edge_weights_mut() {
resize_buffer_to(&mut connection.buffer, buffer_size);
}
}
/// Request audio from the node at the given index.
///
/// **Panics** if there is no node for the given index.
pub fn audio_requested_from(&mut self, out_node: NodeIndex, output: &mut [F], sample_hz: f64) {
// We can only go on if a node actually exists for the given index.
if self.node(out_node).is_none() {
panic!("No node for the given index");
}
let buffer_size = output.len();
// Ensure the dry_buffer is the same length as the output buffer.
if self.dry_buffer.len() != buffer_size {
resize_buffer_to(&mut self.dry_buffer, buffer_size);
}
let mut visit_order = self.visit_order();
while let Some(node_idx) = visit_order.next(self) {
// Set the buffers to equilibrium, ready to sum the inputs of the current node.
for i in 0..buffer_size {
output[i] = F::equilibrium();
self.dry_buffer[i] = F::equilibrium();
}
// Walk over each of the input connections to sum their buffers to the output.
let mut inputs = self.inputs(node_idx);
while let Some(connection_idx) = inputs.next_edge(self) {
let connection = &self[connection_idx];
// Sum the connection's buffer onto the output.
//
// We can be certain that `connection`'s buffer is the same size as the
// `output` buffer as all connections are visited from their input nodes
// (towards the end of the visit_order while loop) before being visited here
// by their output nodes.
sample::slice::zip_map_in_place(
output,
&connection.buffer,
|out_frame, con_frame| {
out_frame.zip_map(con_frame, |out_sample, con_sample| {
let out_signed =
out_sample.to_sample::<<F::Sample as Sample>::Signed>();
let con_signed =
con_sample.to_sample::<<F::Sample as Sample>::Signed>();
(out_signed + con_signed).to_sample::<F::Sample>()
})
},
);
}
// Store the dry signal in the dry buffer for later summing.
sample::slice::write(&mut self.dry_buffer, output);
// Render the audio with the current node and sum the dry and wet signals.
let (dry, wet) = {
let node = &mut self[node_idx];
// Render our `output` buffer with the current node.
// The `output` buffer is now representative of a fully wet signal.
node.audio_requested(output, sample_hz);
let dry = node.dry();
let wet = node.wet();
(dry, wet)
};
// Combine the dry and wet signals.
sample::slice::zip_map_in_place(output, &self.dry_buffer, |f_wet, f_dry| {
f_wet.zip_map(f_dry, |s_wet, s_dry| {
let wet = s_wet.mul_amp(wet);
let dry = s_dry.mul_amp(dry);
wet.add_amp(dry.to_sample())
})
});
// If we've reached our output node, we're done!
if node_idx == out_node {
return;
}
// Walk over each of the outgoing connections and write the rendered output to them.
let mut outputs = self.outputs(node_idx);
while let Some(connection_idx) = outputs.next_edge(self) {
let connection = &mut self.dag[connection_idx];
// Ensure the buffer matches the target length.
if connection.buffer.len() != output.len() {
resize_buffer_to(&mut connection.buffer, output.len());
}
// Write the rendered audio to the outgoing connection buffers.
sample::slice::write(&mut connection.buffer, output);
}
}
}
/// Prepare the visit order for the graph in its current state.
///
/// This is called whenever the **Graph** is mutated in some way that may change the flow of
/// its edges.
///
/// When audio is requested from the graph, we need to iterate through all nodes so that all
/// child nodes are visited before their parents. To do this, we can use petgraph's toposort
/// algorithm to return the topological order of our graph.
///
/// The user should never have to worry about this, thus the method is private.
fn prepare_visit_order(&mut self) {
self.visit_order = daggy::petgraph::algo::toposort(self.dag.graph());
}
}
impl<F, N> ::std::ops::Index<NodeIndex> for Graph<F, N> {
type Output = N;
#[inline]
fn index<'a>(&'a self, index: NodeIndex) -> &'a N {
&self.dag[index]
}
}
impl<F, N> ::std::ops::IndexMut<NodeIndex> for Graph<F, N> {
#[inline]
fn index_mut(&mut self, index: NodeIndex) -> &mut N {
&mut self.dag[index]
}
}
impl<F, N> ::std::ops::Index<EdgeIndex> for Graph<F, N> {
type Output = Connection<F>;
#[inline]
fn index<'a>(&'a self, index: EdgeIndex) -> &'a Connection<F> {
&self.dag[index]
}
}
impl<F, N> Node<F> for Graph<F, N>
where
F: Frame,
N: Node<F>,
{
fn audio_requested(&mut self, output: &mut [F], sample_hz: f64) {
match self.maybe_master {
Some(master) => self.audio_requested_from(master, output, sample_hz),
None => {
// If there is no set master node, we'll start from the back of the visit_order and
// use the first node that has no output connections.
let mut visit_order_rev = self.visit_order_rev();
while let Some(node) = visit_order_rev.next(self) {
if self.inputs(node).count(self) == 0 {
self.audio_requested_from(node, output, sample_hz);
return;
}
}
}
}
}
}
impl<F, N> Walker<Graph<F, N>> for Inputs<F, N> {
type Index = usize;
/// The next (connection, node) input pair to some node in our walk for the given **Graph**.
#[inline]
fn next(&mut self, graph: &Graph<F, N>) -> Option<(EdgeIndex, NodeIndex)> {
self.parents.next(&graph.dag)
}
/// The next input connection to some node in our walk for the given **Graph**.
#[inline]
fn next_edge(&mut self, graph: &Graph<F, N>) -> Option<EdgeIndex> {
self.parents.next_edge(&graph.dag)
}
/// The next input node to some node in our walk for the given **Graph**.
#[inline]
fn next_node(&mut self, graph: &Graph<F, N>) -> Option<NodeIndex> {
self.parents.next_node(&graph.dag)
}
}
impl<F, N> Walker<Graph<F, N>> for Outputs<F, N> {
type Index = usize;
/// The next (connection, node) output pair from some node in our walk for the given **Graph**.
#[inline]
fn next(&mut self, graph: &Graph<F, N>) -> Option<(EdgeIndex, NodeIndex)> {
self.children.next(&graph.dag)
}
/// The next output connection from some node in our walk for the given **Graph**.
#[inline]
fn next_edge(&mut self, graph: &Graph<F, N>) -> Option<EdgeIndex> {
self.children.next_edge(&graph.dag)
}
/// The next output node from some node in our walk for the given **Graph**.
#[inline]
fn next_node(&mut self, graph: &Graph<F, N>) -> Option<NodeIndex> {
self.children.next_node(&graph.dag)
}
}
impl VisitOrder {
/// The index of the next node that would be visited during audio requested in our walk of the
/// given **Graph**'s visit order.
#[inline]
pub fn next<F, N>(&mut self, graph: &Graph<F, N>) -> Option<NodeIndex> {
graph
.visit_order
.get(self.current_visit_order_idx)
.map(|&idx| {
self.current_visit_order_idx += 1;
idx
})
}
}
impl VisitOrderReverse {
/// The index of the next node that would be visited during audio requested in our walk of the
/// given **Graph**'s visit order.
#[inline]
pub fn next<F, N>(&mut self, graph: &Graph<F, N>) -> Option<NodeIndex> {
if self.current_visit_order_idx > 0 {
self.current_visit_order_idx -= 1;
graph
.visit_order
.get(self.current_visit_order_idx)
.map(|&idx| idx)
} else {
None
}
}
}
/// Resize the given buffer to the given target length.
fn resize_buffer_to<F>(buffer: &mut Vec<F>, target_len: usize)
where
F: Frame,
{
let len = buffer.len();
if len < target_len {
buffer.extend((len..target_len).map(|_| F::equilibrium()))
} else if len > target_len {
buffer.truncate(target_len);
}
}
impl ::std::fmt::Display for WouldCycle {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
writeln!(f, "{:?}", self)
}
}
impl ::std::error::Error for WouldCycle {
fn description(&self) -> &str {
"Adding this input would have caused the graph to cycle!"
}
}