fix(analysis): map waveform bins to decoded length, not inflated n_frames

Container-reported frame counts can exceed decoded samples on some VBR or
badly tagged files; using max() squashed energy into the leading bins.
This commit is contained in:
Maxim Isaev
2026-05-10 01:43:00 +03:00
parent 308eb36f05
commit cdd7cb192d
@@ -334,13 +334,21 @@ fn decode_scan_pcm(
let mut fed_any_frames = false; let mut fed_any_frames = false;
let mut sample_idx: u64 = 0; let mut sample_idx: u64 = 0;
let mut loop_i: u32 = 0; let mut loop_i: u32 = 0;
// Fixed timeline from metadata when available; otherwise fall back to decoded // Bin mapping must use the decoded mono sample count. When the container
// length (full-buffer analysis only — partial byte windows still shift, but // reports `n_frames` **larger** than what we actually decoded (bad VBR tags,
// then we usually lack n_frames anyway). // wrong duration in headers) but the buffer is already the full file — all
let bin_grid_frames = timeline_hint // CPU-seed paths pass a complete artifact — using `max(n_frames, decoded)`
.map(|n| n.max(decoded_frames)) // squashes the entire waveform into the leading bins ("only the start").
.unwrap_or(decoded_frames) if let Some(n) = timeline_hint {
.max(1); if n > decoded_frames {
crate::app_deprintln!(
"[analysis][waveform] bin_grid: ignore container n_frames={} (> decoded {}) — map bins to decoded length",
n,
decoded_frames
);
}
}
let bin_grid_frames = decoded_frames.max(1);
loop { loop {
let packet = match format.next_packet() { let packet = match format.next_packet() {