slb: the headerless path was decoding stereo at a fixed offset; both are wrong
1495 banks carry no RIFF and take a separate path that hardcoded both the offset and stereo. Across a random 48-bank sample there was NOT ONE where the old stereo-at-1392 pair beat the best mono offset; median gain 184x, individual banks going from 0-4816 decoded bytes to 180000-380000. Stereo shows the same stop-after-one-frame signature already recorded for the leading segment. With no RIFF the offset cannot be derived, so scan_data_offset picks among the four disc offsets by XMA1 packet-header plausibility. Validated on the LABELLED set -- all 7358 banks that do have a RIFF, where the answer is forced: 7330 correct (99.62%), and all 28 misses are ties on the top score, never a wrong unique winner. Ties fall back to 1392. The winning offsets also reproduce, by directory, the distribution measured independently from the RIFF-bearing banks. jpn\etc splits 1468/1600, so path alone is not sufficient -- which is why this is a scan and not a lookup table. 7 disc tests pass (build-reborn test -p sylpheed-formats --test slb_leading_segment_disc, SYLPHEED_DISC wired up).
This commit is contained in:
@@ -153,3 +153,69 @@ fn derived_offset_recovers_voice_banks_without_regressing_etc() {
|
||||
b.windows(4).position(|w| w == b"RIFF").unwrap()),
|
||||
slb::HEADERLESS_DATA_OFFSET);
|
||||
}
|
||||
|
||||
/// The scan agrees with the truth wherever the truth is knowable.
|
||||
///
|
||||
/// A bank carrying a `RIFF` has its offset *forced* to `first_riff % 2048`, so
|
||||
/// those banks are a labelled set for a rule meant to serve the ones without a
|
||||
/// `RIFF`. Over the whole labelled set the scan is right 99.6 % of the time and
|
||||
/// its only failures are ties. This test walks a slice of it.
|
||||
#[test]
|
||||
fn scan_data_offset_agrees_with_the_riff_derived_answer() {
|
||||
skip_without_disc!(root);
|
||||
let snd = PakArchive::open(root.join("dat/sound.pak")).expect("sound.pak");
|
||||
let mut checked = 0usize;
|
||||
let mut agreed = 0usize;
|
||||
for lang in ["eng", "jpn"] {
|
||||
for (dir, lo, hi) in [("Voice", 1u32, 120u32), ("etc", 1, 120)] {
|
||||
for n in lo..hi {
|
||||
let path = format!("{lang}\\{dir}\\VOICE_TCAF_{n:03}.slb");
|
||||
let Some(entry) = snd.find_by_name(&path) else { continue };
|
||||
let Ok(b) = snd.read(entry) else { continue };
|
||||
let Some(ri) = b.windows(4).position(|w| w == b"RIFF") else { continue };
|
||||
if ri <= slb::HEADERLESS_DATA_OFFSET {
|
||||
continue;
|
||||
}
|
||||
if !b[slb::HEADERLESS_DATA_OFFSET..ri].iter().any(|v| *v != 0) {
|
||||
continue;
|
||||
}
|
||||
checked += 1;
|
||||
if slb::scan_data_offset(&b) == slb::leading_data_offset(ri) {
|
||||
agreed += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(checked >= 20, "expected a usable labelled set, got {checked}");
|
||||
// The whole-disc rate is 99.62%; allow a little slack for a small slice.
|
||||
let rate = agreed as f64 / checked as f64;
|
||||
assert!(
|
||||
rate >= 0.95,
|
||||
"scan agreed on {agreed}/{checked} ({:.1}%), expected >=95%",
|
||||
rate * 100.0
|
||||
);
|
||||
}
|
||||
|
||||
/// Every offset the scan can return is one of the four seen on disc.
|
||||
#[test]
|
||||
fn scan_only_returns_known_offsets() {
|
||||
skip_without_disc!(root);
|
||||
let snd = PakArchive::open(root.join("dat/sound.pak")).expect("sound.pak");
|
||||
let mut seen = 0usize;
|
||||
for n in 1u32..200 {
|
||||
for path in [
|
||||
format!("eng\\Voice\\VOICE_ADAN_{n:03}.slb"),
|
||||
format!("jpn\\Voice\\VOICE_ADAN_{n:03}.slb"),
|
||||
] {
|
||||
let Some(entry) = snd.find_by_name(&path) else { continue };
|
||||
let Ok(b) = snd.read(entry) else { continue };
|
||||
let got = slb::scan_data_offset(&b);
|
||||
assert!(
|
||||
slb::DATA_OFFSET_CANDIDATES.contains(&got),
|
||||
"{path}: scan returned {got}, not a known offset"
|
||||
);
|
||||
seen += 1;
|
||||
}
|
||||
}
|
||||
assert!(seen >= 20, "expected banks to test, saw {seen}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user