1use aether_core::{node::DspNode, param::ParamBlock, BUFFER_SIZE, MAX_INPUTS};
9use ringbuf::{traits::Producer, HeapProd};
10
11pub struct ScopeNode {
12 producer: HeapProd<f32>,
13}
14
15impl ScopeNode {
16 pub fn new(producer: HeapProd<f32>) -> Self {
17 Self { producer }
18 }
19}
20
21impl DspNode for ScopeNode {
22 fn process(
23 &mut self,
24 inputs: &[Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS],
25 output: &mut [f32; BUFFER_SIZE],
26 _params: &mut ParamBlock,
27 _sample_rate: f32,
28 ) {
29 let silence = [0.0f32; BUFFER_SIZE];
30 let input = inputs[0].unwrap_or(&silence);
31
32 let _ = self.producer.push_slice(input);
34
35 output.copy_from_slice(input);
37 }
38
39 fn type_name(&self) -> &'static str {
40 "ScopeNode"
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 use proptest::prelude::*;
48 use ringbuf::{traits::Split, HeapRb};
49
50 fn audio_buffer() -> impl Strategy<Value = [f32; BUFFER_SIZE]> {
52 prop::collection::vec(-1.0f32..=1.0f32, BUFFER_SIZE)
53 .prop_map(|v| v.try_into().unwrap())
54 }
55
56 proptest! {
58 #[test]
65 fn prop_scope_node_pass_through(
66 input_samples in audio_buffer(),
67 ) {
68 let ring = HeapRb::<f32>::new(BUFFER_SIZE * 2);
69 let (producer, _consumer) = ring.split();
70 let mut node = ScopeNode::new(producer);
71 let input_buffer: [f32; BUFFER_SIZE] = input_samples;
72 let mut output_buffer = [0.0f32; BUFFER_SIZE];
73 let mut params = ParamBlock::default();
74 let inputs: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = {
75 let mut arr: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = [None; MAX_INPUTS];
76 arr[0] = Some(&input_buffer);
77 arr
78 };
79 node.process(&inputs, &mut output_buffer, &mut params, 48000.0);
80 prop_assert_eq!(output_buffer, input_buffer);
81 }
82 }
83
84 proptest! {
86 #[test]
94 fn prop_scope_frame_serialization(
95 samples in audio_buffer(),
96 ) {
97 let mut serialized = Vec::with_capacity(256);
98 for &sample in &samples {
99 serialized.extend_from_slice(&sample.to_le_bytes());
100 }
101 prop_assert_eq!(serialized.len(), 256);
102 let mut deserialized = [0.0f32; 64];
103 for (i, chunk) in serialized.chunks_exact(4).enumerate() {
104 let bytes: [u8; 4] = chunk.try_into().unwrap();
105 deserialized[i] = f32::from_le_bytes(bytes);
106 }
107 prop_assert_eq!(deserialized, samples);
108 }
109 }
110}