use anyhow::Result;
use rlx_core::codec_bench as cb;
use rlx_runtime::Device;
use rlx_tsac::correct;
use rlx_tsac::{TsacBackendKind, TsacCodec, TsacOptions};
const CRATE: &str = "rlx-tsac";
fn main() -> Result<()> {
let (_dur, iters) = cb::parse_dur_iters();
let dir = correct::default_dir();
if !correct::weights_available(&dir) {
eprintln!(
"skip {CRATE}: Descript-DAC-44kHz weights not at {} (set RLX_DAC_DIR / .cache/dac44)",
dir.display()
);
return Ok(());
}
let in_wav = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../rlx-qwen3-tts/examples/audio/ask_not.wav");
if !in_wav.is_file() {
eprintln!("skip {CRATE}: missing input wav {}", in_wav.display());
return Ok(());
}
let audio_s = wav_seconds(&in_wav).unwrap_or(0.0);
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, &in_wav, audio_s, iters) {
cb::report_fail(CRATE, dev, "all", &e.to_string());
}
}
Ok(())
}
fn bench_device(
dir: &std::path::Path,
dev: Device,
in_wav: &std::path::Path,
audio_s: f64,
iters: usize,
) -> Result<()> {
let opts = TsacOptions {
device: dev,
backend: TsacBackendKind::Correct,
quality: Some(6),
..Default::default()
};
let codec = TsacCodec::open_with_options(dir, opts)?;
let ran = codec.device();
let tmp = std::env::temp_dir().join(format!("rlx-tsac-bench-{}.tsac", std::process::id()));
let out = std::env::temp_dir().join(format!("rlx-tsac-bench-{}.wav", std::process::id()));
match cb::time_median_ms(1, iters, || codec.encode(in_wav, &tmp).map(|_| ())) {
Ok(run_ms) => cb::report(CRATE, ran, "encode", audio_s, 0, 0.0, run_ms),
Err(e) => cb::report_fail(CRATE, ran, "encode", &e.to_string()),
}
match cb::time_median_ms(1, iters, || codec.decode(&tmp, &out)) {
Ok(run_ms) => cb::report(CRATE, ran, "decode", audio_s, 0, 0.0, run_ms),
Err(e) => cb::report_fail(CRATE, ran, "decode", &e.to_string()),
}
let _ = std::fs::remove_file(&tmp);
let _ = std::fs::remove_file(&out);
Ok(())
}
fn wav_seconds(path: &std::path::Path) -> Option<f64> {
let b = std::fs::read(path).ok()?;
let ch = (*b.get(22)? as usize | ((*b.get(23)? as usize) << 8)).max(1);
let sr = u32::from_le_bytes([*b.get(24)?, *b.get(25)?, *b.get(26)?, *b.get(27)?]).max(1);
let data = b.len().saturating_sub(44);
Some(data as f64 / (sr as f64 * ch as f64 * 2.0))
}