use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
use rusty_mp3::Mp3Decoder;
#[global_allocator]
static GLOBAL_ALLOC: rusty_alloc_api::RustyAlloc = rusty_alloc_api::RustyAlloc;
static FRAMES: AtomicU64 = AtomicU64::new(0);
static SAMPLES: AtomicU64 = AtomicU64::new(0);
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let Some(path) = args.first() else {
eprintln!("usage: decprof <input.mp3> [repeats]");
std::process::exit(2);
};
let repeats: usize = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(1);
let bytes = std::fs::read(path).expect("read input");
println!("input: {path} ({} KiB)", bytes.len() / 1024);
let mut pcm_hash: u64 = 0;
let t0 = std::time::Instant::now();
for _ in 0..repeats {
let mut dec = Mp3Decoder::new();
dec.push(&bytes);
dec.flush();
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
while let Ok(f) = dec.next_frame() {
FRAMES.fetch_add(1, Relaxed);
SAMPLES.fetch_add((f.samples.len() / f.channels.max(1) as usize) as u64, Relaxed);
for s in &f.samples {
for b in s.to_bits().to_le_bytes() {
h ^= b as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
}
}
pcm_hash = h;
}
let wall = t0.elapsed().as_secs_f64();
let frames = FRAMES.load(Relaxed);
let samples = SAMPLES.load(Relaxed);
println!(
"decoded {frames} frames, {samples} samples/ch over {repeats} pass(es) in {wall:.3} s"
);
println!("WORK-COUNT frames={frames} samples_per_ch={samples}");
println!("PCM fnv1a: {pcm_hash:#018x} <- decode byte-identity gate");
println!(
"throughput: {:.1}x realtime (44.1 kHz assumed)\n",
samples as f64 / 44_100.0 / wall
);
rusty_mp3::decode::prof::dump();
rusty_mp3::decode::prof::census();
}