//! The `.slb` leading segment — recovered, and scoped. //! //! `VOICE_D_453` used to decode to 0.14 s because its line lives in a headerless //! packet stream *before* the first `RIFF`, and the decoder started at the //! `RIFF`. The banks that looked fine were the ones whose leading segment is //! silence. One rule, two outcomes. use std::path::Path; use std::sync::OnceLock; use sylpheed_formats::{slb, PakArchive}; mod common; use common::skip_without_disc; /// One archive for the whole binary. /// /// `PakArchive` holds the entire concatenated payload in memory, and /// `sound.pak` is **1.01 GB** (`sound.p00`-`.p04`). Opening it per call — which /// the helpers below did, inside loops — put one copy per test thread in flight, /// so at the default thread count the suite needed ~6 GB and was SIGKILLed by /// the CI container's 7 GB cap (`--memory-swap` equals `--memory`, so there is /// no swap to absorb it). A killed suite prints no `test result:` line at all, /// so it vanishes from the tally rather than failing visibly. /// /// The archive is immutable once open and every accessor takes `&self`, so one /// shared instance is equivalent to N private ones — at 1/N the memory. fn sound(root: &Path) -> &'static PakArchive { static SOUND: OnceLock = OnceLock::new(); // Every caller passes the same `disc_root()`, so first-writer-wins is the // same archive whichever test initialises it. SOUND.get_or_init(|| PakArchive::open(root.join("dat/sound.pak")).expect("sound.pak")) } fn bank(root: &Path, n: u32) -> Vec { let snd = sound(root); let path = format!("eng\\etc\\VOICE_D_{n}.slb"); let entry = snd.find_by_name(&path).expect("bank present"); snd.read(entry).expect("read") } /// The boundary is arithmetic and has no tunable: the first `RIFF` sits at /// exactly `HEADERLESS_DATA_OFFSET + n*XMA1_PACKET` in every resupply bank. #[test] fn leading_segment_is_a_whole_number_of_packets() { skip_without_disc!(root); for (n, packets) in [(450u32, 8usize), (451, 1), (452, 7), (453, 22), (454, 29)] { let b = bank(&root, n); let ri = b.windows(4).position(|w| w == b"RIFF").expect("has a RIFF"); assert!(ri > slb::HEADERLESS_DATA_OFFSET, "VOICE_D_{n}"); let lead = ri - slb::HEADERLESS_DATA_OFFSET; assert_eq!( lead % slb::XMA1_PACKET, 0, "VOICE_D_{n} not a whole packet count" ); assert_eq!(lead / slb::XMA1_PACKET, packets, "VOICE_D_{n} packet count"); } } /// The two banks whose line lives in the leading segment now yield it. #[test] fn broken_banks_recover_their_line() { skip_without_disc!(root); // (bank, sub-waves expected, payload of the leading one) for (n, waves, lead_len) in [(453u32, 2usize, 45116usize), (454, 2, 59452)] { let riffs = slb::to_xma_riffs(&bank(&root, n)); assert_eq!(riffs.len(), waves, "VOICE_D_{n} sub-wave count"); assert_eq!(riffs[0].len(), lead_len, "VOICE_D_{n} leading segment"); // It must be the LARGER part: that is the whole point. assert!( riffs[0].len() > riffs[1].len() * 5, "VOICE_D_{n}: leading segment should dominate" ); } } /// `VOICE_D_451`'s leading region is all zeros — the guard must skip it, so the /// rule cannot prepend silence to a bank that does not need it. #[test] fn all_zero_leading_region_is_skipped() { skip_without_disc!(root); let b = bank(&root, 451); let ri = b.windows(4).position(|w| w == b"RIFF").unwrap(); assert!( b[slb::HEADERLESS_DATA_OFFSET..ri].iter().all(|x| *x == 0), "expected an all-zero leading region" ); // Two sub-waves, both from the RIFF section — no synthesised third. assert_eq!(slb::to_xma_riffs(&b).len(), 2); } fn bank_named(root: &Path, path: &str) -> Vec { let snd = sound(root); let entry = snd .find_by_name(path) .unwrap_or_else(|| panic!("{path} present")); snd.read(entry).expect("read") } /// `HEADERLESS_DATA_OFFSET` is the `\etc\` case, not the format. /// /// The leading stream is a whole number of packets ending at the first `RIFF`, /// so its start is `first_riff % XMA1_PACKET`. Disc-wide that takes four values /// and only 1392 matches the old constant — assuming it elsewhere starts the /// decode mid-packet. See docs/re/structures/slb-data-offset.md. #[test] fn leading_data_offset_is_derived_not_assumed() { skip_without_disc!(root); // (bank, expected derived offset). The `etc` banks must still land on the // old constant — that is the no-regression half of the test. for (path, want) in [ ("eng\\etc\\VOICE_D_452.slb", 1392usize), ("eng\\etc\\VOICE_D_453.slb", 1392), ("eng\\Voice\\VOICE_TCAF_592.slb", 1468), ("jpn\\Voice\\VOICE_TCAF_592.slb", 1728), ("jpn\\etc\\VOICE_D_452.slb", 1600), ] { let b = bank_named(&root, path); let ri = b.windows(4).position(|w| w == b"RIFF").expect("has a RIFF"); let got = slb::leading_data_offset(ri); assert_eq!(got, want, "{path}: derived offset"); assert_eq!( (ri - got) % slb::XMA1_PACKET, 0, "{path}: leading stream is not a whole packet count" ); assert!( got >= slb::HEADERLESS_DATA_OFFSET, "{path}: offsets below the old constant are unexplained" ); } } /// The banks the old constant mis-decoded now carry a leading sub-wave, and the /// ones it decoded correctly are untouched. #[test] fn derived_offset_recovers_voice_banks_without_regressing_etc() { skip_without_disc!(root); for path in [ "eng\\Voice\\VOICE_TCAF_592.slb", "jpn\\Voice\\VOICE_TCAF_592.slb", ] { let b = bank_named(&root, path); let ri = b.windows(4).position(|w| w == b"RIFF").expect("has a RIFF"); // Under the old constant this leading region was not a whole packet // count, so `to_xma_riffs` emitted no leading sub-wave at all. assert_ne!( (ri - slb::HEADERLESS_DATA_OFFSET) % slb::XMA1_PACKET, 0, "{path}: expected the OLD constant to mis-align here" ); let riffs = slb::to_xma_riffs(&b); assert!( riffs.len() >= 2, "{path}: expected a leading sub-wave plus at least one RIFF, got {}", riffs.len() ); } // Control: an `etc` bank still produces what it did before. let b = bank_named(&root, "eng\\etc\\VOICE_D_452.slb"); assert_eq!( slb::leading_data_offset(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 = sound(&root); 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 = sound(&root); 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}"); } /// A wave's boundary is exact: `seek` magic sits at `data_at + declared_size`. /// /// Established 2026-08-26 (docs/re/structures/slb-data-offset.md). Every /// `RIFF`-bearing entry on the disc satisfies it — **7 620/7 620** in the full /// sweep — and the `seek` chunk's little-endian packet count at `+12` times /// 2048 equals the declared size. This is the decoder-independent boundary, and /// it is what proves the declared sizes honest rather than over-stated. /// /// The test walks a bounded slice so it stays fast; the identity is disc-wide. #[test] fn a_waves_declared_size_is_confirmed_by_the_next_seek() { skip_without_disc!(root); let snd = sound(&root); let mut checked = 0usize; for n in 1u32..400 { for path in [ format!("eng\\etc\\VOICE_D_{n}.slb"), format!("eng\\Voice\\VOICE_TCAF_{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 Some(ri) = b.windows(4).position(|w| w == b"RIFF") else { continue; }; let Some(rel) = b[ri..].windows(4).position(|w| w == b"data") else { continue; }; let di = ri + rel; let Some(sz) = b.get(di + 4..di + 8) else { continue; }; let declared = u32::from_le_bytes(sz.try_into().unwrap()) as usize; // The boundary lies outside this entry's own TOC window whenever the // declared size overruns it, which is the common case — so read from // the archive's flat data rather than from the entry slice. let probe = entry.offset as usize + di + 8 + declared; let Some(tag) = snd.data_at(probe, 16) else { continue; }; assert_eq!( &tag[0..4], b"seek", "{path}: expected `seek` at data_at+declared ({probe})" ); let packets = u32::from_le_bytes(tag[12..16].try_into().unwrap()) as usize; assert_eq!( packets * slb::XMA1_PACKET, declared, "{path}: seek packet count x 2048 != declared data size" ); checked += 1; } } assert!(checked >= 30, "expected banks to check, got {checked}"); eprintln!("wave-boundary identity held for {checked} banks"); } /// A **music** bank has no leading segment — the bytes before its first `RIFF` /// are the bank header, and emitting them made `BGM_103` look like three stems. /// /// The header sizes itself (`+0x24`, in 2048-byte blocks), and on every bank on /// this disc that size lands exactly on the first `RIFF`. So the guard is not a /// heuristic and has no threshold: if a bank states a header, believe it. #[test] fn a_bank_that_states_its_own_header_has_no_leading_segment() { skip_without_disc!(root); let snd = sound(&root); let mut with_header = 0usize; let mut mid_bank = 0usize; // Peek at the 56-byte header through the archive's flat data rather than // decompressing 9 519 entries: `sound.pak` stores them uncompressed, and a // full read of all of them is several GB (it OOM-killed the test runner). for entry in snd.entries() { let Some(head) = snd.data_at(entry.offset as usize, 0x38) else { continue; }; match slb::bank_header_len(head) { Some(h) => { let b = snd.read(entry).expect("read a bank that states a header"); let ri = b.windows(4).position(|w| w == b"RIFF").expect("has a RIFF"); // Declared header ends exactly at the first RIFF: no gap, so // nothing before it can be a packet stream. assert_eq!(h, ri, "a bank header that does not end at its first RIFF"); with_header += 1; } None => mid_bank += 1, } } // 28 music banks (ids 1001-1023, 1101-1105); the rest are mid-bank windows, // where the leading region IS real and must keep being emitted. assert_eq!( with_header, 28, "banks stating their own header at offset 0" ); assert!(mid_bank > 9000, "mid-bank windows, got {mid_bank}"); eprintln!("{with_header} banks state a header; {mid_bank} mid-bank windows"); } /// The regression itself: the menu's music bank is **two** sub-waves, and they /// are the two the corpus names — matching the executable's `BGM_103` and the /// two streams the runtime XMA probe saw at the main menu. #[test] fn the_menu_music_bank_is_exactly_two_sub_waves() { skip_without_disc!(root); let snd = sound(&root); for (name, sizes) in [ ("BGM_103.slb", [3_876_864usize, 3_930_112]), ("BGM_001.slb", [4_466_688, 4_673_536]), ] { let entry = snd.find_by_name(name).expect("bank present"); let b = snd.read(entry).expect("read"); let riffs = slb::to_xma_riffs(&b); assert_eq!(riffs.len(), 2, "{name}: sub-wave count"); for (r, want) in riffs.iter().zip(sizes) { let di = r.windows(4).position(|w| w == b"data").expect("data chunk"); let got = u32::from_le_bytes(r[di + 4..di + 8].try_into().unwrap()) as usize; assert_eq!(got, want, "{name}: sub-wave payload size"); } } }