1pub mod buffer;
66pub mod channel;
67pub mod processor;
68pub mod sample;
69
70pub use crate::buffer::*;
71pub use crate::channel::*;
72pub use crate::processor::*;
73pub use crate::sample::*;
74
75#[doc(no_inline)]
76pub use petgraph::graph::{EdgeIndex, NodeIndex};
77
78use petgraph::Direction;
79use petgraph::stable_graph::StableDiGraph;
80use petgraph::visit::{DfsPostOrder, EdgeRef, Reversed};
81
82use std::collections::HashMap;
83
84pub type AudioGraphError = &'static str;
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum GraphNode {
91 Input,
92 Output,
93 Node(NodeIndex),
94}
95
96impl From<NodeIndex> for GraphNode {
97 fn from(value: NodeIndex) -> Self {
98 GraphNode::Node(value)
99 }
100}
101
102struct ProcessorNode<T: Sample> {
104 processor: Box<dyn Processor<T> + Send>,
105}
106
107impl<T: Sample> ProcessorNode<T> {
108 pub fn new(processor: impl Processor<T> + Send + 'static) -> Self {
109 Self {
110 processor: Box::new(processor),
111 }
112 }
113
114 pub fn process(&mut self, context: &mut ProcessingContext<T>) {
115 self.processor.process(context);
116 }
117}
118
119#[derive(Clone)]
120#[doc(hidden)]
121pub struct EdgeData {
122 pub channel_selection: Option<ChannelSelection>,
123 pub enabled: bool,
124}
125
126#[doc(hidden)]
128pub trait GraphEdge: Clone {
129 const SUPPORTS_REWIRE: bool; fn new(channel_selection: Option<ChannelSelection>) -> Self;
132 fn data(&self) -> &EdgeData;
133 fn data_mut(&mut self) -> &mut EdgeData;
134
135 fn get_rewire(&self) -> Option<&HashMap<usize, usize>> {
136 None
137 }
138}
139
140#[derive(Clone)]
141#[doc(hidden)]
142pub struct ProcessorChannel {
143 pub data: EdgeData,
144}
145
146impl GraphEdge for ProcessorChannel {
147 const SUPPORTS_REWIRE: bool = false;
148
149 fn new(channel_selection: Option<ChannelSelection>) -> Self {
150 Self {
151 data: EdgeData {
152 channel_selection,
153 enabled: true,
154 },
155 }
156 }
157
158 fn data(&self) -> &EdgeData {
159 &self.data
160 }
161
162 fn data_mut(&mut self) -> &mut EdgeData {
163 &mut self.data
164 }
165}
166
167#[derive(Clone)]
168#[doc(hidden)]
169pub struct RewireProcessorChannel {
170 pub data: EdgeData,
171 pub rewire: Option<HashMap<usize, usize>>,
172}
173
174impl GraphEdge for RewireProcessorChannel {
175 const SUPPORTS_REWIRE: bool = true;
176
177 fn new(channel_selection: Option<ChannelSelection>) -> Self {
178 Self {
179 data: EdgeData {
180 channel_selection,
181 enabled: true,
182 },
183 rewire: None,
184 }
185 }
186
187 fn data(&self) -> &EdgeData {
188 &self.data
189 }
190
191 fn data_mut(&mut self) -> &mut EdgeData {
192 &mut self.data
193 }
194
195 fn get_rewire(&self) -> Option<&HashMap<usize, usize>> {
196 self.rewire.as_ref()
197 }
198}
199
200type GraphVisitMap<T, E> = <StableDiGraph<ProcessorNode<T>, E> as petgraph::visit::Visitable>::Map;
201
202#[allow(private_bounds)]
222pub struct DspGraph<T: Sample, Edge: GraphEdge> {
223 graph: StableDiGraph<ProcessorNode<T>, Edge>,
224 topo_order: Vec<NodeIndex>, buffers: Vec<Option<MultiChannelBuffer<T>>>,
226 input_node: NodeIndex,
227 output_node: NodeIndex,
228 summing_buffer: MultiChannelBuffer<T>,
229 dfs_visitor: DfsPostOrder<NodeIndex, GraphVisitMap<T, Edge>>,
230 topo_dirty: bool,
231}
232
233#[allow(private_bounds)]
234impl<T: Sample, Edge: GraphEdge> DspGraph<T, Edge> {
235 pub fn new(num_channels: usize, frame_size: FrameSize, max_num_edges: Option<usize>) -> Self {
243 let max_num_edges = max_num_edges.unwrap_or(64);
244
245 let mut buffers = Vec::with_capacity(max_num_edges);
246 for _ in 0..max_num_edges {
247 buffers.push(None);
248 }
249
250 let mut graph = DspGraph {
251 graph: StableDiGraph::with_capacity(max_num_edges, max_num_edges),
252 topo_order: Vec::with_capacity(max_num_edges),
253 buffers,
254 input_node: NodeIndex::end(),
255 output_node: NodeIndex::end(),
256 summing_buffer: MultiChannelBuffer::new(num_channels, frame_size),
257 dfs_visitor: DfsPostOrder::default(),
258 topo_dirty: true,
259 };
260
261 graph.input_node = graph
262 .add_processor(NoOp, MultiChannelBuffer::new(0, FrameSize(0)))
263 .unwrap();
264 graph.output_node = graph
265 .add_processor(NoOp, MultiChannelBuffer::new(0, FrameSize(0)))
266 .unwrap();
267
268 graph.dfs_visitor = DfsPostOrder::empty(&graph.graph);
269
270 graph
271 }
272
273 pub fn add_processor<P: Processor<T> + Send + 'static>(
278 &mut self,
279 processor: P,
280 output_buffer: MultiChannelBuffer<T>,
281 ) -> Result<NodeIndex, AudioGraphError> {
282 if self.graph.node_count() >= self.graph.capacity().0 {
283 return Err("Graph node capacity exceeded");
284 }
285
286 if output_buffer.num_frames().0 > self.summing_buffer.num_frames().0 {
287 return Err("Output buffer frame size exceeds graph capacity");
288 }
289
290 if output_buffer.num_channels() > self.summing_buffer.num_channels() {
291 return Err("Output buffer channel count exceeds graph capacity");
292 }
293
294 let node_index = self.graph.add_node(ProcessorNode::new(processor));
295 let buffer_index = node_index.index();
296
297 if buffer_index >= self.buffers.len() {
298 return Err("Buffer capacity exceeded");
299 }
300
301 self.buffers[buffer_index] = Some(output_buffer);
302
303 Ok(node_index)
304 }
305
306 pub fn connect(
319 &mut self,
320 from: GraphNode,
321 to: GraphNode,
322 channel_selection: Option<ChannelSelection>,
323 ) -> Result<EdgeIndex, AudioGraphError> {
324 if self.graph.edge_count() >= self.graph.capacity().1 {
325 return Err("Graph edge capacity exceeded");
326 }
327
328 if let (GraphNode::Input, GraphNode::Input)
330 | (GraphNode::Node(_), GraphNode::Input)
331 | (GraphNode::Output, _) = (from, to)
332 {
333 return Err("Invalid connection");
334 }
335
336 let from_index = match from {
337 GraphNode::Input => self.input_node,
338 GraphNode::Output => self.output_node,
339 GraphNode::Node(idx) => idx,
340 };
341 let to_index = match to {
342 GraphNode::Input => self.input_node,
343 GraphNode::Output => self.output_node,
344 GraphNode::Node(idx) => idx,
345 };
346
347 if self.graph.node_weight(from_index).is_none() {
348 return Err("Source node does not exist");
349 }
350 if self.graph.node_weight(to_index).is_none() {
351 return Err("Destination node does not exist");
352 }
353
354 let channel_selection = match channel_selection {
355 None => None,
356 Some(selection) => {
357 let mut channel_selection = selection;
358
359 if from_index != self.input_node {
360 let source_buffer_channels = self.buffers[from_index.index()]
361 .as_ref()
362 .unwrap()
363 .num_channels();
364 channel_selection.clamp(source_buffer_channels);
365 }
366
367 if to_index != self.output_node {
368 let destination_buffer_channels = self.buffers[to_index.index()]
369 .as_ref()
370 .unwrap()
371 .num_channels();
372 channel_selection.clamp(destination_buffer_channels);
373 }
374 Some(channel_selection)
375 }
376 };
377
378 let edge = Edge::new(channel_selection);
379
380 let edge_index = match self.graph.find_edge(from_index, to_index) {
381 Some(existing_edge_index) => {
382 *self.graph.edge_weight_mut(existing_edge_index).unwrap() = edge;
383 existing_edge_index
384 }
385 None => self.graph.add_edge(from_index, to_index, edge),
386 };
387
388 self.topo_dirty = true;
389 Ok(edge_index)
390 }
391
392 pub fn remove_connection(&mut self, edge: EdgeIndex) -> Result<(), AudioGraphError> {
398 self.graph.remove_edge(edge).ok_or("Edge not found")?;
399 self.topo_dirty = true;
400 Ok(())
401 }
402
403 pub fn enable_connection(&mut self, edge: EdgeIndex) -> Result<(), AudioGraphError> {
405 if let Some(edge_weight) = self.graph.edge_weight_mut(edge) {
406 edge_weight.data_mut().enabled = true;
407 Ok(())
408 } else {
409 Err("Edge not found")
410 }
411 }
412
413 pub fn disable_connection(&mut self, edge: EdgeIndex) -> Result<(), AudioGraphError> {
415 if let Some(edge_weight) = self.graph.edge_weight_mut(edge) {
416 edge_weight.data_mut().enabled = false;
417 Ok(())
418 } else {
419 Err("Edge not found")
420 }
421 }
422
423 fn ensure_topo_order_updated(&mut self) {
424 if self.topo_dirty {
425 self.topo_order.clear(); self.dfs_visitor.reset(&self.graph);
428 let reversed = Reversed(&self.graph);
429 for start_node in self
430 .graph
431 .neighbors_directed(self.output_node, Direction::Incoming)
432 {
433 self.dfs_visitor.move_to(start_node);
434 while let Some(node) = self.dfs_visitor.next(&reversed) {
435 self.topo_order.push(node);
436 }
437 }
438
439 self.topo_dirty = false;
440 }
441 }
442
443 pub fn process(
445 &mut self,
446 input: &dyn AudioBuffer<T>,
447 output: &mut dyn AudioBuffer<T>,
448 num_frames: FrameSize,
449 ) {
450 self.ensure_topo_order_updated(); output.clear();
453
454 for &node_index in &self.topo_order {
455 if node_index == self.output_node {
456 continue;
457 }
458
459 let output_buffer_index = node_index.index();
460
461 let mut incoming_edges = self
462 .graph
463 .edges_directed(node_index, Direction::Incoming)
464 .filter(|edge| edge.weight().data().enabled);
465
466 let num_incoming_edges = incoming_edges.clone().count();
467
468 if num_incoming_edges > 1 {
470 self.summing_buffer.clear();
471 let mut channel_selection: Option<ChannelSelection> = None;
472
473 for edge in incoming_edges {
474 let input_node = edge.source();
475 let input_buffer: &dyn AudioBuffer<T> = if input_node == self.input_node {
476 input
477 } else {
478 let input_buffer_index = input_node.index();
479 self.buffers[input_buffer_index].as_ref().unwrap()
480 };
481
482 let edge_selection = edge.weight().data().channel_selection.clone();
483
484 if Edge::SUPPORTS_REWIRE {
485 if let Some(rewire) = edge.weight().get_rewire() {
486 let rewired_buffer_view = RewiredBufferView {
487 buffer: input_buffer,
488 rewire,
489 };
490 self.summing_buffer
491 .add(&rewired_buffer_view, &edge_selection);
492 } else {
493 self.summing_buffer.add(input_buffer, &edge_selection);
494 }
495 } else {
496 self.summing_buffer.add(input_buffer, &edge_selection);
497 }
498
499 if let Some(edge_selection) = &edge_selection {
500 if let Some(existing_selection) = &mut channel_selection {
501 existing_selection.combine(edge_selection);
502 } else {
503 channel_selection = Some(edge_selection.clone());
504 }
505 }
506 }
507
508 let output_buffer: &mut dyn AudioBuffer<T> =
509 self.buffers[output_buffer_index].as_mut().unwrap();
510 let processor_node = self.graph.node_weight_mut(node_index).unwrap();
511
512 let mut context = ProcessingContext::create_unchecked(
513 &self.summing_buffer,
514 output_buffer,
515 channel_selection,
516 num_frames,
517 );
518
519 processor_node.process(&mut context);
520 } else if num_incoming_edges == 1 {
521 let (input_node, channel_selection, rewire_map) = {
522 let edge = incoming_edges.next().unwrap();
523 let rewire = if Edge::SUPPORTS_REWIRE {
524 edge.weight().get_rewire().cloned()
525 } else {
526 None
527 };
528 (
529 edge.source(),
530 edge.weight().data().channel_selection.clone(),
531 rewire,
532 )
533 };
534
535 let (input_buffer, output_buffer): (&dyn AudioBuffer<T>, &mut dyn AudioBuffer<T>) =
536 if input_node == self.input_node {
537 let output_buffer = self.buffers[output_buffer_index].as_mut().unwrap();
538 (input, output_buffer)
539 } else {
540 let input_buffer_index = input_node.index();
541 let (low, high) = self.buffers.split_at_mut(output_buffer_index);
542 (
543 low[input_buffer_index].as_ref().unwrap(),
544 high[0].as_mut().unwrap(),
545 )
546 };
547
548 let processor_node = self.graph.node_weight_mut(node_index).unwrap();
549
550 if Edge::SUPPORTS_REWIRE {
551 if let Some(rewire) = &rewire_map {
552 let rewired_buffer_view = RewiredBufferView {
553 buffer: input_buffer,
554 rewire,
555 };
556 let mut context = ProcessingContext::create_unchecked(
557 &rewired_buffer_view,
558 output_buffer,
559 channel_selection,
560 num_frames,
561 );
562 processor_node.process(&mut context);
563 } else {
564 let mut context = ProcessingContext::create_unchecked(
565 input_buffer,
566 output_buffer,
567 channel_selection,
568 num_frames,
569 );
570 processor_node.process(&mut context);
571 }
572 } else {
573 let mut context = ProcessingContext::create_unchecked(
574 input_buffer,
575 output_buffer,
576 channel_selection,
577 num_frames,
578 );
579 processor_node.process(&mut context);
580 }
581 }
582 }
583
584 for edge in self
585 .graph
586 .edges_directed(self.output_node, Direction::Incoming)
587 .filter(|e| e.weight().data().enabled)
588 {
589 let node = edge.source();
590 let node_buffer: &dyn AudioBuffer<T> = if node == self.input_node {
591 input
592 } else {
593 let input_buffer_index = node.index();
594 self.buffers[input_buffer_index].as_ref().unwrap()
595 };
596 output.add(node_buffer, &edge.weight().data().channel_selection.clone());
597 }
598 }
599}
600
601#[allow(private_bounds)]
602impl<T: Sample> RewireDspGraph<T> {
603 pub fn rewire(
653 &mut self,
654 edge_index: EdgeIndex,
655 rewire_mapping: &[(usize, usize)], ) -> Result<(), AudioGraphError> {
657 if let Some(edge) = self.graph.edge_weight_mut(edge_index) {
658 let mut channel_selection = ChannelSelection::new(0);
659 let mut rewire = HashMap::new();
660
661 for &(source, dest) in rewire_mapping {
662 channel_selection.connect(dest)?;
663
664 if rewire.insert(dest, source).is_some() {
666 return Err("Duplicate destination channel in rewire mapping");
667 }
668 }
669
670 edge.data_mut().channel_selection = Some(channel_selection);
671 edge.rewire = Some(rewire);
672
673 Ok(())
674 } else {
675 Err("Edge not found")
676 }
677 }
678
679 pub fn remove_rewire(&mut self, edge_index: EdgeIndex) -> Result<(), AudioGraphError> {
683 if let Some(edge) = self.graph.edge_weight_mut(edge_index) {
684 edge.rewire = None;
685 edge.data.channel_selection = None;
686 Ok(())
687 } else {
688 Err("Edge not found")
689 }
690 }
691
692 pub fn connect_rewired(
698 &mut self,
699 from: GraphNode,
700 to: GraphNode,
701 wiring: &[(usize, usize)],
702 ) -> Result<EdgeIndex, AudioGraphError> {
703 let edge = self.connect(from, to, None)?;
704 self.rewire(edge, wiring)?;
705 Ok(edge)
706 }
707}
708
709#[allow(private_interfaces)]
711pub type BasicDspGraph<T> = DspGraph<T, ProcessorChannel>;
712
713#[allow(private_interfaces)]
715pub type RewireDspGraph<T> = DspGraph<T, RewireProcessorChannel>;
716
717#[cfg(test)]
718mod tests {
719 use crate::processor::PassThrough;
720
721 use super::*;
722
723 struct FourtyTwo {}
724
725 impl Processor<f32> for FourtyTwo {
726 fn process(&mut self, context: &mut ProcessingContext<f32>) {
727 for channel in 0..context.output_buffer.num_channels() {
728 context
729 .output_buffer
730 .channel_mut(channel)
731 .unwrap()
732 .fill(42.0);
733 }
734 }
735 }
736
737 #[test]
738 fn test_simple_graph() {
739 let mut graph = BasicDspGraph::<f32>::new(1, FrameSize(10), None);
740 let fourty_two = graph
741 .add_processor(FourtyTwo {}, MultiChannelBuffer::new(1, FrameSize(10)))
742 .unwrap();
743 graph
744 .connect(GraphNode::Input, fourty_two.into(), None)
745 .unwrap();
746 graph
747 .connect(fourty_two.into(), GraphNode::Output, None)
748 .unwrap();
749
750 let input = MultiChannelBuffer::new(1, FrameSize(10));
751 let mut output = MultiChannelBuffer::new(1, FrameSize(10));
752 graph.process(&input, &mut output, FrameSize(10));
753
754 output.channel(0).unwrap().iter().for_each(|&x| {
755 assert_eq!(x, 42.0);
756 });
757 }
758
759 #[test]
760 fn test_passthrough() {
761 let mut graph = BasicDspGraph::<f32>::new(1, FrameSize(10), None);
762 graph
763 .connect(GraphNode::Input, GraphNode::Output, None)
764 .unwrap();
765 let mut input = MultiChannelBuffer::new(1, FrameSize(10));
766 input.channel_mut(0).unwrap().fill(2.0);
767
768 let mut output = MultiChannelBuffer::new(1, FrameSize(10));
769 graph.process(&input, &mut output, FrameSize(10));
770
771 output.channel(0).unwrap().iter().for_each(|&x| {
772 assert_eq!(x, 2.0);
773 });
774 }
775
776 #[test]
777 fn test_sum_at_output() {
778 let mut graph = BasicDspGraph::<f32>::new(1, FrameSize(10), None);
779 graph
780 .connect(GraphNode::Input, GraphNode::Output, None)
781 .unwrap();
782 let fourty_two = graph
783 .add_processor(FourtyTwo {}, MultiChannelBuffer::new(1, FrameSize(10)))
784 .unwrap();
785 graph
786 .connect(GraphNode::Input, fourty_two.into(), None)
787 .unwrap();
788 graph
789 .connect(fourty_two.into(), GraphNode::Output, None)
790 .unwrap();
791
792 let mut input = MultiChannelBuffer::new(1, FrameSize(10));
793 input.channel_mut(0).unwrap().fill(2.0);
794 let mut output = MultiChannelBuffer::new(1, FrameSize(10));
795
796 graph.process(&input, &mut output, FrameSize(10));
797
798 output.channel(0).unwrap().iter().for_each(|&x| {
799 assert_eq!(x, 44.0);
800 });
801 }
802
803 #[test]
804 fn test_partial_channel_routing() {
805 let mut graph = BasicDspGraph::<f32>::new(3, FrameSize(10), None);
806 let fourty_two = graph
807 .add_processor(FourtyTwo {}, MultiChannelBuffer::new(3, FrameSize(10)))
808 .unwrap();
809
810 let passthrough = graph
811 .add_processor(PassThrough {}, MultiChannelBuffer::new(3, FrameSize(10)))
812 .unwrap();
813
814 graph
816 .connect(GraphNode::Input, fourty_two.into(), None)
817 .unwrap();
818
819 let mut second_channel_only = ChannelSelection::new(0); second_channel_only.connect(1).unwrap();
821
822 graph
823 .connect(
824 fourty_two.into(),
825 passthrough.into(),
826 Some(second_channel_only),
827 )
828 .unwrap();
829
830 graph
831 .connect(passthrough.into(), GraphNode::Output, None)
832 .unwrap();
833
834 let mut input = MultiChannelBuffer::new(3, FrameSize(10));
835 input.channel_mut(0).unwrap().fill(1.0);
836 input.channel_mut(1).unwrap().fill(2.0);
837 input.channel_mut(2).unwrap().fill(3.0);
838
839 let mut output = MultiChannelBuffer::new(3, FrameSize(10));
840 graph.process(&input, &mut output, FrameSize(10));
841
842 output.channel(0).unwrap().iter().for_each(|&x| {
844 assert_eq!(x, 0.0);
845 });
846 output.channel(1).unwrap().iter().for_each(|&x| {
847 assert_eq!(x, 42.0);
848 });
849 output.channel(2).unwrap().iter().for_each(|&x| {
850 assert_eq!(x, 0.0);
851 });
852 }
853
854 #[test]
855 fn test_processing_order_and_count() {
856 struct Adder {
857 value: f32,
858 }
859
860 impl Processor<f32> for Adder {
861 fn process(&mut self, context: &mut ProcessingContext<f32>) {
862 for ch in 0..context.output_buffer.num_channels() {
863 let input_channel = context.input_buffer.channel(ch).unwrap();
864 let output_channel = context.output_buffer.channel_mut(ch).unwrap();
865 for (o, &i) in output_channel.iter_mut().zip(input_channel.iter()) {
866 *o = i + self.value;
867 }
868 }
869 }
870 }
871
872 let mut graph = BasicDspGraph::<f32>::new(1, FrameSize(8), None);
873
874 let add1 = graph
875 .add_processor(
876 Adder { value: 1.0 },
877 MultiChannelBuffer::new(1, FrameSize(8)),
878 )
879 .unwrap();
880
881 let add3 = graph
882 .add_processor(
883 Adder { value: 3.0 },
884 MultiChannelBuffer::new(1, FrameSize(8)),
885 )
886 .unwrap();
887 let add5 = graph
888 .add_processor(
889 Adder { value: 5.0 },
890 MultiChannelBuffer::new(1, FrameSize(8)),
891 )
892 .unwrap();
893
894 graph.connect(GraphNode::Input, add1.into(), None).unwrap();
895 graph.connect(add1.into(), add3.into(), None).unwrap();
896 graph.connect(add1.into(), add5.into(), None).unwrap();
897 graph.connect(add3.into(), GraphNode::Output, None).unwrap();
898 graph.connect(add5.into(), GraphNode::Output, None).unwrap();
899
900 let input = MultiChannelBuffer::new(1, FrameSize(8));
901 let mut output = MultiChannelBuffer::new(1, FrameSize(8));
902
903 graph.process(&input, &mut output, FrameSize(8));
904
905 output.channel(0).unwrap().iter().for_each(|&x| {
906 assert_eq!(x, 10.0);
907 });
908 }
909
910 #[test]
911 fn test_reconnect() {
912 let frame_size = FrameSize(10);
913
914 let mut graph = BasicDspGraph::<f32>::new(2, frame_size, Some(16));
915
916 let node_a = graph
917 .add_processor(PassThrough {}, MultiChannelBuffer::new(2, frame_size))
918 .unwrap();
919
920 let input_edge = graph
922 .connect(
923 GraphNode::Input,
924 node_a.into(),
925 Some(ChannelSelection::new(2)),
926 )
927 .unwrap();
928
929 let output_edge = graph
930 .connect(
931 node_a.into(),
932 GraphNode::Output,
933 Some(ChannelSelection::new(2)),
934 )
935 .unwrap();
936
937 let mut input = MultiChannelBuffer::new(2, frame_size);
938 input.channel_mut(0).unwrap().fill(1.0);
939 input.channel_mut(1).unwrap().fill(2.0);
940
941 let mut output = MultiChannelBuffer::new(2, frame_size);
942
943 graph.process(&input, &mut output, frame_size);
944 assert_eq!(output.channel(0).unwrap()[0], 1.0);
945 assert_eq!(output.channel(1).unwrap()[0], 2.0);
946
947 let new_input_edge = graph
949 .connect(
950 GraphNode::Input,
951 node_a.into(),
952 Some(ChannelSelection::from_indices(&[0])), )
954 .unwrap();
955 let new_output_edge = graph
956 .connect(
957 node_a.into(),
958 GraphNode::Output,
959 Some(ChannelSelection::from_indices(&[0])), )
961 .unwrap();
962
963 assert_eq!(input_edge, new_input_edge);
964 assert_eq!(output_edge, new_output_edge);
965
966 output.clear();
967 graph.process(&input, &mut output, frame_size);
968 assert_eq!(output.channel(0).unwrap()[0], 1.0);
969 assert_eq!(output.channel(1).unwrap()[0], 0.0); graph
972 .connect(
973 GraphNode::Input,
974 node_a.into(),
975 Some(ChannelSelection::from_indices(&[1])), )
977 .unwrap();
978 graph
979 .connect(
980 node_a.into(),
981 GraphNode::Output,
982 Some(ChannelSelection::from_indices(&[1])), )
984 .unwrap();
985
986 output.clear();
987 graph.process(&input, &mut output, frame_size);
988 assert_eq!(output.channel(0).unwrap()[0], 0.0); assert_eq!(output.channel(1).unwrap()[0], 2.0);
990 }
991
992 #[test]
993 fn test_capacity_limits() {
994 let mut graph = BasicDspGraph::<f32>::new(1, FrameSize(10), Some(4));
995
996 let n1 = graph
998 .add_processor(PassThrough {}, MultiChannelBuffer::new(1, FrameSize(10)))
999 .unwrap();
1000 let n2 = graph
1001 .add_processor(PassThrough {}, MultiChannelBuffer::new(1, FrameSize(10)))
1002 .unwrap();
1003
1004 assert!(
1005 graph
1006 .add_processor(PassThrough {}, MultiChannelBuffer::new(1, FrameSize(10)))
1007 .is_err()
1008 );
1009
1010 graph.connect(GraphNode::Input, n1.into(), None).unwrap();
1011 graph.connect(n1.into(), n2.into(), None).unwrap();
1012 graph.connect(n2.into(), GraphNode::Output, None).unwrap();
1013 graph.connect(GraphNode::Input, n2.into(), None).unwrap();
1014
1015 let result = graph.connect(n1.into(), GraphNode::Output, None);
1016 assert!(result.is_err());
1017 }
1018
1019 #[test]
1020 fn test_enable_disable_connection() {
1021 let frame_size = FrameSize(10);
1022 let mut graph = BasicDspGraph::<f32>::new(1, frame_size, None);
1023
1024 let node = graph
1025 .add_processor(FourtyTwo {}, MultiChannelBuffer::new(1, frame_size))
1026 .unwrap();
1027
1028 graph.connect(GraphNode::Input, node.into(), None).unwrap();
1029
1030 let output_edge = graph.connect(node.into(), GraphNode::Output, None).unwrap();
1031
1032 let mut input = MultiChannelBuffer::new(1, frame_size);
1033 input.channel_mut(0).unwrap().fill(1.0);
1034
1035 let mut output = MultiChannelBuffer::new(1, frame_size);
1036
1037 graph.process(&input, &mut output, frame_size);
1038 assert_eq!(output.channel(0).unwrap()[0], 42.0);
1039
1040 graph.disable_connection(output_edge).unwrap();
1041
1042 output.clear();
1043 graph.process(&input, &mut output, frame_size);
1044 assert_eq!(output.channel(0).unwrap()[0], 0.0);
1045
1046 graph.enable_connection(output_edge).unwrap();
1047
1048 output.clear();
1049 graph.process(&input, &mut output, frame_size);
1050 assert_eq!(output.channel(0).unwrap()[0], 42.0);
1051 }
1052}