use aether_core::{node::DspNode, param::ParamBlock, BUFFER_SIZE, MAX_INPUTS};
use ringbuf::{traits::Producer, HeapProd};
pub struct RecordNode {
producer: HeapProd<f32>,
}
impl RecordNode {
pub fn new(producer: HeapProd<f32>) -> Self {
Self { producer }
}
}
impl DspNode for RecordNode {
fn process(
&mut self,
inputs: &[Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS],
output: &mut [f32; BUFFER_SIZE],
_params: &mut ParamBlock,
_sample_rate: f32,
) {
let silence = [0.0f32; BUFFER_SIZE];
let input = inputs[0].unwrap_or(&silence);
let _ = self.producer.push_slice(input);
output.copy_from_slice(input);
}
fn type_name(&self) -> &'static str {
"RecordNode"
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
use ringbuf::{traits::{Consumer, Split}, HeapRb};
fn audio_buffer() -> impl Strategy<Value = [f32; BUFFER_SIZE]> {
prop::collection::vec(-1.0f32..=1.0f32, BUFFER_SIZE)
.prop_map(|v| v.try_into().unwrap())
}
proptest! {
#[test]
fn prop_record_node_pass_through(
input_samples in audio_buffer(),
) {
let ring = HeapRb::<f32>::new(BUFFER_SIZE * 2);
let (producer, _consumer) = ring.split();
let mut node = RecordNode::new(producer);
let input_buffer: [f32; BUFFER_SIZE] = input_samples;
let mut output_buffer = [0.0f32; BUFFER_SIZE];
let mut params = ParamBlock::default();
let inputs: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = {
let mut arr: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = [None; MAX_INPUTS];
arr[0] = Some(&input_buffer);
arr
};
node.process(&inputs, &mut output_buffer, &mut params, 48000.0);
prop_assert_eq!(output_buffer, input_buffer);
}
#[test]
fn prop_record_node_ring_buffer_round_trip(
input_samples in audio_buffer(),
) {
let ring = HeapRb::<f32>::new(BUFFER_SIZE * 2);
let (producer, mut consumer) = ring.split();
let mut node = RecordNode::new(producer);
let input_buffer: [f32; BUFFER_SIZE] = input_samples;
let mut output_buffer = [0.0f32; BUFFER_SIZE];
let mut params = ParamBlock::default();
let inputs: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = {
let mut arr: [Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS] = [None; MAX_INPUTS];
arr[0] = Some(&input_buffer);
arr
};
node.process(&inputs, &mut output_buffer, &mut params, 48000.0);
let mut drained_samples = [0.0f32; BUFFER_SIZE];
let drained_count = consumer.pop_slice(&mut drained_samples);
prop_assert_eq!(drained_count, BUFFER_SIZE);
prop_assert_eq!(drained_samples, input_buffer);
}
}
}