use sva_samples::biquad::{State, design};
use sva_samples::machine::Ctx;
use sva_samples::machine::ops::Layout;
use sva_samples::{Buffer, NodeRenderer, Site, SiteId};
const RATE: u32 = 8_000;
const LEN: usize = 64;
fn silent(renderer: &NodeRenderer, layout: &Layout) -> Result<Buffer, sva_samples::SampleError> {
renderer.run(
layout,
&Ctx {
rate: RATE,
origin_secs: 0.0,
len: 0,
reads: &[],
self_planes: &[],
written: 0,
},
)
}
fn ramp() -> Buffer {
Buffer::mono(RATE, (0..LEN).map(|i| i as f64 / LEN as f64).collect())
}
fn renderer() -> NodeRenderer {
NodeRenderer::Add(vec![
NodeRenderer::Filter {
site: SiteId(0),
x: Box::new(NodeRenderer::Buffer {
id: sva_samples::BufId(0),
shift: 0,
}),
cutoff: Box::new(NodeRenderer::Const(800.0)),
q: Box::new(NodeRenderer::Const(0.7)),
gain: Box::new(NodeRenderer::Const(0.0)),
},
NodeRenderer::Mul(vec![
NodeRenderer::Const(0.5),
NodeRenderer::SelfAt { steps: 1 },
]),
])
}
#[test]
fn a_buffer_read_a_filter_and_a_self_recurrence_produce_the_expected_samples() {
let read = ramp();
let renderer = renderer();
let layout = Layout {
width: 1,
read_widths: vec![1],
sites: vec![Site::Filter(sva_samples::Shape::Lowpass)],
};
let mut history = vec![0.0; LEN];
for i in 0..LEN {
let block = renderer
.run(
&layout,
&Ctx {
rate: RATE,
origin_secs: 0.0,
len: i + 1,
reads: &[&read],
self_planes: &history,
written: i,
},
)
.expect("a mono run");
history[i] = block.at(0, i);
}
let coeffs = design(
sva_samples::Shape::Lowpass,
800.0,
0.7,
0.0,
f64::from(RATE),
);
let mut state = State::default();
let mut want = vec![0.0; LEN];
for i in 0..LEN {
let filtered = state.step(&coeffs, read.at(0, i));
want[i] = filtered + 0.5 * if i == 0 { 0.0 } else { want[i - 1] };
}
for i in 0..LEN {
assert!(
(history[i] - want[i]).abs() < 1e-12,
"sample {i}: machine {} closed form {}",
history[i],
want[i]
);
}
assert!(history.iter().any(|&s| s != 0.0), "silence tests nothing");
}
#[test]
fn a_channel_past_the_last_component_refuses() {
let out = silent(
&NodeRenderer::Channel {
x: Box::new(NodeRenderer::Buffer {
id: sva_samples::BufId(0),
shift: 0,
}),
k: 3,
},
&Layout {
width: 2,
read_widths: vec![2],
sites: Vec::new(),
},
);
assert_eq!(
out.err(),
Some(sva_samples::SampleError::ChannelOutOfRange { k: 3, width: 2 })
);
}
#[test]
fn a_mono_operand_widens_to_its_neighbours_components_without_crossing_them() {
let stereo = Buffer::of_planes(RATE, vec![vec![1.0; LEN], vec![-2.0; LEN]]);
let renderer = NodeRenderer::Join(vec![
NodeRenderer::Mul(vec![
NodeRenderer::Channel {
x: Box::new(NodeRenderer::Buffer {
id: sva_samples::BufId(0),
shift: 0,
}),
k: 1,
},
NodeRenderer::Const(0.25),
]),
NodeRenderer::Mul(vec![
NodeRenderer::Buffer {
id: sva_samples::BufId(0),
shift: 0,
},
NodeRenderer::Const(3.0),
]),
]);
let layout = Layout {
width: 3,
read_widths: vec![2],
sites: Vec::new(),
};
let out = renderer
.run(
&layout,
&Ctx {
rate: RATE,
origin_secs: 0.0,
len: LEN,
reads: &[&stereo],
self_planes: &[],
written: 0,
},
)
.expect("a three-wide run");
assert_eq!(out.width, 3);
assert_eq!(out.at(0, 7), -0.5);
assert_eq!(out.at(1, 7), 3.0);
assert_eq!(out.at(2, 7), -6.0);
}
#[test]
fn a_width_mismatch_leaves_compile_under_its_own_code() {
let out = silent(
&NodeRenderer::Add(vec![
NodeRenderer::Buffer {
id: sva_samples::BufId(0),
shift: 0,
},
NodeRenderer::Buffer {
id: sva_samples::BufId(1),
shift: 0,
},
]),
&Layout {
width: 3,
read_widths: vec![2, 3],
sites: Vec::new(),
},
);
assert_eq!(
out.err().as_ref().map(sva_samples::SampleError::code),
Some("type.width_mismatch")
);
}