1use aether_core::{node::DspNode, param::ParamBlock, BUFFER_SIZE, MAX_INPUTS};
8use ringbuf::{traits::Producer, HeapProd};
9
10pub struct RecordNode {
11 producer: HeapProd<f32>,
12}
13
14impl RecordNode {
15 pub fn new(producer: HeapProd<f32>) -> Self {
16 Self { producer }
17 }
18}
19
20impl DspNode for RecordNode {
21 fn process(
22 &mut self,
23 inputs: &[Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS],
24 output: &mut [f32; BUFFER_SIZE],
25 _params: &mut ParamBlock,
26 _sample_rate: f32,
27 ) {
28 let silence = [0.0f32; BUFFER_SIZE];
29 let input = inputs[0].unwrap_or(&silence);
30
31 let _ = self.producer.push_slice(input);
33
34 output.copy_from_slice(input);
36 }
37
38 fn type_name(&self) -> &'static str {
39 "RecordNode"
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use proptest::prelude::*;
47 use ringbuf::{
48 traits::{Consumer, Split},
49 HeapRb,
50 };
51
52 fn audio_buffer() -> impl Strategy<Value = [f32; BUFFER_SIZE]> {
54 prop::collection::vec(-1.0f32..=1.0f32, BUFFER_SIZE).prop_map(|v| v.try_into().unwrap())
55 }
56
57 proptest! {
59 #[test]
66 fn prop_record_node_pass_through(
67 input_samples in audio_buffer(),
68 ) {
69 let ring = HeapRb::<f32>::new(BUFFER_SIZE * 2);
70 let (producer, _consumer) = ring.split();
71 let mut node = RecordNode::new(producer);
72 let input_buffer: [f32; BUFFER_SIZE] = input_samples;
73 let mut output_buffer = [0.0f32; BUFFER_SIZE];
74 let mut params = ParamBlock::default();
75 let inputs: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = {
76 let mut arr: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = [None; MAX_INPUTS];
77 arr[0] = Some(&input_buffer);
78 arr
79 };
80 node.process(&inputs, &mut output_buffer, &mut params, 48000.0);
81 prop_assert_eq!(output_buffer, input_buffer);
82 }
83
84 #[test]
92 fn prop_record_node_ring_buffer_round_trip(
93 input_samples in audio_buffer(),
94 ) {
95 let ring = HeapRb::<f32>::new(BUFFER_SIZE * 2);
96 let (producer, mut consumer) = ring.split();
97 let mut node = RecordNode::new(producer);
98 let input_buffer: [f32; BUFFER_SIZE] = input_samples;
99 let mut output_buffer = [0.0f32; BUFFER_SIZE];
100 let mut params = ParamBlock::default();
101 let inputs: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = {
102 let mut arr: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = [None; MAX_INPUTS];
103 arr[0] = Some(&input_buffer);
104 arr
105 };
106 node.process(&inputs, &mut output_buffer, &mut params, 48000.0);
107 let mut drained_samples = [0.0f32; BUFFER_SIZE];
108 let drained_count = consumer.pop_slice(&mut drained_samples);
109 prop_assert_eq!(drained_count, BUFFER_SIZE);
110 prop_assert_eq!(drained_samples, input_buffer);
111 }
112 }
113}