use std::f64::consts::TAU;
use audio_resample_bsd::{Resampler, RubatoResampler};
use proptest::prelude::*;
fn fast_config() -> ProptestConfig {
ProptestConfig {
cases: 32,
timeout: 10_000,
..ProptestConfig::default()
}
}
fn sine(freq: f64, rate: f64, n: usize) -> Vec<f32> {
let omega = TAU * freq / rate;
(0..n).map(|i| (omega * i as f64).sin() as f32).collect()
}
proptest! {
#![proptest_config(fast_config())]
#[test]
fn valid_config_processes_sine_to_finite_output(
rate_in in 8000u32..=192_000,
rate_out in 8000u32..=192_000,
channels in 1u16..=4u16,
chunk in 256usize..=4096,
freq in 50.0f64..4000.0,
) {
prop_assume!(freq < (rate_in as f64) / 2.0 && freq < (rate_out as f64) / 2.0);
let rs = RubatoResampler::new(
f64::from(rate_in),
f64::from(rate_out),
channels.into(),
chunk,
);
let mut rs = match rs {
Ok(r) => r,
Err(_) => return Ok(()),
};
let input = sine(freq, f64::from(rate_in), chunk * channels as usize);
let mut output = vec![0.0_f32; rs.output_frames_max() * channels as usize];
let written = rs.process_into_buffer(&input, &mut output)?;
for &s in &output[..written * channels as usize] {
prop_assert!(s.is_finite(), "non-finite output sample {s}");
}
}
#[test]
fn delay_is_finite_and_bounded(
rate_in in 8000u32..=192_000u32,
rate_out in 8000u32..=192_000u32,
chunk in 256usize..=8192,
) {
let rs = match RubatoResampler::new(f64::from(rate_in), f64::from(rate_out), 1, chunk) {
Ok(r) => r,
Err(_) => return Ok(()),
};
let delay = rs.output_delay();
let out_max = rs.output_frames_max();
prop_assert!(delay < out_max + chunk, "delay {delay} unexpectedly large vs out_max {out_max}");
}
#[test]
fn set_rate_then_process_is_stable(
rate_a in 22050u32..=48_000u32,
rate_b in 48_000u32..=96_000u32,
) {
let mut rs = match RubatoResampler::new(f64::from(rate_a), 48_000.0, 1, 1024) {
Ok(r) => r,
Err(_) => return Ok(()),
};
rs.set_rate(f64::from(rate_b), 48_000.0);
let input = sine(1000.0, f64::from(rate_b), 1024);
let mut output = vec![0.0_f32; rs.output_frames_max()];
let written = rs.process_into_buffer(&input, &mut output)?;
for &s in &output[..written] {
prop_assert!(s.is_finite(), "non-finite after set_rate: {s}");
}
}
}