#![allow(dead_code)]
use hound::WavReader;
fn project_root() -> String {
env!("CARGO_MANIFEST_DIR").to_string()
}
pub fn wav_path(filename: &str) -> String {
format!("{}/audio_test_files/{}", project_root(), filename)
}
pub fn load_audio_reference(filename: &str) -> serde_json::Value {
let path = format!("{}/python/audio_references/{}", project_root(), filename);
let data = std::fs::read_to_string(&path).unwrap_or_else(|e| {
panic!(
"Failed to read {path}: {e}\n\
Run: cd python && uv run generate_audio_references.py"
)
});
serde_json::from_str(&data).expect("Failed to parse JSON")
}
pub fn read_wav_mono(path: &str) -> (Vec<f64>, u32) {
let reader = WavReader::open(path).unwrap_or_else(|e| panic!("Failed to open WAV {path}: {e}"));
let spec = reader.spec();
let sample_rate = spec.sample_rate;
let bits = spec.bits_per_sample;
let max_val = (1i64 << (bits - 1)) as f64;
let samples: Vec<f64> = reader
.into_samples::<i32>()
.map(|s| s.unwrap() as f64 / max_val)
.collect();
(samples, sample_rate)
}
pub fn extract_frame(
samples: &[f64],
frame_length: usize,
hop_length: usize,
frame_index: usize,
) -> Vec<f64> {
let start = frame_index * hop_length;
let end = (start + frame_length).min(samples.len());
samples[start..end].to_vec()
}
pub fn assert_approx_eq(actual: &[f64], expected: &[f64], tol: f64, label: &str) {
assert_eq!(
actual.len(),
expected.len(),
"{label}: length mismatch: got {} expected {}",
actual.len(),
expected.len()
);
for (i, (a, e)) in actual.iter().zip(expected.iter()).enumerate() {
let diff = (a - e).abs();
assert!(
diff < tol,
"{label}[{i}]: got {a}, expected {e}, diff {diff} > tol {tol}"
);
}
}