use std::panic::AssertUnwindSafe;
use std::path::Path;
use beat_this::{BeatThis, OrtRuntime};
const MEL_MODEL_PATH: &str = "references/remixatron_rust/MelSpectrogram_Ultimate.onnx";
const BEAT_MODEL_PATH: &str = "references/remixatron_rust/BeatThis_small0.onnx";
const TEST_AUDIO_PATH: &str = "test_files/It Don't Mean A Thing - Kings of Swing.mp3";
fn ort_is_available() -> bool {
std::panic::catch_unwind(AssertUnwindSafe(|| {
let rt = OrtRuntime::default();
let _ = rt.is_coreml_available();
}))
.is_ok()
}
#[test]
fn test_full_pipeline_peak_picking() {
if !ort_is_available() {
eprintln!("Skipping test: ORT runtime not available");
return;
}
let mel_path = Path::new(MEL_MODEL_PATH);
let beat_path = Path::new(BEAT_MODEL_PATH);
let audio_path = Path::new(TEST_AUDIO_PATH);
if !mel_path.exists() || !beat_path.exists() || !audio_path.exists() {
eprintln!("Skipping test: required files not found");
return;
}
let runtime = OrtRuntime::default();
let mut bt = BeatThis::new(&runtime, mel_path, beat_path).expect("Failed to create BeatThis");
let audio = beat_this::load_audio(audio_path, 22050).expect("Failed to load audio");
let duration = audio.samples.len() as f32 / 22050.0;
let result = bt
.analyze_audio(&audio.samples, audio.sample_rate)
.expect("analyze_audio failed");
let beats = &result.beats;
let downbeats = &result.downbeats;
assert!(!beats.is_empty(), "No beats detected in real music");
assert!(!downbeats.is_empty(), "No downbeats detected in real music");
for &t in beats {
assert!(t >= 0.0, "Negative beat time: {t}");
assert!(
t <= duration + 0.1,
"Beat time {t} exceeds duration {duration}"
);
}
for &t in downbeats {
assert!(t >= 0.0, "Negative downbeat time: {t}");
assert!(
t <= duration + 0.1,
"Downbeat time {t} exceeds duration {duration}"
);
}
assert!(
beats.windows(2).all(|w| w[0] <= w[1]),
"Beat times are not sorted"
);
assert!(
downbeats.windows(2).all(|w| w[0] <= w[1]),
"Downbeat times are not sorted"
);
for &d in downbeats {
assert!(beats.contains(&d), "Downbeat time {d} not found in beats");
}
if beats.len() >= 2 {
let intervals: Vec<f32> = beats.windows(2).map(|w| w[1] - w[0]).collect();
let median = {
let mut sorted = intervals.clone();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
sorted[sorted.len() / 2]
};
assert!(
median > 0.2 && median < 2.0,
"Median beat interval {median:.3}s outside plausible range [0.2, 2.0]"
);
let bpm = 60.0 / median;
eprintln!(
"Peak picking: {:.1}s audio ā {} beats, {} downbeats",
duration,
beats.len(),
downbeats.len(),
);
eprintln!(" Median beat interval: {median:.3}s ({bpm:.1} BPM)");
eprintln!(" First 5 beats: {:?}", &beats[..beats.len().min(5)]);
eprintln!(
" First 5 downbeats: {:?}",
&downbeats[..downbeats.len().min(5)]
);
}
}