use fundsp::prelude::*;
use std::{cell::RefCell, rc::Rc};
use crate::{assert_audio_unit_meta_data_snapshot, assert_audio_unit_snapshot};
use crate::config::{
SvgChartConfigBuilder, SvgPreserveAspectRatio, SvgPreserveAspectRatioAlignment,
SvgPreserveAspectRatioBuilder, SvgPreserveAspectRatioKwd, WavOutput,
};
use crate::prelude::*;
#[test]
fn test_sine() {
let config = SnapshotConfigBuilder::default().build().unwrap();
let unit = sine_hz::<f32>(440.0);
let data = snapshot_audio_unit_with_input_and_options(unit, InputSource::None, config);
insta::assert_binary_snapshot!("sine.svg", data)
}
#[test]
fn test_custom_input() {
let config = SnapshotConfigBuilder::default()
.num_samples(100)
.build()
.unwrap();
let input = (0..100).map(|i| (i as f32 / 50.0).sin()).collect();
let data = snapshot_audio_unit_with_input_and_options(
lowpass_hz(500.0, 0.7),
InputSource::VecByChannel(vec![input]),
config,
);
insta::assert_binary_snapshot!("custom_input.svg", data)
}
#[test]
fn test_stereo() {
let config = SnapshotConfigBuilder::default().build().unwrap();
let unit = sine_hz::<f32>(440.0) | sine_hz::<f32>(880.0);
let data = snapshot_audio_unit_with_input_and_options(unit, InputSource::None, config);
insta::assert_binary_snapshot!("stereo.svg", data)
}
#[test]
fn test_lowpass_impulse() {
let config = SnapshotConfigBuilder::default()
.num_samples(300)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 1.0);
let data = snapshot_audio_unit_with_input_and_options(unit, InputSource::impulse(), config);
insta::assert_binary_snapshot!("lowpass_impulse.svg", data)
}
#[test]
fn test_net() {
let config = SnapshotConfigBuilder::default()
.num_samples(420)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0) >> lowpass_hz(500.0, 0.7);
let mut net = Net::new(0, 1);
let unit_id = net.push(Box::new(unit));
net.pipe_input(unit_id);
net.pipe_output(unit_id);
let data = snapshot_audio_unit_with_input_and_options(net, InputSource::None, config);
insta::assert_binary_snapshot!("net.svg", data)
}
#[test]
fn test_batch_prcessing() {
let config = SnapshotConfig {
processing_mode: Processing::Batch(64),
..Default::default()
};
let unit = sine_hz::<f32>(440.0);
let data = snapshot_audio_unit_with_options(unit, config);
insta::assert_binary_snapshot!("process_64.svg", data)
}
#[test]
fn test_vec_by_tick() {
let config = SnapshotConfigBuilder::default()
.num_samples(100)
.build()
.unwrap();
let input_data: Vec<Vec<f32>> = (0..100).map(|i| vec![(i as f32 / 50.0).cos()]).collect();
let data = snapshot_audio_unit_with_input_and_options(
lowpass_hz(800.0, 0.5),
InputSource::VecByTick(input_data),
config,
);
insta::assert_binary_snapshot!("vec_by_tick.svg", data)
}
#[test]
fn test_flat_input() {
let config = SnapshotConfigBuilder::default()
.num_samples(200)
.build()
.unwrap();
let flat_input = vec![0.5];
let data = snapshot_audio_unit_with_input_and_options(
highpass_hz(200.0, 0.7),
InputSource::Flat(flat_input),
config,
);
insta::assert_binary_snapshot!("flat_input.svg", data)
}
#[test]
fn test_sine_input_source() {
let config = SnapshotConfigBuilder::default()
.num_samples(200)
.build()
.unwrap();
let data = snapshot_audio_unit_with_input_and_options(
bandpass_hz(1000.0, 500.0),
InputSource::sine(100.0, 44100.0),
config,
);
insta::assert_binary_snapshot!("sine_input_source.svg", data)
}
#[test]
fn test_multi_channel_vec_by_channel_with_inputs() {
let chart = SvgChartConfigBuilder::default()
.with_inputs(true)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.num_samples(150)
.output_mode(chart)
.build()
.unwrap();
let left_channel: Vec<f32> = (0..150)
.map(|i| (i as f32 / 75.0 * std::f32::consts::PI).sin())
.collect();
let right_channel: Vec<f32> = (0..150)
.map(|i| (i as f32 / 75.0 * std::f32::consts::PI).cos())
.collect();
let unit = resonator_hz(440.0, 100.0) | resonator_hz(440.0, 100.0);
let data = snapshot_audio_unit_with_input_and_options(
unit,
InputSource::VecByChannel(vec![left_channel, right_channel]),
config,
);
insta::assert_binary_snapshot!("multi_channel_vec_by_channel_with_inputs.svg", data)
}
#[test]
fn test_macro_variant_unit_only() {
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!(unit);
}
#[test]
fn test_macro_variant_name_and_unit() {
let unit = saw_hz(220.0);
assert_audio_unit_snapshot!("macro_with_name", unit);
}
#[test]
fn test_macro_variant_name_unit_input() {
let unit = lowpass_hz(1000.0, 1.0);
assert_audio_unit_snapshot!("macro_with_input", unit, InputSource::impulse());
}
#[test]
fn test_macro_variant_expr_name_unit_input() {
let unit = lowpass_hz(500.0, 0.5);
let dyn_part = 42;
assert_audio_unit_snapshot!(
format!("macro_expr_name_{}", dyn_part),
unit,
InputSource::impulse()
);
}
#[test]
fn test_macro_variant_name_unit_input_config() {
let config = SnapshotConfigBuilder::default()
.num_samples(512)
.build()
.unwrap();
let unit = highpass_hz(2000.0, 0.7);
assert_audio_unit_snapshot!(
"macro_with_config",
unit,
InputSource::sine(100.0, 44100.0),
config
);
}
#[test]
fn test_macro_variant_unit_and_config() {
let unit = lowpass_hz(1000.0, 1.0);
let config = SnapshotConfigBuilder::default()
.num_samples(256)
.build()
.unwrap();
assert_audio_unit_snapshot!(unit, config);
}
#[test]
fn test_raw_snapshot_data_basic_shape() {
let config = SnapshotConfigBuilder::default()
.num_samples(128)
.build()
.unwrap();
let data = snapshot_audio_unit_data_with_input_and_options(
sine_hz::<f32>(440.0),
InputSource::None,
config,
);
assert_eq!(data.input_data.len(), 0);
assert_eq!(data.output_data.len(), 1);
assert_eq!(data.output_data[0].len(), 128);
assert_eq!(data.abnormalities.len(), 1);
assert_eq!(data.num_samples, 128);
}
#[test]
fn test_raw_snapshot_data_reports_abnormalities() {
let config = SnapshotConfigBuilder::default()
.allow_abnormal_samples(true)
.num_samples(30)
.build()
.unwrap();
let data = snapshot_audio_unit_data_with_input_and_options(
pass(),
InputSource::Generator(Box::new(|sample, _| {
if sample.is_multiple_of(3) {
f32::INFINITY
} else {
sample as f32
}
})),
config,
);
assert!(
!data.abnormalities[0].is_empty(),
"expected abnormal samples to be collected"
);
assert!(data
.abnormalities[0]
.iter()
.all(|(_, kind)| *kind == SnapshotAbnormalSample::PosInf));
assert!(data.output_data[0].iter().all(|sample| sample.is_finite()));
}
#[test]
fn test_macro_assert_audio_unit_meta_data_snapshot() {
assert_audio_unit_meta_data_snapshot!(
sine_hz::<f32>(220.0),
InputSource::None,
SnapshotConfigBuilder::default()
.num_samples(64)
.output_mode(
SvgChartConfigBuilder::default()
.chart_title("meta_dashboard")
.build()
.unwrap()
)
.build()
.unwrap() => |data: &AudioUnitSnapshotData| {
let output = &data.output_data[0];
let min = output.iter().copied().fold(f32::INFINITY, f32::min);
let max = output.iter().copied().fold(f32::NEG_INFINITY, f32::max);
insta_fun_meta! {
magnitudes: line(output.iter().map(|sample| sample.abs())),
min_max: range(min, max),
num_samples: scalar(data.num_samples),
}
}
);
}
#[test]
fn test_chart_with_title() {
let chart = SvgChartConfigBuilder::default()
.chart_title("Test Waveform 440Hz")
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!("chart_with_title", unit, InputSource::None, config);
}
#[test]
fn test_chart_with_grid() {
let chart = SvgChartConfigBuilder::default()
.show_grid(true)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!("chart_with_grid", unit, InputSource::None, config);
}
#[test]
fn test_chart_without_labels() {
let chart = SvgChartConfigBuilder::default()
.show_labels(false)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!("chart_without_labels", unit, InputSource::None, config);
}
#[test]
fn test_chart_with_custom_colors() {
let chart = SvgChartConfigBuilder::default()
.with_inputs(true)
.output_colors(vec!["#FF0000".to_string(), "#00FF00".to_string()])
.input_colors(vec!["#0000FF".to_string(), "#FFFF00".to_string()])
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.7);
assert_audio_unit_snapshot!(
"chart_custom_colors",
unit,
InputSource::sine(200.0, 44100.0),
config
);
}
#[test]
fn test_chart_with_custom_background() {
let chart = SvgChartConfigBuilder::default()
.background_color("#1E1E1E")
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!("chart_custom_background", unit, InputSource::None, config);
}
#[test]
fn test_chart_with_custom_line_width() {
let chart = SvgChartConfigBuilder::default()
.line_width(4.0)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!("chart_custom_line_width", unit, InputSource::None, config);
}
#[test]
fn test_chart_with_custom_dimensions() {
let chart = SvgChartConfigBuilder::default()
.svg_width(800)
.svg_height_per_channel(150)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!("chart_custom_dimensions", unit, InputSource::None, config);
}
#[test]
fn test_chart_with_preserve_aspect_ratio_plain() {
let preserve = SvgPreserveAspectRatioBuilder::default()
.alignment(SvgPreserveAspectRatioAlignment::XMidYMid)
.kwd(SvgPreserveAspectRatioKwd::None)
.build()
.unwrap();
let chart = SvgChartConfigBuilder::default()
.preserve_aspect_ratio(preserve)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!(
"chart_preserve_aspect_ratio_plain",
unit,
InputSource::None,
config
);
}
#[test]
fn test_chart_with_preserve_aspect_ratio_scale_to_fit() {
let chart = SvgChartConfigBuilder::default()
.preserve_aspect_ratio(SvgPreserveAspectRatio::scale_to_fit())
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!(
"chart_preserve_aspect_ratio_scale_to_fit",
unit,
InputSource::None,
config
);
}
#[test]
fn test_chart_with_all_options() {
let chart = SvgChartConfigBuilder::default()
.chart_title("Complete Waveform Test")
.show_grid(true)
.show_labels(true)
.with_inputs(true)
.output_color("#FF6B6B")
.input_color("#95E77E")
.background_color("#2C3E50")
.line_width(3.0)
.svg_width(1200)
.svg_height_per_channel(120)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!(
"chart_all_options",
unit,
InputSource::sine(100.0, 44100.0),
config
);
}
#[test]
fn test_chart_grid_and_no_labels() {
let chart = SvgChartConfigBuilder::default()
.show_grid(true)
.show_labels(false)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!("chart_grid_no_labels", unit, InputSource::None, config);
}
#[test]
fn test_chart_multi_channel_with_custom_colors() {
let chart = SvgChartConfigBuilder::default()
.with_inputs(true)
.output_color("#FF1744")
.output_color("#00E676")
.input_color("#2979FF")
.input_color("#FFEA00")
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.7) | highpass_hz(200.0, 0.7);
assert_audio_unit_snapshot!(
"chart_stereo_custom_colors",
unit,
InputSource::Flat(vec![0.5, -0.5]),
config
);
}
#[test]
fn chart_with_custom_output_channel_labels() {
let chart = SvgChartConfigBuilder::default()
.with_inputs(true)
.output_color("#FF1744")
.output_color("#00E676")
.output_title("lowpass_hz(1000.0, 0.7)")
.output_title("highpass_hz(200.0, 0.7)")
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.7) | highpass_hz(200.0, 0.7);
assert_audio_unit_snapshot!(
"chart_stereo_custom_labels",
unit,
InputSource::Flat(vec![0.5, -0.5]),
config
);
}
#[test]
fn chart_with_custom_input_channel_labels() {
let chart = SvgChartConfigBuilder::default()
.with_inputs(true)
.input_color("#2979FF")
.input_color("#FFEA00")
.input_title("left")
.input_title("right")
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.7) | highpass_hz(200.0, 0.7);
assert_audio_unit_snapshot!(
"chart_stereo_custom_inputs",
unit,
InputSource::Flat(vec![0.5, -0.5]),
config
);
}
#[test]
fn test_warmup_none() {
let config = SnapshotConfigBuilder::default()
.warm_up(WarmUp::None)
.num_samples(256)
.build()
.unwrap();
let unit = lowpass_hz(500.0, 0.8);
assert_audio_unit_snapshot!("warmup_none", unit, InputSource::impulse(), config);
}
#[test]
fn test_warmup_samples() {
let config = SnapshotConfigBuilder::default()
.warm_up(WarmUp::Samples(20_000))
.num_samples(2560)
.build()
.unwrap();
let unit = lowpass_hz(500.0, 0.8);
assert_audio_unit_snapshot!("warmup_samples", unit, InputSource::impulse(), config);
}
#[test]
fn test_warmup_seconds() {
let config = SnapshotConfigBuilder::default()
.warm_up(WarmUp::Seconds(0.01))
.num_samples(600)
.build()
.unwrap();
let unit = lowpass_hz(500.0, 0.8);
assert_audio_unit_snapshot!("warmup_seconds", unit, InputSource::impulse(), config);
}
#[test]
fn test_warmup_samples_with_input() {
let warm_input = Rc::new(RefCell::new(InputSource::impulse()));
let config = SnapshotConfigBuilder::default()
.warm_up(WarmUp::SamplesWithInput {
samples: 128,
input: warm_input.clone(),
})
.num_samples(256)
.build()
.unwrap();
let unit = resonator_hz(440.0, 50.0);
assert_audio_unit_snapshot!(
"warmup_samples_with_input_impulse",
unit,
InputSource::impulse(),
config
);
}
#[test]
fn test_abnormal_allowed() {
let config = SnapshotConfigBuilder::default()
.allow_abnormal_samples(true)
.num_samples(800)
.build()
.unwrap();
let unit = pass();
assert_audio_unit_snapshot!(
"abnormal_allowed",
unit,
InputSource::Generator(Box::new(|sample, _| {
if sample.is_multiple_of(3) && sample.is_multiple_of(5) {
f32::NAN
} else if sample.is_multiple_of(3) {
f32::NEG_INFINITY
} else if sample.is_multiple_of(5) {
f32::INFINITY
} else {
sample as f32
}
})),
config
);
}
#[test]
#[should_panic]
fn test_abnormal_disallowed_panic() {
let config = SnapshotConfigBuilder::default()
.allow_abnormal_samples(false)
.num_samples(800)
.build()
.unwrap();
let unit = pass();
assert_audio_unit_snapshot!(
"abnormal_disallowed_should_panic",
unit,
InputSource::Generator(Box::new(|sample, _| {
if sample.is_multiple_of(3) && sample.is_multiple_of(5) {
f32::NAN
} else if sample.is_multiple_of(3) {
f32::NEG_INFINITY
} else if sample.is_multiple_of(5) {
f32::INFINITY
} else {
sample as f32
}
})),
config
);
}
#[test]
fn test_chart_layout_combined() {
let chart = SvgChartConfigBuilder::default()
.chart_layout(Layout::Combined)
.show_grid(true)
.with_inputs(true)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.7) | highpass_hz(200.0, 0.7);
assert_audio_unit_snapshot!(
"chart_layout_combined",
unit,
InputSource::Flat(vec![0.5, -0.5]),
config
);
}
#[test]
fn test_chart_layout_combined_per_type() {
let chart = SvgChartConfigBuilder::default()
.chart_layout(Layout::CombinedPerChannelType)
.show_grid(true)
.with_inputs(true)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.7) | highpass_hz(200.0, 0.7);
assert_audio_unit_snapshot!(
"chart_layout_combined_per_type",
unit,
InputSource::Flat(vec![0.5, -0.5]),
config
);
}
#[test]
fn test_chart_layout_combined_per_type_no_inputs() {
let chart = SvgChartConfigBuilder::default()
.with_inputs(false)
.chart_layout(Layout::CombinedPerChannelType)
.show_grid(true)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(800.0, 0.7) | highpass_hz(300.0, 0.7);
assert_audio_unit_snapshot!(
"chart_layout_combined_per_type_no_inputs",
unit,
InputSource::None,
config
);
}
#[test]
fn test_chart_layout_combined_per_type_viewbox_height_uses_rows() {
let chart = SvgChartConfigBuilder::default()
.chart_layout(Layout::CombinedPerChannelType)
.with_inputs(true)
.svg_width(1024)
.svg_height_per_channel(512)
.show_grid(true)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.num_samples(1280)
.output_mode(chart)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.7) | highpass_hz(200.0, 0.7);
let svg = snapshot_audio_unit_with_input_and_options(
unit,
InputSource::Flat(vec![0.5, -0.5]),
config,
);
let svg = String::from_utf8(svg).expect("snapshot output should be valid UTF-8 SVG");
insta::assert_binary_snapshot!("chart_layout_combined_per_type_viewbox_height.svg", svg.as_bytes().to_vec());
assert!(
svg.contains("viewBox=\"0 0 1024 1024\""),
"expected row-based viewBox height, got header: {}",
svg.lines().next().unwrap_or_default()
);
}
#[test]
fn chart_x_axis_labels_as_time() {
let chart = SvgChartConfigBuilder::default()
.format_x_axis_labels_as_time(true)
.show_labels(true)
.max_labels_x_axis(None)
.build()
.unwrap();
let config = SnapshotConfigBuilder::default()
.num_samples(30000)
.output_mode(chart)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
assert_audio_unit_snapshot!(
"chart_x_axis_labels_as_time",
unit,
InputSource::None,
config
);
}
#[test]
fn test_wav16_basic() {
let config = SnapshotConfigBuilder::default()
.output_mode(WavOutput::Wav16)
.num_samples(2048)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
let data = snapshot_audio_unit_with_input_and_options(unit, InputSource::None, config);
insta::assert_binary_snapshot!("wav16.wav", data);
}
#[test]
fn test_wav32_basic() {
let config = SnapshotConfigBuilder::default()
.output_mode(WavOutput::Wav32)
.num_samples(2048)
.build()
.unwrap();
let unit = sine_hz::<f32>(440.0);
let data = snapshot_audio_unit_with_input_and_options(unit, InputSource::None, config);
insta::assert_binary_snapshot!("wav32.wav", data);
}
#[test]
fn test_wav16_with_warmup() {
let config = SnapshotConfigBuilder::default()
.warm_up(WarmUp::Samples(20_000))
.output_mode(WavOutput::Wav16)
.num_samples(2048)
.build()
.unwrap();
let unit = lowpass_hz(1000.0, 0.8);
let data = snapshot_audio_unit_with_input_and_options(unit, InputSource::impulse(), config);
insta::assert_binary_snapshot!("wav16_warmup.wav", data);
}
#[cfg(feature = "dot")]
#[test]
fn test_dsp_net_snapshot() {
use fundsp::prelude::*;
let mut net = Net::new(2, 2);
let left_filter = lowpass_hz(500.0, 0.7);
let left_id = net.push(Box::new(left_filter));
net.connect_input(0, left_id, 0);
let right_filter = highpass_hz(1200.0, 0.6);
let right_id = net.push(Box::new(right_filter));
net.connect_input(1, right_id, 0);
let stereo = multipass::<U2>();
let stereo_id = net.push(Box::new(stereo));
net.connect(left_id, 0, stereo_id, 0);
net.connect(right_id, 0, stereo_id, 1);
net.pipe_output(stereo_id);
assert_dsp_net_snapshot!("net_graph", net);
}
#[cfg(feature = "dot")]
#[test]
fn test_dsp_net_snapshot_complex() {
use fundsp::prelude::*;
let mut net = Net::new(0, 2);
let gen_a = net.push(Box::new(sine_hz::<f32>(220.0))); let gen_b = net.push(Box::new(saw_hz(330.0)));
let lp = net.push(Box::new(lowpass_hz(400.0, 0.7))); let hp = net.push(Box::new(highpass_hz(800.0, 0.5)));
net.connect(gen_a, 0, lp, 0);
net.connect(gen_b, 0, hp, 0);
let pan_a = net.push(Box::new(pan(-0.25))); let pan_b = net.push(Box::new(pan(0.25))); net.pipe_all(lp, pan_a);
net.pipe_all(hp, pan_b);
let bus_mix = net.push(Box::new(multipass::<U2>() + multipass::<U2>())); net.connect(pan_a, 0, bus_mix, 0);
net.connect(pan_a, 1, bus_mix, 1);
net.connect(pan_b, 0, bus_mix, 0);
net.connect(pan_b, 1, bus_mix, 1);
let rev = net.push(Box::new(reverb_stereo(2.5, 0.6, 0.4)));
net.pipe_all(bus_mix, rev);
net.pipe_output(rev);
net.connect_output(pan_b, 1, 1);
assert_dsp_net_snapshot!("complex_net_graph", net);
}
#[test]
fn test_meta_enriched_types_statistics_frequency_table() {
let config = SnapshotConfigBuilder::default()
.num_samples(1024)
.build()
.unwrap();
assert_audio_unit_meta_data_snapshot!(
sine_hz::<f32>(440.0),
InputSource::None,
config => |data: &AudioUnitSnapshotData| {
let output = &data.output_data[0];
let samples_f64: Vec<f64> = output.iter().map(|s| *s as f64).collect();
let freq_mag: Vec<f64> = (0..64)
.map(|i| {
let normalized = (i as f64 / 64.0 * std::f64::consts::PI).sin();
20.0 * normalized.log10().max(-80.0)
})
.collect();
let hist_data: Vec<f64> = (0..10)
.map(|bin| {
samples_f64
.iter()
.filter(|&&s| {
let bin_min = -1.0 + (bin as f64 * 0.2);
let bin_max = bin_min + 0.2;
s >= bin_min && s < bin_max
})
.count() as f64
})
.collect();
insta_fun_meta! {
sample_count: scalar(output.len()),
amplitude_range: range(*samples_f64.iter().fold(&f64::INFINITY, |a, b| if a < b { a } else { b }), *samples_f64.iter().fold(&f64::NEG_INFINITY, |a, b| if a > b { a } else { b })),
waveform: line(output.iter().take(100).map(|s| *s as f64).collect::<Vec<_>>()),
amplitude_histogram: histogram(hist_data),
statistics: statistics_from_data(samples_f64.clone()),
magnitude_spectrum: frequency_response(freq_mag),
unit_info: table(vec![
("frequency_hz".to_string(), "440".to_string()),
("sample_rate".to_string(), "44100".to_string()),
("duration_samples".to_string(), output.len().to_string()),
])
}
}
);
}