1use std::cell::UnsafeCell;
28use std::collections::HashMap;
29use std::ops::Deref;
30
31use daggy::Walker;
32use thiserror::Error;
33
34use audio_garbage_collector::{make_shared, make_shared_cell, Shared, SharedCell};
35use audio_processor_traits::simple_processor::MonoAudioProcessor;
36use audio_processor_traits::{
37 AudioBuffer, AudioContext, AudioProcessor, AudioProcessorSettings, NoopAudioProcessor,
38};
39use augmented_oscillator::Oscillator;
40
41#[cfg(test)]
42mod test_allocator;
43
44pub type NodeIndex = daggy::NodeIndex<u32>;
45pub type ConnectionIndex = daggy::EdgeIndex<u32>;
46
47pub type DefaultProcessor = NoopAudioProcessor<f32>;
49
50pub type AudioProcessorGraph = AudioProcessorGraphImpl<DefaultProcessor>;
52
53pub type AudioProcessorGraphHandle = AudioProcessorGraphHandleImpl<DefaultProcessor>;
55
56struct BufferCell<BufferType>(UnsafeCell<BufferType>);
57
58unsafe impl<BufferType> Sync for BufferCell<BufferType> {}
59
60struct ProcessorCell<P>(UnsafeCell<P>);
61
62unsafe impl<P> Sync for ProcessorCell<P> {}
63
64pub struct AudioProcessorGraphHandleImpl<P> {
65 input_node: NodeIndex,
66 output_node: NodeIndex,
67 dag: SharedCell<daggy::Dag<(), ()>>,
68 process_order: SharedCell<Vec<NodeIndex>>,
69 audio_processor_settings: SharedCell<Option<AudioProcessorSettings>>,
70 processors: SharedCell<HashMap<NodeIndex, Shared<ProcessorCell<NodeType<P>>>>>,
71 buffers: SharedCell<HashMap<ConnectionIndex, Shared<BufferCell<AudioBuffer<f32>>>>>,
72}
73
74impl<P: Send + 'static + AudioProcessor> AudioProcessorGraphHandleImpl<P> {
75 pub fn add_node(&self, mut processor: NodeType<P>) -> NodeIndex {
76 let mut processors = self.processors.get().deref().clone();
77 let mut dag = self.dag.get().deref().clone();
78 let index = dag.add_node(());
79
80 if let Some(settings) = self.audio_processor_settings.get().deref() {
81 let mut context = AudioContext::from(*settings);
82 match processor {
83 NodeType::Simple(ref mut processor) => processor.prepare(&mut context),
84 NodeType::Static(ref mut processor) => processor.prepare(&mut context),
85 _ => {}
86 }
87 }
88
89 let processor_ref = make_shared(ProcessorCell(UnsafeCell::new(processor)));
90 processors.insert(index, processor_ref);
91
92 self.processors.set(make_shared(processors));
93 self.dag.set(make_shared(dag));
94 index
95 }
96
97 pub fn add_connection(
98 &self,
99 source: NodeIndex,
100 destination: NodeIndex,
101 ) -> Result<ConnectionIndex, AudioProcessorGraphError> {
102 let mut buffers = self.buffers.get().deref().clone();
103
104 let mut dag = self.dag.get().deref().clone();
105 let edge = dag
106 .add_edge(source, destination, ())
107 .map_err(|_| AudioProcessorGraphError::WouldCycle)?;
108 let new_order = daggy::petgraph::algo::toposort(&dag, None)
109 .map_err(|_| AudioProcessorGraphError::WouldCycle)?;
110
111 let mut buffer = AudioBuffer::empty();
112 if let Some(settings) = self.audio_processor_settings.get().deref() {
113 buffer.resize(settings.output_channels, settings.block_size);
114 }
115
116 let buffer = make_shared(BufferCell(UnsafeCell::new(buffer)));
117
118 buffers.insert(edge, buffer);
119 self.buffers.set(make_shared(buffers));
120
121 self.dag.set(make_shared(dag));
122 self.process_order.set(make_shared(new_order));
123
124 Ok(edge)
125 }
126
127 pub fn clear(&self) {
128 let mut dag = self.dag.get().deref().clone();
129 dag.clear_edges();
130 self.dag.set(make_shared(dag));
131 }
132
133 pub fn input(&self) -> NodeIndex {
134 self.input_node
135 }
136
137 pub fn output(&self) -> NodeIndex {
138 self.output_node
139 }
140}
141
142#[derive(Debug, Error)]
143pub enum AudioProcessorGraphError {
144 #[error("Adding this connection would result in a cycle")]
145 WouldCycle,
146}
147
148pub enum NodeType<P> {
149 Simple(Box<dyn AudioProcessor<SampleType = f32> + Send>),
150 Static(P),
151 None,
152}
153
154impl From<Box<dyn AudioProcessor<SampleType = f32> + Send>> for NodeType<NoopAudioProcessor<f32>> {
155 fn from(inner: Box<dyn AudioProcessor<SampleType = f32> + Send>) -> Self {
156 NodeType::Simple(inner)
157 }
158}
159
160pub struct AudioProcessorGraphImpl<P> {
161 input_node: NodeIndex,
162 output_node: NodeIndex,
163 handle: Shared<AudioProcessorGraphHandleImpl<P>>,
164 temporary_buffer: AudioBuffer<f32>,
165}
166
167impl<P: Send + 'static + AudioProcessor> Default for AudioProcessorGraphImpl<P> {
168 fn default() -> Self {
169 Self::new(daggy::Dag::default())
170 }
171}
172
173impl<P: Send + 'static + AudioProcessor> AudioProcessorGraphImpl<P> {
174 fn new(mut dag: daggy::Dag<(), ()>) -> Self {
175 let _input_proc: NodeType<P> = NodeType::Simple(Box::<NoopAudioProcessor<f32>>::default());
176 let input_node = dag.add_node(());
177 let _output_proc: NodeType<P> = NodeType::Simple(Box::<NoopAudioProcessor<f32>>::default());
178 let output_node = dag.add_node(());
179
180 AudioProcessorGraphImpl {
181 input_node,
182 output_node,
183 handle: make_shared(AudioProcessorGraphHandleImpl {
184 input_node,
185 output_node,
186 dag: make_shared_cell(dag),
187 process_order: make_shared_cell(Vec::new()),
188 audio_processor_settings: make_shared_cell(None),
189 processors: make_shared_cell(HashMap::new()),
190 buffers: make_shared_cell(HashMap::new()),
191 }),
192 temporary_buffer: AudioBuffer::empty(),
193 }
194 }
195
196 pub fn from_handle(handle: Shared<AudioProcessorGraphHandleImpl<P>>) -> Self {
197 Self {
198 input_node: handle.input_node,
199 output_node: handle.output_node,
200 handle,
201 temporary_buffer: AudioBuffer::empty(),
202 }
203 }
204
205 pub fn input(&self) -> NodeIndex {
206 self.input_node
207 }
208
209 pub fn output(&self) -> NodeIndex {
210 self.output_node
211 }
212
213 pub fn handle(&self) -> &Shared<AudioProcessorGraphHandleImpl<P>> {
214 &self.handle
215 }
216
217 pub fn add_node(&mut self, processor: NodeType<P>) -> NodeIndex {
218 self.handle.add_node(processor)
219 }
220
221 pub fn add_connection(
222 &mut self,
223 source: NodeIndex,
224 destination: NodeIndex,
225 ) -> Result<ConnectionIndex, AudioProcessorGraphError> {
226 self.handle.add_connection(source, destination)
227 }
228}
229
230impl<P: AudioProcessor<SampleType = f32>> AudioProcessor for AudioProcessorGraphImpl<P> {
231 type SampleType = f32;
232
233 fn prepare(&mut self, context: &mut AudioContext) {
234 let settings = context.settings;
235 self.temporary_buffer
236 .resize(settings.output_channels(), settings.block_size());
237
238 self.handle
239 .audio_processor_settings
240 .set(make_shared(Some(settings)));
241 let buffers = self.handle.buffers.get();
242 for buffer_ref in buffers.values() {
243 let buffer = buffer_ref.deref().0.get();
244 unsafe {
245 (*buffer).resize(settings.output_channels(), settings.block_size());
246 }
247 }
248
249 let handle = self.handle.deref();
250
251 let processors = handle.processors.get();
252 let process_order = handle.process_order.get();
253 let process_order = process_order.deref();
254
255 for node_index in process_order {
256 if let Some(processor) = handle
257 .dag
258 .get()
259 .node_weight(*node_index)
260 .and(processors.get(node_index))
261 {
262 unsafe {
263 match &mut *processor.deref().0.get() {
264 NodeType::Simple(processor) => {
265 processor.prepare(context);
266 }
267 NodeType::Static(processor) => {
268 processor.prepare(context);
269 }
270 NodeType::None => {}
271 }
272 }
273 }
274 }
275 }
276
277 fn process(&mut self, context: &mut AudioContext, data: &mut AudioBuffer<Self::SampleType>) {
278 let num_channels = data.num_channels();
279 let num_samples = data.num_samples();
280 self.temporary_buffer.resize(num_channels, num_samples);
282
283 let handle = self.handle.deref();
284 let dag = handle.dag.get();
285 let dag = dag.deref();
286 let processors = handle.processors.get();
287 let buffers = handle.buffers.get();
288 let process_order = handle.process_order.get();
289 let process_order = process_order.deref();
290
291 let mut outputs = dag.children(self.input_node);
293 while let Some((connection_id, _)) = outputs.walk_next(dag) {
294 if let Some(buffer_ref) = dag
295 .edge_weight(connection_id)
296 .and(buffers.get(&connection_id))
297 {
298 let buffer = unsafe { &mut *buffer_ref.deref().0.get() };
299 buffer.resize(num_channels, num_samples);
300 buffer.copy_from(data);
301 }
302 }
303
304 for node_index in process_order {
305 let node_index = *node_index;
306
307 if node_index == self.input_node || node_index == self.output_node {
308 continue;
309 }
310
311 for sample in self.temporary_buffer.slice_mut() {
313 *sample = 0.0
314 }
315
316 let inputs = dag.parents(node_index);
317 for (connection_id, _) in inputs.iter(dag) {
318 if let Some(buffer_ref) = dag
319 .edge_weight(connection_id)
320 .and(buffers.get(&connection_id))
321 {
322 let buffer = buffer_ref.deref().0.get();
323 unsafe {
324 let buffer = &mut *buffer;
325 buffer.resize(data.num_channels(), data.num_samples());
326 self.temporary_buffer.add(buffer);
327 }
328 }
329 }
330
331 if let Some(processor_ref) =
332 dag.node_weight(node_index).and(processors.get(&node_index))
333 {
334 let processor = processor_ref.deref().0.get();
335 let processor = unsafe { &mut *processor };
336
337 match processor {
338 NodeType::Simple(processor) => {
339 processor.process(context, &mut self.temporary_buffer);
340 }
341 NodeType::Static(processor) => {
342 processor.process(context, &mut self.temporary_buffer);
343 }
344 NodeType::None => {}
345 }
346 }
347
348 let mut outputs = dag.children(node_index);
349 while let Some((connection_id, _)) = outputs.walk_next(dag) {
350 if let Some(buffer_ref) = dag
351 .edge_weight(connection_id)
352 .and(buffers.get(&connection_id))
353 {
354 let buffer = buffer_ref.deref().0.get();
355 let buffer = unsafe { &mut *buffer };
356 buffer.resize(num_channels, num_samples);
357 buffer.copy_from(&self.temporary_buffer);
358 }
359 }
360 }
361
362 let inputs = dag.parents(self.output_node);
364
365 for d in data.slice_mut() {
367 *d = 0.0;
368 }
369
370 for (connection_id, _) in inputs.iter(dag) {
371 if let Some(buffer_ref) = dag
372 .edge_weight(connection_id)
373 .and(buffers.get(&connection_id))
374 {
375 let buffer = buffer_ref.deref().0.get();
376
377 data.add(unsafe { &*buffer });
378 }
379 }
380 }
381}
382
383#[cfg(test)]
384mod test {
385 use std::time::Duration;
386
387 use assert_no_alloc::assert_no_alloc;
388 use audio_processor_testing_helpers::{assert_f_eq, test_level_equivalence};
389 use audio_processor_testing_helpers::{rms_level, sine_buffer};
390
391 use audio_processor_traits::audio_buffer::AudioBuffer;
392 use audio_processor_traits::simple_processor::MonoCopyProcessor;
393 use audio_processor_utility::gain::GainProcessor;
394 use audio_processor_utility::pan::PanProcessor;
395 use augmented_oscillator::Oscillator;
396
397 use super::*;
398
399 #[test]
400 fn test_create_graph() {
401 let _ = AudioProcessorGraph::default();
402 }
403
404 #[test]
405 fn test_create_graph_and_add_node() {
406 let mut graph = AudioProcessorGraph::default();
407 graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
408 GainProcessor::default(),
409 ))));
410 }
411
412 #[test]
413 fn test_create_graph_and_add_2_nodes() {
414 let mut graph = AudioProcessorGraph::default();
415 let gain1 = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
416 GainProcessor::default(),
417 ))));
418 let gain2 = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
419 GainProcessor::default(),
420 ))));
421 let _connection_id = graph.add_connection(gain1, gain2).unwrap();
422 }
423
424 #[test]
425 fn test_create_heterogeneous_graph() {
426 let mut graph = AudioProcessorGraph::default();
427 let gain = Box::new(MonoCopyProcessor::new(GainProcessor::default()));
428 let gain = graph.add_node(NodeType::Simple(gain));
429 let pan = graph.add_node(NodeType::Simple(Box::new(PanProcessor::default())));
430 let _connection_id = graph.add_connection(gain, pan).unwrap();
431 }
432
433 #[test]
434 fn test_process_empty_graph_is_silent() {
435 type BufferType = AudioBuffer<f32>;
436
437 let mut settings = AudioProcessorSettings::default();
438 settings.input_channels = 1;
439 settings.output_channels = 1;
440 settings.block_size = 1000;
441 let mut context = AudioContext::from(settings);
442
443 let mut empty_buffer = BufferType::empty();
444 empty_buffer.resize(1, 1000);
445 let mut graph = AudioProcessorGraph::default();
446
447 assert!((rms_level(empty_buffer.channel(0)) - 0.0).abs() < f32::EPSILON);
448
449 let mut process_buffer = empty_buffer.clone();
450 graph.prepare(&mut context);
451
452 assert_no_alloc(|| {
453 graph.process(&mut context, &mut process_buffer);
454 });
455
456 test_level_equivalence(
457 empty_buffer.channel(0),
458 process_buffer.channel(0),
459 1000,
460 1000,
461 f32::EPSILON,
462 );
463 }
464
465 #[test]
466 fn test_empty_graph_passthrough() {
467 let mut context = AudioContext::default();
468 context.settings.input_channels = 1;
469 context.settings.output_channels = 1;
470 let mut buffer = AudioBuffer::empty();
471 buffer.resize(1, 4);
472 buffer.set(0, 0, 1.0);
473 buffer.set(0, 1, 2.0);
474 buffer.set(0, 2, 3.0);
475 buffer.set(0, 3, 4.0);
476
477 let mut graph = AudioProcessorGraph::default();
478 graph.add_connection(graph.input(), graph.output()).unwrap();
479 graph.prepare(&mut context);
480 assert_no_alloc(|| {
481 graph.process(&mut context, &mut buffer);
482 });
483 assert_f_eq!(*buffer.get(0, 0), 1.0);
484 assert_f_eq!(*buffer.get(0, 1), 2.0);
485 assert_f_eq!(*buffer.get(0, 2), 3.0);
486 assert_f_eq!(*buffer.get(0, 3), 4.0);
487 }
488
489 #[test]
490 fn test_single_node_graph() {
491 let settings = AudioProcessorSettings::default();
492 let mut context = AudioContext::from(settings);
493 context.settings.input_channels = 1;
494 context.settings.output_channels = 1;
495 context.settings.block_size = 4;
496
497 let mut buffer = AudioBuffer::empty();
498 buffer.resize(1, 4);
499 buffer.set(0, 0, 1.0);
500 buffer.set(0, 1, 2.0);
501 buffer.set(0, 2, 3.0);
502 buffer.set(0, 3, 4.0);
503
504 struct Sum10Node {}
505 impl MonoAudioProcessor for Sum10Node {
506 type SampleType = f32;
507 fn m_process(
508 &mut self,
509 _context: &mut AudioContext,
510 sample: Self::SampleType,
511 ) -> Self::SampleType {
512 sample + 10.0
513 }
514 }
515
516 let sum_10_node = MonoCopyProcessor::new(Sum10Node {});
517
518 let mut graph = AudioProcessorGraph::default();
519 let sum_10_node = graph.add_node(NodeType::Simple(Box::new(sum_10_node)));
520 graph.add_connection(graph.input(), sum_10_node).unwrap();
521 graph.add_connection(sum_10_node, graph.output()).unwrap();
522 graph.prepare(&mut context);
523 assert_no_alloc(|| {
524 graph.process(&mut context, &mut buffer);
525 });
526 assert_f_eq!(*buffer.get(0, 0), 11.0);
527 assert_f_eq!(*buffer.get(0, 1), 12.0);
528 assert_f_eq!(*buffer.get(0, 2), 13.0);
529 assert_f_eq!(*buffer.get(0, 3), 14.0);
530 }
531
532 #[test]
533 fn test_series_node_graph() {
534 let settings = AudioProcessorSettings::default();
535 let mut context = AudioContext::from(settings);
536 context.settings.input_channels = 1;
537 context.settings.output_channels = 1;
538 context.settings.block_size = 4;
539
540 let mut buffer = AudioBuffer::empty();
541 buffer.resize(1, 4);
542 buffer.set(0, 0, 1.0);
543 buffer.set(0, 1, 2.0);
544 buffer.set(0, 2, 3.0);
545 buffer.set(0, 3, 4.0);
546
547 #[derive(Clone)]
548 struct Mult10Node {}
549 impl MonoAudioProcessor for Mult10Node {
550 type SampleType = f32;
551 fn m_process(
552 &mut self,
553 _context: &mut AudioContext,
554 sample: Self::SampleType,
555 ) -> Self::SampleType {
556 sample * 10.0
557 }
558 }
559
560 let mult_10_node = Mult10Node {};
561
562 let mut graph = AudioProcessorGraph::default();
563 let node1 = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
564 mult_10_node.clone(),
565 ))));
566 let node2 = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
567 mult_10_node,
568 ))));
569 graph.add_connection(graph.input(), node1).unwrap();
570 graph.add_connection(node1, node2).unwrap();
571 graph.add_connection(node2, graph.output()).unwrap();
572 graph.prepare(&mut context);
573 assert_no_alloc(|| {
574 graph.process(&mut context, &mut buffer);
575 });
576 assert_f_eq!(*buffer.get(0, 0), 100.0);
577 assert_f_eq!(*buffer.get(0, 1), 200.0);
578 assert_f_eq!(*buffer.get(0, 2), 300.0);
579 assert_f_eq!(*buffer.get(0, 3), 400.0);
580 }
581
582 #[test]
583 fn test_buffer_in_series() {
584 let settings = AudioProcessorSettings::default();
585 let mut context = AudioContext::from(settings);
586 context.settings.input_channels = 1;
587 context.settings.output_channels = 1;
588 let mut buffer = AudioBuffer::empty();
589 buffer.resize(1, 4);
590 buffer.set(0, 0, 1.0);
591 buffer.set(0, 1, 2.0);
592 buffer.set(0, 2, 3.0);
593 buffer.set(0, 3, 4.0);
594
595 #[derive(Clone)]
596 struct Mult10Node {}
597 impl AudioProcessor for Mult10Node {
598 type SampleType = f32;
599 fn process(&mut self, _context: &mut AudioContext, buffer: &mut AudioBuffer<f32>) {
600 for sample in buffer.slice_mut() {
601 *sample *= 10.0
602 }
603 }
604 }
605
606 let mult_10_node = Mult10Node {};
607
608 let mut graph = AudioProcessorGraph::default();
609 let node1 = graph.add_node(NodeType::Simple(Box::new(mult_10_node.clone())));
610 let node2 = graph.add_node(NodeType::Simple(Box::new(mult_10_node)));
611 graph.add_connection(graph.input(), node1).unwrap();
612 graph.add_connection(node1, node2).unwrap();
613 graph.add_connection(node2, graph.output()).unwrap();
614 graph.prepare(&mut context);
615 assert_no_alloc(|| {
616 graph.process(&mut context, &mut buffer);
617 });
618 assert_f_eq!(*buffer.get(0, 0), 100.0);
619 assert_f_eq!(*buffer.get(0, 1), 200.0);
620 assert_f_eq!(*buffer.get(0, 2), 300.0);
621 assert_f_eq!(*buffer.get(0, 3), 400.0);
622 }
623
624 #[test]
625 fn test_buffer_in_parallel() {
626 let mut settings = AudioProcessorSettings::default();
627 settings.input_channels = 1;
628 settings.output_channels = 1;
629 settings.block_size = 4;
630
631 let mut context = AudioContext::from(settings);
632 let mut buffer = AudioBuffer::empty();
633 buffer.resize(1, 4);
634 buffer.set(0, 0, 1.0);
635 buffer.set(0, 1, 2.0);
636 buffer.set(0, 2, 3.0);
637 buffer.set(0, 3, 4.0);
638
639 #[derive(Clone)]
640 struct Mult10Node {}
641 impl AudioProcessor for Mult10Node {
642 type SampleType = f32;
643 fn process(&mut self, _context: &mut AudioContext, buffer: &mut AudioBuffer<f32>) {
644 for sample in buffer.slice_mut() {
645 *sample *= 10.0
646 }
647 }
648 }
649
650 let mult_10_node = Mult10Node {};
651
652 let mut graph = AudioProcessorGraph::default();
653 let node1 = graph.add_node(NodeType::Simple(Box::new(mult_10_node.clone())));
654 let node2 = graph.add_node(NodeType::Simple(Box::new(mult_10_node)));
655 graph.add_connection(graph.input(), node1).unwrap();
656 graph.add_connection(node1, graph.output()).unwrap();
657 graph.add_connection(graph.input(), node2).unwrap();
658 graph.add_connection(node2, graph.output()).unwrap();
659 graph.prepare(&mut context);
660
661 assert_no_alloc(|| {
662 graph.process(&mut context, &mut buffer);
663 });
664
665 assert_f_eq!(*buffer.get(0, 0), 20.0);
666 assert_f_eq!(*buffer.get(0, 1), 40.0);
667 assert_f_eq!(*buffer.get(0, 2), 60.0);
668 assert_f_eq!(*buffer.get(0, 3), 80.0);
669 }
670
671 #[test]
672 fn test_more_complex_graph() {
673 let settings = AudioProcessorSettings::default();
676 let mut context = AudioContext::from(settings);
677 context.settings.input_channels = 1;
678 context.settings.output_channels = 1;
679 context.settings.block_size = 4;
680
681 let mut buffer = AudioBuffer::empty();
682 buffer.resize(1, 4);
683 buffer.set(0, 0, 1.0);
684 buffer.set(0, 1, 2.0);
685 buffer.set(0, 2, 3.0);
686 buffer.set(0, 3, 4.0);
687
688 #[derive(Clone)]
689 struct Mult10Node {}
690 impl AudioProcessor for Mult10Node {
691 type SampleType = f32;
692 fn process(&mut self, _context: &mut AudioContext, buffer: &mut AudioBuffer<f32>) {
693 for sample in buffer.slice_mut() {
694 *sample *= 10.0
695 }
696 }
697 }
698
699 let mult_10_node = Mult10Node {};
700
701 let mut graph = AudioProcessorGraph::default();
702 let node_a1 = graph.add_node(NodeType::Simple(Box::new(mult_10_node.clone())));
703 let node_a2 = graph.add_node(NodeType::Simple(Box::new(mult_10_node.clone())));
704 let node_b1 = graph.add_node(NodeType::Simple(Box::new(mult_10_node.clone())));
705 let node_b2 = graph.add_node(NodeType::Simple(Box::new(mult_10_node)));
706 graph.add_connection(graph.input(), node_a1).unwrap();
707 graph.add_connection(node_a1, node_a2).unwrap();
708 graph.add_connection(node_a2, graph.output()).unwrap();
709 graph.add_connection(graph.input(), node_b1).unwrap();
710 graph.add_connection(node_b1, node_b2).unwrap();
711 graph.add_connection(node_b2, graph.output()).unwrap();
712 graph.prepare(&mut context);
713 assert_no_alloc(|| {
714 graph.process(&mut context, &mut buffer);
715 });
716 assert_f_eq!(*buffer.get(0, 0), 200.0);
717 assert_f_eq!(*buffer.get(0, 1), 400.0);
718 assert_f_eq!(*buffer.get(0, 2), 600.0);
719 assert_f_eq!(*buffer.get(0, 3), 800.0);
720 }
721
722 #[test]
723 fn test_30_node_graph() {
724 let settings = AudioProcessorSettings::default();
727 let mut context = AudioContext::from(settings);
728 context.settings.input_channels = 1;
729 context.settings.output_channels = 1;
730 context.settings.block_size = 4;
731
732 let mut buffer = AudioBuffer::empty();
733 buffer.resize(1, 4);
734 buffer.set(0, 0, 1.0);
735 buffer.set(0, 1, 2.0);
736 buffer.set(0, 2, 3.0);
737 buffer.set(0, 3, 4.0);
738
739 #[derive(Clone)]
740 struct Mult10Node {}
741 impl AudioProcessor for Mult10Node {
742 type SampleType = f32;
743 fn process(&mut self, _context: &mut AudioContext, buffer: &mut AudioBuffer<f32>) {
744 for sample in buffer.slice_mut() {
745 *sample *= 10.0
746 }
747 }
748 }
749
750 let mult_10_node = Mult10Node {};
751
752 let mut graph = AudioProcessorGraph::default();
753 for _i in 0..10 {
754 let mut current_idx = graph.input();
755 for _i in 0..3 {
756 let node = graph.add_node(NodeType::Simple(Box::new(mult_10_node.clone())));
757 graph.add_connection(current_idx, node).unwrap();
758 current_idx = node;
759 }
760 graph.add_connection(current_idx, graph.output()).unwrap();
761 }
762 graph.prepare(&mut context);
763 assert_no_alloc(|| {
764 graph.process(&mut context, &mut buffer);
765 });
766 assert_f_eq!(*buffer.get(0, 0), 10000.0);
767 assert_f_eq!(*buffer.get(0, 1), 20000.0);
768 assert_f_eq!(*buffer.get(0, 2), 30000.0);
769 assert_f_eq!(*buffer.get(0, 3), 40000.0);
770 }
771
772 #[test]
773 fn test_process_empty_graph_passes_through_sine() {
774 type BufferType = AudioBuffer<f32>;
775
776 let mut settings = AudioProcessorSettings::default();
777 settings.set_input_channels(1);
778 settings.set_output_channels(1);
779 let sine_buffer: BufferType = BufferType::from_interleaved(
780 1,
781 &sine_buffer(settings.sample_rate, 440.0, Duration::from_millis(3)),
782 );
783 let mut context = AudioContext::from(settings);
784 assert_eq!(sine_buffer.num_channels(), 1);
785
786 let mut graph = AudioProcessorGraph::default();
787 graph.add_connection(graph.input(), graph.output()).unwrap();
788
789 let mut process_buffer = sine_buffer.clone();
790 graph.prepare(&mut context);
791 assert_no_alloc(|| {
792 graph.process(&mut context, &mut process_buffer);
793 });
794
795 test_level_equivalence(
796 sine_buffer.channel(0),
797 process_buffer.channel(0),
798 settings.block_size(),
799 settings.block_size(),
800 f32::EPSILON,
801 );
802 }
803
804 #[test]
805 fn test_process_sine_generator_is_silent_if_disconnected() {
806 type BufferType = AudioBuffer<f32>;
807
808 let settings = AudioProcessorSettings::default();
809 let mut context = AudioContext::from(settings);
810 context.settings.input_channels = 1;
811 context.settings.output_channels = 1;
812 context.settings.block_size = 1000;
813
814 let mut oscillator = Oscillator::sine(settings.sample_rate);
815 oscillator.set_frequency(440.0);
816 let oscillator = OscillatorProcessor { oscillator };
817
818 let mut empty_buffer: BufferType = AudioBuffer::empty();
819 empty_buffer.resize(1, 1000);
820
821 let mut process_buffer = AudioBuffer::empty();
822 process_buffer.resize(1, 1000);
823
824 let mut graph = AudioProcessorGraph::default();
826 graph.prepare(&mut context);
827 let _oscillator_idx = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
828 oscillator,
829 ))));
830 assert_no_alloc(|| {
831 graph.process(&mut context, &mut process_buffer);
832 });
833
834 test_level_equivalence(
835 empty_buffer.channel(0),
836 process_buffer.channel(0),
837 1000,
838 1000,
839 f32::EPSILON,
840 );
841 }
842
843 #[test]
844 fn test_process_sine_generator_is_silent_if_only_connected_to_input() {
845 let settings = AudioProcessorSettings::default();
846 let mut context = AudioContext::from(settings);
847 context.settings.input_channels = 1;
848 context.settings.output_channels = 1;
849 context.settings.block_size = 1000;
850
851 let mut oscillator = Oscillator::sine(settings.sample_rate);
852 oscillator.set_frequency(440.0);
853 let oscillator = OscillatorProcessor { oscillator };
854
855 let mut empty_buffer = AudioBuffer::empty();
856 empty_buffer.resize(1, 1000);
857
858 let mut process_buffer = AudioBuffer::empty();
859 process_buffer.resize(1, 1000);
860
861 let mut graph = AudioProcessorGraph::default();
863 graph.prepare(&mut context);
864 let oscillator_idx = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
865 oscillator,
866 ))));
867 graph
868 .add_connection(graph.input_node, oscillator_idx)
869 .unwrap();
870 assert_no_alloc(|| {
871 graph.process(&mut context, &mut process_buffer);
872 });
873
874 test_level_equivalence(
875 empty_buffer.channel(0),
876 process_buffer.channel(0),
877 1000,
878 1000,
879 f32::EPSILON,
880 );
881 }
882
883 #[test]
884 fn test_two_nodes_get_summed_if_connected_to_output() {
885 let settings = AudioProcessorSettings::default();
886 let mut context = AudioContext::from(settings);
887 context.settings.input_channels = 1;
888 context.settings.output_channels = 1;
889
890 struct Node1;
891 impl MonoAudioProcessor for Node1 {
892 type SampleType = f32;
893 fn m_process(
894 &mut self,
895 _context: &mut AudioContext,
896 sample: Self::SampleType,
897 ) -> Self::SampleType {
898 sample + 1.0
899 }
900 }
901
902 struct Node2;
903 impl MonoAudioProcessor for Node2 {
904 type SampleType = f32;
905 fn m_process(
906 &mut self,
907 _context: &mut AudioContext,
908 sample: Self::SampleType,
909 ) -> Self::SampleType {
910 sample + 2.0
911 }
912 }
913
914 let node1 = Node1 {};
915 let node2 = Node2 {};
916
917 let mut graph = AudioProcessorGraph::default();
918 graph.prepare(&mut context);
919
920 let input_idx = graph.input();
921 let output_idx = graph.output();
922 let node1_idx = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(node1))));
923 let node2_idx = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(node2))));
924 graph.add_connection(input_idx, node1_idx).unwrap();
925 graph.add_connection(input_idx, node2_idx).unwrap();
926 graph.add_connection(node1_idx, output_idx).unwrap();
927 graph.add_connection(node2_idx, output_idx).unwrap();
928
929 let mut process_buffer = AudioBuffer::empty();
930 process_buffer.resize(1, 3);
931 assert_no_alloc(|| {
932 graph.process(&mut context, &mut process_buffer);
933 });
934 let output = process_buffer.channel(0).to_vec();
935 assert_eq!(output, vec![3.0, 3.0, 3.0]);
936 }
937
938 #[test]
939 fn test_process_sine_generator_in_the_graph_produces_sine() {
940 type BufferType = AudioBuffer<f32>;
941 let settings = AudioProcessorSettings::default();
942 let mut context = AudioContext::from(settings);
943 context.settings.input_channels = 1;
944 context.settings.output_channels = 1;
945 context.settings.block_size = 1000;
946
947 let mut oscillator = Oscillator::sine(settings.sample_rate);
948 oscillator.set_frequency(440.0);
949 let oscillator = OscillatorProcessor { oscillator };
950
951 let reference_sine: BufferType = BufferType::from_interleaved(
952 1,
953 &sine_buffer(
954 settings.sample_rate,
955 440.0,
956 Duration::from_secs_f32((1.0 / settings.sample_rate) * 1000.0),
957 ),
958 );
959
960 let mut process_buffer = AudioBuffer::empty();
961 process_buffer.resize(1, 1000);
962
963 let mut graph = AudioProcessorGraph::default();
964 graph.prepare(&mut context);
965 let oscillator_idx = graph.add_node(NodeType::Simple(Box::new(MonoCopyProcessor::new(
966 oscillator,
967 ))));
968 graph
969 .add_connection(graph.input_node, oscillator_idx)
970 .unwrap();
971 graph
972 .add_connection(oscillator_idx, graph.output_node)
973 .unwrap();
974 assert_no_alloc(|| {
975 graph.process(&mut context, &mut process_buffer);
976 });
977
978 test_level_equivalence(
979 reference_sine.channel(0),
980 process_buffer.channel(0),
981 1000,
982 1000,
983 f32::EPSILON,
984 );
985 }
986}
987
988#[derive(Clone)]
990pub struct OscillatorProcessor {
991 pub oscillator: Oscillator<f32>,
992}
993
994impl MonoAudioProcessor for OscillatorProcessor {
995 type SampleType = f32;
996
997 fn m_prepare(&mut self, context: &mut AudioContext) {
998 self.oscillator
999 .set_sample_rate(context.settings.sample_rate);
1000 }
1001
1002 fn m_process(
1003 &mut self,
1004 _context: &mut AudioContext,
1005 _sample: Self::SampleType,
1006 ) -> Self::SampleType {
1007 self.oscillator.next_sample()
1008 }
1009}