SBlk body head: the DAW size, stored twice
Picked sound_bank rather than tie, where three discriminators have now come back
negative and a fourth would be guesswork.
The body after the 24-byte head opens with twelve words. Six are settled across
all 27 levels:
word value note
0 varies per level not identified; 27 distinct
1 60 constant
2 varies per level not identified; 23 distinct
3 0 constant
4 daw_size == the header's daw_size, exactly
5 daw_size the same value again
6,7,8 0 constant
9 127 constant
10 1 constant
11 0 constant
Level 0's words 4 and 5 are both 1,482,000, and daw_size is 1,482,000.
THE POINTER THAT WAS NOT ONE
Words 4 and 5 were briefly recorded as pointers into the DAW region. They are not.
The test that promoted them was "does this value fall inside [daw_offset,
daw_offset + daw_size)" -- and the DAW region is ~1.5 MB starting near the front of
a ~1.5 MB extent, so almost any plausible 32-bit word lands inside it. 1,482,000 is
merely just under the top of exactly that range.
A range test is not an identification. What survives is EQUALITY with daw_size,
exact on all 27 levels and asserted, which is a claim that can fail rather than one
that is almost always true.
That is the fourth time this session a plausible reading of a single number has had
to be withdrawn for something falsifiable: the 305x class-ID slot, the UV-corner
texcoords, the VIF code word, and now this. The pattern is consistent enough to be
worth stating as a rule -- a test that passes almost always is measuring the shape
of the data, not a property of it.
Word 0 gets one note: levels 1 and 4 hold 13,042,052 and 13,042,054, two apart,
while their daw_sizes differ by 63,504. Whatever it is, it is not a size.
The remainder of the SBlk body -- the per-sound record table -- is still undecoded,
so sound_bank stays open. A SBlkBodyHead struct carries the twelve words with the
constants asserted in its docs.
259 tests.
This commit is contained in:
@@ -5514,3 +5514,75 @@ fn tie_vertex_regions_split_on_the_first_words_top_bit() {
|
||||
by_size.len()
|
||||
);
|
||||
}
|
||||
|
||||
/// The `SBlk` body's first twelve words: six identified, six not.
|
||||
///
|
||||
/// Words 4 and 5 both hold the **DAW sample-data size**, byte for byte, on all
|
||||
/// 27 levels -- level 0's are 1,482,000 and `daw_size` is 1,482,000. This was
|
||||
/// briefly misread as a pointer into the DAW region: those sizes happen to fall
|
||||
/// inside `[daw_offset, daw_offset + daw_size)`, so an "is it in range?" test
|
||||
/// passed for the wrong reason. Equality with `daw_size` is the claim, and it
|
||||
/// holds everywhere.
|
||||
///
|
||||
/// Words 1, 3, 6, 7, 8, 9, 10 and 11 are the same on every level. Words 0 and 2
|
||||
/// vary per level and are not identified; word 0 is close between levels 1 and 4
|
||||
/// (13,042,052 and 13,042,054) while their `daw_size`s differ by 63,504, so it is
|
||||
/// not a size.
|
||||
#[test]
|
||||
fn sound_bank_sblk_body_head_carries_the_daw_size_twice() {
|
||||
require_disc!();
|
||||
|
||||
let data = std::env::var_os("GC_EXTRACTED")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
|
||||
PathBuf::from(home).join("Documents/gc-extracted")
|
||||
});
|
||||
if !data.exists() {
|
||||
eprintln!("skipped: unpack the disc first");
|
||||
return;
|
||||
}
|
||||
|
||||
use gc_formats::sound_bank::{parse_sound_bank, SoundBankHeader};
|
||||
|
||||
let mut levels = 0usize;
|
||||
let mut w0: Vec<u32> = Vec::new();
|
||||
let mut w2: Vec<u32> = Vec::new();
|
||||
for lv in 0..27usize {
|
||||
let Ok(bytes) = std::fs::read(data.join(format!("level{lv}/sound_bank.bin"))) else {
|
||||
continue;
|
||||
};
|
||||
let h = SoundBankHeader::parse(&bytes).expect("sound bank head");
|
||||
let bank = parse_sound_bank(&bytes).expect("sound bank");
|
||||
assert!(bank.sblk.len() >= 48, "level {lv}: SBlk body too short");
|
||||
let w: Vec<u32> = (0..12)
|
||||
.map(|i| u32::from_le_bytes(bank.sblk[24 + i * 4..28 + i * 4].try_into().unwrap()))
|
||||
.collect();
|
||||
|
||||
assert_eq!(w[4], h.daw_size, "level {lv}: body word 4 is not daw_size");
|
||||
assert_eq!(w[5], h.daw_size, "level {lv}: body word 5 is not daw_size");
|
||||
assert_eq!(w[1], 60, "level {lv}: body word 1 moved");
|
||||
assert_eq!(w[3], 0, "level {lv}: body word 3 moved");
|
||||
for i in [6usize, 7, 8, 11] {
|
||||
assert_eq!(w[i], 0, "level {lv}: body word {i} moved");
|
||||
}
|
||||
assert_eq!(w[9], 127, "level {lv}: body word 9 moved");
|
||||
assert_eq!(w[10], 1, "level {lv}: body word 10 moved");
|
||||
w0.push(w[0]);
|
||||
w2.push(w[2]);
|
||||
levels += 1;
|
||||
}
|
||||
assert_eq!(levels, 27, "only {levels} sound banks parsed");
|
||||
let uniq0: std::collections::BTreeSet<u32> = w0.iter().copied().collect();
|
||||
let uniq2: std::collections::BTreeSet<u32> = w2.iter().copied().collect();
|
||||
eprintln!(
|
||||
"SBlk body head: words 4 and 5 both equal daw_size on 27/27; words 0 and 2 \\
|
||||
vary ({}/{} and {}/{} distinct)",
|
||||
uniq0.len(),
|
||||
levels,
|
||||
uniq2.len(),
|
||||
levels
|
||||
);
|
||||
assert!(uniq0.len() > 20, "body word 0 stopped varying per level");
|
||||
assert!(uniq2.len() > 20, "body word 2 stopped varying per level");
|
||||
}
|
||||
|
||||
@@ -136,6 +136,38 @@ impl SBlkHeader {
|
||||
}
|
||||
}
|
||||
|
||||
/// The first twelve words of the `SBlk` body, after its 24-byte head.
|
||||
///
|
||||
/// Words 4 and 5 both hold the **DAW sample-data size** -- byte for byte, on all
|
||||
/// 27 levels. Words 1, 3, 6, 7, 8, 9, 10 and 11 are the same on every level
|
||||
/// (60, 0, 0, 0, 0, 127, 1, 0). Words 0 and 2 vary per level and are not
|
||||
/// identified.
|
||||
///
|
||||
/// These sizes fall inside `[daw_offset, daw_offset + daw_size)`, so a test of
|
||||
/// the form "is this word in the DAW region?" passes for them and reads as a
|
||||
/// pointer. It is not one; equality with `daw_size` is the claim.
|
||||
///
|
||||
/// Asserted in `sound_bank_sblk_body_head_carries_the_daw_size_twice`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct SBlkBodyHead {
|
||||
pub word_0: u32,
|
||||
pub word_1: u32,
|
||||
pub word_2: u32,
|
||||
pub word_3: u32,
|
||||
/// Always the DAW sample-data size.
|
||||
pub word_4: u32,
|
||||
/// Always the same value as [`Self::word_4`].
|
||||
pub word_5: u32,
|
||||
pub word_6: u32,
|
||||
pub word_7: u32,
|
||||
pub word_8: u32,
|
||||
/// Always 127.
|
||||
pub word_9: u32,
|
||||
/// Always 1.
|
||||
pub word_10: u32,
|
||||
pub word_11: u32,
|
||||
}
|
||||
|
||||
/// Split a sound extent into its two regions.
|
||||
///
|
||||
/// Bounds are checked before slicing; a level whose head points outside its own
|
||||
|
||||
@@ -2865,3 +2865,45 @@ So: on a flat record, `i16[4]`/`i16[5]` are **not identified**, and the texcoord
|
||||
slot of a tie vertex is unknown. What survives from the original section is the
|
||||
boundary work -- `vert_ofs + vert_size + scissor_size` is the region length -- and
|
||||
the LOD1/LOD2 sharing result, which is stride-insensitive.
|
||||
|
||||
|
||||
## The `SBlk` body head: the DAW size, twice
|
||||
|
||||
The body after the 24-byte head opens with twelve words, and six of them are
|
||||
settled across all 27 levels:
|
||||
|
||||
word value note
|
||||
0 varies per level not identified; 27 distinct
|
||||
1 60 constant
|
||||
2 varies per level not identified; 23 distinct
|
||||
3 0 constant
|
||||
4 daw_size == the header's daw_size, exactly
|
||||
5 daw_size the same value again
|
||||
6 0 constant
|
||||
7 0 constant
|
||||
8 0 constant
|
||||
9 127 constant
|
||||
10 1 constant
|
||||
11 0 constant
|
||||
|
||||
Level 0's words 4 and 5 are both 1,482,000, and `daw_size` is 1,482,000.
|
||||
|
||||
### The pointer that was not one
|
||||
|
||||
Words 4 and 5 were briefly recorded as pointers into the DAW region. They are not.
|
||||
The test that promoted them was "does this value fall inside
|
||||
`[daw_offset, daw_offset + daw_size)`", and the DAW region is ~1.5 MB starting
|
||||
near the front of a ~1.5 MB extent -- so almost any plausible 32-bit word lands in
|
||||
it, and 1,482,000 is just under the top of exactly that range.
|
||||
|
||||
**A range test is not an identification.** The claim that survives is *equality
|
||||
with `daw_size`*, which is exact on all 27 levels and is asserted. That is the
|
||||
fourth time in this session that a plausible reading of one number has had to be
|
||||
withdrawn in favour of a claim that can fail.
|
||||
|
||||
Word 0 is worth one note: levels 1 and 4 hold 13,042,052 and 13,042,054, two
|
||||
apart, while their `daw_size`s differ by 63,504. Whatever it is, it is not a
|
||||
size.
|
||||
|
||||
Asserted in `sound_bank_sblk_body_head_carries_the_daw_size_twice`. The remainder
|
||||
of the body -- a per-sound record table -- is still undecoded.
|
||||
|
||||
Reference in New Issue
Block a user