use node::Node;
use petgraph as pg;
use sound_stream::{Sample, Settings};
#[derive(Clone, Debug)]
pub struct Graph<S, N> {
graph: pg::Graph<Slot<S, N>, ()>,
maybe_master: Option<NodeIndex>,
}
#[derive(Clone, Debug)]
struct Slot<S, N> {
node: N,
buffer: Vec<S>,
is_rendered: bool,
}
pub type NodeIndex = pg::graph::NodeIndex<u32>;
#[derive(Copy, Clone, Debug)]
pub struct WouldCycle;
pub type Inputs<'a, S, N> = Neighbors<'a, S, N>;
pub type InputsWithIndices<'a, S, N> = NeighborsWithIndices<'a, S, N>;
pub type InputsMut<'a, S, N> = NeighborsMut<'a, S, N>;
pub type InputsMutWithIndices<'a, S, N> = NeighborsMutWithIndices<'a, S, N>;
pub type Outputs<'a, S, N> = Neighbors<'a, S, N>;
pub type OutputsWithIndices<'a, S, N> = NeighborsWithIndices<'a, S, N>;
pub type OutputsMut<'a, S, N> = NeighborsMut<'a, S, N>;
pub type OutputsMutWithIndices<'a, S, N> = NeighborsMutWithIndices<'a, S, N>;
pub struct Neighbors<'a, S: 'a, N: 'a> {
graph: &'a pg::Graph<Slot<S, N>, ()>,
neighbors: pg::graph::Neighbors<'a, (), u32>,
}
pub struct NeighborsWithIndices<'a, S: 'a, N: 'a> {
graph: &'a pg::Graph<Slot<S, N>, ()>,
neighbors: pg::graph::Neighbors<'a, (), u32>,
}
pub struct NeighborsMut<'a, S: 'a, N: 'a> {
graph: &'a mut pg::Graph<Slot<S, N>, ()>,
neighbors: pg::graph::Neighbors<'a, (), u32>,
}
pub struct NeighborsMutWithIndices<'a, S: 'a, N: 'a> {
graph: &'a mut pg::Graph<Slot<S, N>, ()>,
neighbors: pg::graph::Neighbors<'a, (), u32>,
}
impl<S, N> Graph<S, N> where S: Sample, N: Node<S> {
pub fn new() -> Graph<S, N> {
let graph = pg::Graph::new();
Graph {
graph: graph,
maybe_master: None,
}
}
pub fn set_master(&mut self, maybe_index: Option<NodeIndex>) {
let maybe_index = match maybe_index {
Some(index) => match self.graph.node_weight(index) {
Some(_) => Some(index),
None => None,
},
None => None,
};
self.maybe_master = maybe_index;
}
pub fn master_index(&self) -> Option<NodeIndex> {
self.maybe_master
}
pub fn add_node(&mut self, node: N) -> NodeIndex {
self.graph.add_node(Slot {
node: node,
buffer: Vec::new(),
is_rendered: false,
})
}
pub fn remove_node(&mut self, idx: NodeIndex) -> Option<N> {
if let Some(master_idx) = self.maybe_master {
if idx == master_idx {
self.maybe_master = None;
}
}
self.graph.remove_node(idx).map(|slot| {
let Slot { node, .. } = slot;
node
})
}
pub fn add_input(&mut self, a: NodeIndex, b: NodeIndex) -> Result<(), WouldCycle> {
let edge = self.graph.add_edge(a, b, ());
if pg::algo::is_cyclic_directed(&self.graph) {
self.graph.remove_edge(edge);
Err(WouldCycle)
} else {
Ok(())
}
}
pub fn remove_input(&mut self, a: NodeIndex, b: NodeIndex) {
if let Some(edge) = self.graph.find_edge(a, b) {
self.graph.remove_edge(edge);
} else if let Some(edge) = self.graph.find_edge(b, a) {
self.graph.remove_edge(edge);
}
}
fn neighbors<'a>(&'a self, idx: NodeIndex,
direction: pg::EdgeDirection) -> Neighbors<'a, S, N> {
Neighbors {
graph: &self.graph,
neighbors: self.graph.neighbors_directed(idx, direction),
}
}
fn neighbors_mut<'a>(&'a mut self, idx: NodeIndex,
direction: pg::EdgeDirection) -> NeighborsMut<'a, S, N> {
let graph = &mut self.graph as *mut pg::Graph<Slot<S, N>, ()>;
NeighborsMut {
graph: unsafe { ::std::mem::transmute(graph) },
neighbors: unsafe { (*graph).neighbors_directed(idx, direction) },
}
}
pub fn inputs<'a>(&'a self, idx: NodeIndex) -> Inputs<'a, S, N> {
self.neighbors(idx, pg::Incoming)
}
pub fn inputs_mut<'a>(&'a mut self, idx: NodeIndex) -> InputsMut<'a, S, N> {
self.neighbors_mut(idx, pg::Incoming)
}
pub fn outputs<'a>(&'a self, idx: NodeIndex) -> Outputs<'a, S, N> {
self.neighbors(idx, pg::Outgoing)
}
pub fn outputs_mut<'a>(&'a mut self, idx: NodeIndex) -> OutputsMut<'a, S, N> {
self.neighbors_mut(idx, pg::Outgoing)
}
pub fn audio_requested_from_node(&mut self,
idx: NodeIndex,
output: &mut[S],
settings: Settings) {
request_audio_from_graph(&mut self.graph, idx, output, settings);
self.reset_buffers();
}
pub fn remove_all_inputs(&mut self, idx: NodeIndex) -> usize {
let input_indices: Vec<_> = self.graph.neighbors_directed(idx, pg::Incoming).collect();
let num = input_indices.len();
for input_idx in input_indices {
self.remove_input(input_idx, idx);
}
num
}
pub fn remove_all_outputs(&mut self, idx: NodeIndex) -> usize {
let output_indices: Vec<_> = self.graph.neighbors_directed(idx, pg::Outgoing).collect();
let num = output_indices.len();
for output_idx in output_indices {
self.remove_input(output_idx, idx);
}
num
}
pub fn clear_disconnected(&mut self) {
let no_incoming: Vec<_> = self.graph.without_edges(pg::Incoming).collect();
let no_outgoing: Vec<_> = self.graph.without_edges(pg::Outgoing).collect();
let indices_for_removal = no_incoming.into_iter()
.filter(|incoming| no_outgoing.iter().any(|outgoing| outgoing == incoming));
for idx in indices_for_removal {
if let Some(master_idx) = self.maybe_master {
if master_idx == idx {
self.maybe_master = None;
}
}
self.graph.remove_node(idx);
}
}
pub fn clear(&mut self) {
self.graph.clear();
self.maybe_master = None;
}
pub fn prepare_buffers(&mut self, settings: Settings) {
let target_len = settings.buffer_size();
for node in self.graph.node_weights_mut() {
let len = node.buffer.len();
if len < target_len {
node.buffer.extend((len..target_len).map(|_| Sample::zero()));
} else if len > target_len {
node.buffer.truncate(target_len);
}
}
}
fn reset_buffers(&mut self) {
for node in self.graph.node_weights_mut() {
node.is_rendered = false;
}
}
}
impl<S, N> ::std::ops::Index<NodeIndex> for Graph<S, N> {
type Output = N;
#[inline]
fn index<'a>(&'a self, index: NodeIndex) -> &'a N {
&self.graph[index].node
}
}
impl<S, N> ::std::ops::IndexMut<NodeIndex> for Graph<S, N> {
#[inline]
fn index_mut(&mut self, index: NodeIndex) -> &mut N {
&mut self.graph[index].node
}
}
impl<S, N> Node<S> for Graph<S, N>
where
S: Sample,
N: Node<S>,
{
fn audio_requested(&mut self, output: &mut [S], settings: Settings) {
if let Some(idx) = self.maybe_master {
self.audio_requested_from_node(idx, output, settings);
}
}
}
#[inline]
fn request_audio_from_graph<S, N>(graph: &mut pg::Graph<Slot<S, N>, ()>,
idx: pg::graph::NodeIndex,
output: &mut [S],
settings: Settings)
where
S: Sample,
N: Node<S>,
{
let graph = graph as *mut pg::Graph<Slot<S, N>, ()>;
let &mut Slot { ref mut node, ref mut buffer, ref mut is_rendered } = unsafe {
&mut(*graph)[idx]
};
if !*is_rendered {
if buffer.len() != output.len() {
let len = buffer.len();
let target_len = output.len();
if len < target_len {
buffer.extend((len..target_len).map(|_| Sample::zero()));
} else if len > target_len {
buffer.truncate(target_len);
}
}
for sample in buffer.iter_mut() {
*sample = Sample::zero();
}
let inputs = unsafe { (*graph).neighbors_directed(idx, pg::Incoming) };
for neighbor_idx in inputs {
let graph: &mut pg::Graph<Slot<S, N>, ()> = unsafe { ::std::mem::transmute(graph) };
request_audio_from_graph(graph, neighbor_idx, buffer, settings);
}
node.audio_requested(buffer, settings);
*is_rendered = true;
}
for (output_sample, sample) in output.iter_mut().zip(buffer.iter()) {
*output_sample = *output_sample + *sample;
}
}
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!"
}
}
impl<'a, S, N> Neighbors<'a, S, N> {
#[inline]
pub fn with_indices(self) -> NeighborsWithIndices<'a, S, N> {
let Neighbors { graph, neighbors } = self;
NeighborsWithIndices {
graph: graph,
neighbors: neighbors,
}
}
}
impl<'a, S, N> NeighborsMut <'a, S, N> {
#[inline]
pub fn with_indices(self) -> NeighborsMutWithIndices<'a, S, N> {
let NeighborsMut { graph, neighbors } = self;
NeighborsMutWithIndices {
graph: graph,
neighbors: neighbors,
}
}
}
impl<'a, S, N> Iterator for Neighbors<'a, S, N> {
type Item = &'a N;
#[inline]
fn next(&mut self) -> Option<&'a N> {
match self.neighbors.next() {
Some(idx) => Some(&self.graph[idx].node),
None => None,
}
}
}
impl<'a, S, N> Iterator for NeighborsWithIndices<'a, S, N> {
type Item = (&'a N, NodeIndex);
#[inline]
fn next(&mut self) -> Option<(&'a N, NodeIndex)> {
match self.neighbors.next() {
Some(idx) => Some((&self.graph[idx].node, idx)),
None => None,
}
}
}
impl<'a, S, N> Iterator for NeighborsMut<'a, S, N> {
type Item = &'a mut N;
#[inline]
fn next(&mut self) -> Option<&'a mut N> {
let NeighborsMut { ref mut graph, ref mut neighbors } = *self;
match neighbors.next() {
Some(idx) => {
let node: &mut N = &mut graph[idx].node;
Some(unsafe { ::std::mem::transmute(node) })
},
None => None,
}
}
}
impl<'a, S, N> Iterator for NeighborsMutWithIndices<'a, S, N> {
type Item = (&'a mut N, NodeIndex);
#[inline]
fn next(&mut self) -> Option<(&'a mut N, NodeIndex)> {
let NeighborsMutWithIndices { ref mut graph, ref mut neighbors } = *self;
match neighbors.next() {
Some(idx) => {
let node: &mut N = &mut graph[idx].node;
Some((unsafe { ::std::mem::transmute(node) }, idx))
},
None => None,
}
}
}