formats: XMA1 is not a WAVEFORMATEX -- audio info was reading three wrong fields

parse_riff_wave read every fmt chunk as a WAVEFORMATEX. XMA1 (tag 0x0165) is
not one, so audio info reported the disc s movie voices as 16 channels,
4310 Hz, 2-bit: 16 is wBitsPerSample read as a channel count and 4310 is
wEncodeOptions (0x10d6) read as a sample rate. This misled me earlier in the
session and I recorded it as a limitation before finding the cause.

XMA1 carries XMAWAVEFORMAT followed by one XMASTREAMFORMAT per stream. The
reader now branches on the tag and reads bits at +2, PsuedoBytesPerSec at +12,
SampleRate at +16 and Channels at +29. The same three files now report 2
channels, 48000 Hz, 16-bit.

The consequence worth having: this crate has no XMA decoder, and
data_bytes / PsuedoBytesPerSec is the only route to a duration. Checked against
durations decoded independently by the port:

  ADV presentation 1   137.34 s declared   137.324 s decoded   +0.012 percent
  ADV presentation 2   137.33 s declared   137.324 s decoded   +0.004 percent
  S00A presentation 1   93.71 s declared    93.694 s decoded   +0.017 percent

So the corpus can now get XMA1 durations off the disc without a decoder, which
is a capability I had written down as absent. It is a declared rate rather than
a measurement of the samples, and the CLI labels it as such.

Regression test pins the real on-disc header bytes and asserts the duration
against the independently decoded 137.324 s. 115 lib tests and 3 media disc
tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
This commit is contained in:
sylph-decoder
2026-08-29 15:42:52 +00:00
parent 9f34829776
commit a98a66190e
3 changed files with 147 additions and 13 deletions

View File

@@ -744,8 +744,16 @@ fn cmd_audio_info(file: &Path) -> Result<()> {
println!(" Channels : {}", opt(info.channels.map(|c| c.to_string())));
println!(" Sample rate: {}", opt(info.sample_rate.map(|r| format!("{r} Hz"))));
println!(" Bit depth : {}", opt(info.bits_per_sample.map(|b| format!("{b}-bit"))));
if let Some(b) = info.avg_bytes_per_sec {
println!(" Byte rate : {} B/s (declared)", b.to_string().yellow());
}
if let Some(d) = info.duration_secs {
println!(" Duration : {d:.2} s");
let how = if info.codec == sylpheed_formats::AudioCodec::Xma {
" (from the declared byte rate, not decoded)"
} else {
""
};
println!(" Duration : {d:.2} s{how}");
}
if let Some(p) = info.xma_packets {
println!(" XMA packets: {} (2048 B each)", p.to_string().yellow());