slb: read Channels instead of assuming mono -- and retract the TCAF_608 conclusion
I read the seek chunk's packet count big-endian; it is little-endian at seek+12, with size == 8 + 4*count. And a seek sits immediately AFTER its own data, so an entry's first seek usually belongs to the PREVIOUS bank (implied start -25232 for D_452, -145988 for TCAF_608). I was comparing an entry's first seek against its first data -- different waves by construction, which is why no reading lined up. With that fixed, the declared sizes are honest: every RIFF-bearing entry on the disc has seek magic at exactly data_at + declared_size with count*2048 == declared. 7620/7620, zero failures. VOICE_TCAF_608 is not truncated. Its Channels is 2 and I decoded it as mono; read as stereo it gives 6520176 bytes = 33.96 s, agreeing with both length signals in the bank (33.88 s from cumulative samples, 33.97 s from PsuedoBytesPerSec). 170 of 8021 banks (2.12%) are stereo -- exactly the rate of my 1-in-60 outlier. This is the mono/stereo trap already documented on this very page, met from the other direction: I had written 'at two channels every bank yields one frame' and then spent several passes blaming missing data for a one-frame decode. Code fix: to_xma_riffs built the leading segment with a hard-wired mono fmt. It now reads Channels from the bank's first RIFF. 7 disc tests pass.
This commit is contained in:
@@ -131,6 +131,18 @@ fn parse_voice_clip(name: &str) -> VoiceClip {
|
||||
/// that yields the full track for segment banks while the clamp drops the
|
||||
/// duplicate takes for alternate-take banks. (Dynamic RE via Canary file-I/O
|
||||
/// tracing confirmed the movie→voice binding; this fixes the *decode* of `RT*`.)
|
||||
/// A bank's channel count, read from its first `RIFF` sub-wave.
|
||||
///
|
||||
/// `XMASTREAMFORMAT.Channels` sits at `RIFF + 49`. **2.12 % of banks are stereo**
|
||||
/// (170 of 8 021), and decoding one of those as mono yields a single frame and
|
||||
/// stops — the same signature already recorded for the leading segment. So the
|
||||
/// channel count has to be read, not assumed. Returns `None` when there is no
|
||||
/// `RIFF` to read it from.
|
||||
fn riff_channels(slb: &[u8]) -> Option<u8> {
|
||||
let ri = find(slb, b"RIFF", 0)?;
|
||||
slb.get(ri + 49).copied().filter(|c| *c == 1 || *c == 2)
|
||||
}
|
||||
|
||||
/// The four data offsets that occur on the disc, in ascending order.
|
||||
///
|
||||
/// Measured over all 7 358 banks whose offset is *known* (they carry a `RIFF`,
|
||||
@@ -280,7 +292,12 @@ pub fn to_xma_riffs(slb: &[u8]) -> Vec<Vec<u8>> {
|
||||
if ri > start {
|
||||
if let Some(data) = slb.get(start..ri) {
|
||||
if data.iter().any(|b| *b != 0) {
|
||||
out.push(build_riff(&synth_xma1_fmt(1, 0, 48000), data));
|
||||
// Channels come from the bank's own `fmt `, not a constant:
|
||||
// 170 of 8 021 banks are stereo and decode to one frame if
|
||||
// forced to mono.
|
||||
let ch = riff_channels(slb).unwrap_or(1);
|
||||
let mask = if ch == 2 { 2 } else { 0 };
|
||||
out.push(build_riff(&synth_xma1_fmt(ch, mask, 48000), data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user