use anyhow::Result;
use rlx_core::AudioCodec;
use rlx_core::codec_bench as cb;
use rlx_dac::DacCodec;
use rlx_runtime::Device;
const CRATE: &str = "rlx-dac";
fn main() -> Result<()> {
let (dur, iters) = cb::parse_dur_iters();
let dir = rlx_dac::resolve_model_dir(None);
if !dir.join("model.safetensors").is_file() {
eprintln!(
"skip {CRATE}: missing {}/model.safetensors (set RLX_DAC_DIR)",
dir.display()
);
return Ok(());
}
let candidates = vec![];
#[cfg(feature = "metal")]
candidates.push(Device::Metal);
#[cfg(feature = "mlx")]
candidates.push(Device::Mlx);
#[cfg(feature = "gpu")]
candidates.push(Device::Gpu);
for dev in cb::available(&candidates) {
if let Err(e) = bench_device(&dir, dev, dur, iters) {
cb::report_fail(CRATE, dev, "all", &e.to_string());
}
}
Ok(())
}
fn bench_device(dir: &std::path::Path, dev: Device, dur: f64, iters: usize) -> Result<()> {
let codec = DacCodec::open_on(dir, dev)?;
let info = codec.info();
let n_samples = (dur * info.sample_rate as f64) as usize;
let pcm = cb::synth_pcm(n_samples, 0.3, 0xDAC0);
let codes = match cb::time_once_ms(|| codec.encode_pcm(&pcm, None)) {
Ok((codes, compile_ms)) => {
let t = codes.num_frames();
let audio_s = (t * info.hop_length) as f64 / info.sample_rate as f64;
let run_ms = cb::time_median_ms(0, iters, || codec.encode_pcm(&pcm, None))?;
cb::report(CRATE, dev, "encode", audio_s, t, compile_ms, run_ms);
codes
}
Err(e) => {
cb::report_fail(CRATE, dev, "encode", &e.to_string());
return Ok(());
}
};
let t = codes.num_frames();
let audio_s = (t * info.hop_length) as f64 / info.sample_rate as f64;
match cb::time_once_ms(|| codec.decode_codes(&codes)) {
Ok((_, compile_ms)) => {
let run_ms = cb::time_median_ms(0, iters, || codec.decode_codes(&codes))?;
cb::report(CRATE, dev, "decode", audio_s, t, compile_ms, run_ms);
}
Err(e) => cb::report_fail(CRATE, dev, "decode", &e.to_string()),
}
Ok(())
}