use daggy::{self, Walker};
use node::Node;
use sample::{self, Frame, Sample};
pub type NodeIndex = daggy::NodeIndex<usize>;
pub type EdgeIndex = daggy::EdgeIndex<usize>;
pub type NodesMut<'a, N> = daggy::NodeWeightsMut<'a, N, usize>;
pub type RawNodes<'a, N> = daggy::RawNodes<'a, N, usize>;
pub type RawEdges<'a, F> = daggy::RawEdges<'a, Connection<F>, usize>;
pub type EdgeIndices = daggy::EdgeIndices<usize>;
pub type Dag<F, N> = daggy::Dag<N, Connection<F>, usize>;
pub type PetGraph<F, N> = daggy::PetGraph<N, Connection<F>, usize>;
#[derive(Clone, Debug)]
pub struct Graph<F, N> {
dag: Dag<F, N>,
visit_order: Vec<NodeIndex>,
maybe_master: Option<NodeIndex>,
dry_buffer: Vec<F>,
}
#[derive(Clone, Debug)]
pub struct Connection<F> {
pub buffer: Vec<F>,
}
#[derive(Copy, Clone, Debug)]
pub struct WouldCycle;
pub struct Inputs<F, N> {
parents: daggy::Parents<N, Connection<F>, usize>,
}
pub struct Outputs<F, N> {
children: daggy::Children<N, Connection<F>, usize>,
}
pub struct VisitOrder {
current_visit_order_idx: usize,
}
pub struct VisitOrderReverse {
current_visit_order_idx: usize,
}
impl<F, N> Graph<F, N>
where F: Frame, N: Node<F>
{
pub fn new() -> Self {
let dag = daggy::Dag::new();
Graph {
dag: dag,
visit_order: Vec::new(),
dry_buffer: Vec::new(),
maybe_master: None,
}
}
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,
}
}
pub fn dag(&self) -> &Dag<F, N> {
&self.dag
}
pub fn into_dag(self) -> Dag<F, N> {
let Graph { dag, .. } = self;
dag
}
pub fn pet_graph(&self) -> &PetGraph<F, N> {
self.dag.graph()
}
pub fn into_pet_graph(self) -> PetGraph<F, N> {
self.into_dag().into_graph()
}
pub fn node_count(&self) -> usize {
self.dag.node_count()
}
pub fn connection_count(&self) -> usize {
self.dag.edge_count()
}
pub fn master_index(&self) -> Option<NodeIndex> {
self.maybe_master
}
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();
}
pub fn add_node(&mut self, node: N) -> NodeIndex {
let idx = self.dag.add_node(node);
idx
}
pub fn node(&self, node: NodeIndex) -> Option<&N> {
self.dag.node_weight(node)
}
pub fn node_mut(&mut self, node: NodeIndex) -> Option<&mut N> {
self.dag.node_weight_mut(node)
}
pub fn raw_nodes(&self) -> RawNodes<N> {
self.dag.raw_nodes()
}
pub fn nodes_mut(&mut self) -> NodesMut<N> {
self.dag.node_weights_mut()
}
pub fn connection(&self, edge: EdgeIndex) -> Option<&Connection<F>> {
self.dag.edge_weight(edge)
}
pub fn raw_edges(&self) -> RawEdges<F> {
self.dag.raw_edges()
}
pub fn index_twice_mut(&mut self, a: NodeIndex, b: NodeIndex) -> (&mut N, &mut N) {
self.dag.index_twice_mut(a, b)
}
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
})
}
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)
}
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)
}
pub fn find_connection(&self, src: NodeIndex, dest: NodeIndex) -> Option<EdgeIndex> {
self.dag.find_edge(src, dest)
}
pub fn remove_edge(&mut self, edge: EdgeIndex) -> bool {
if self.dag.remove_edge(edge).is_some() {
self.prepare_visit_order();
true
} else {
false
}
}
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,
}
}
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
}
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
}
pub fn inputs(&self, idx: NodeIndex) -> Inputs<F, N> {
Inputs { parents: self.dag.parents(idx) }
}
pub fn outputs(&self, idx: NodeIndex) -> Outputs<F, N> {
Outputs { children: self.dag.children(idx) }
}
pub fn visit_order(&self) -> VisitOrder {
VisitOrder { current_visit_order_idx: 0 }
}
pub fn visit_order_rev(&self) -> VisitOrderReverse {
VisitOrderReverse { current_visit_order_idx: self.visit_order.len() }
}
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
}
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
}
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
}
pub fn clear(&mut self) {
self.dag.clear();
self.visit_order.clear();
self.maybe_master = None;
}
pub fn prepare_buffers(&mut self, buffer_size: usize) {
resize_buffer_to(&mut self.dry_buffer, buffer_size);
for connection in self.dag.edge_weights_mut() {
resize_buffer_to(&mut connection.buffer, buffer_size);
}
}
pub fn audio_requested_from(&mut self, out_node: NodeIndex, output: &mut [F], sample_hz: f64) {
if self.node(out_node).is_none() {
panic!("No node for the given index");
}
let buffer_size = output.len();
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) {
for i in 0..buffer_size {
output[i] = F::equilibrium();
self.dry_buffer[i] = F::equilibrium();
}
let mut inputs = self.inputs(node_idx);
while let Some(connection_idx) = inputs.next_edge(self) {
let connection = &self[connection_idx];
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>()
})
});
}
sample::slice::write(&mut self.dry_buffer, output);
let (dry, wet) = {
let node = &mut self[node_idx];
node.audio_requested(output, sample_hz);
let dry = node.dry();
let wet = node.wet();
(dry, wet)
};
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 node_idx == out_node {
return;
}
let mut outputs = self.outputs(node_idx);
while let Some(connection_idx) = outputs.next_edge(self) {
let connection = &mut self.dag[connection_idx];
if connection.buffer.len() != output.len() {
resize_buffer_to(&mut connection.buffer, output.len());
}
sample::slice::write(&mut connection.buffer, output);
}
}
}
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 => {
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;
#[inline]
fn next(&mut self, graph: &Graph<F, N>) -> Option<(EdgeIndex, NodeIndex)> {
self.parents.next(&graph.dag)
}
#[inline]
fn next_edge(&mut self, graph: &Graph<F, N>) -> Option<EdgeIndex> {
self.parents.next_edge(&graph.dag)
}
#[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;
#[inline]
fn next(&mut self, graph: &Graph<F, N>) -> Option<(EdgeIndex, NodeIndex)> {
self.children.next(&graph.dag)
}
#[inline]
fn next_edge(&mut self, graph: &Graph<F, N>) -> Option<EdgeIndex> {
self.children.next_edge(&graph.dag)
}
#[inline]
fn next_node(&mut self, graph: &Graph<F, N>) -> Option<NodeIndex> {
self.children.next_node(&graph.dag)
}
}
impl VisitOrder {
#[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 {
#[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
}
}
}
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!"
}
}