Closes the open question left by the take-2 audio capture, where the probe logged five streams on one boot when only ADV s three were accounted for. Both unexplained sizes are whole packet counts, 562 and 620. Searching every inter-descriptor span of the voice stream and every sound.pak entry large enough finds zero hits in the voice stream and ONE entry carrying both -- hash 9799c546, which candidate enumeration recovers as BGM_102.slb, two streams of 1150976 and 1269760 B. One entry holding both sizes is the two-stem shape rather than two coincidental matches. So the boot s five streams were ADV s three voice streams plus one music bank s two stems, and nothing is unaccounted for. What it does not establish is which screen it belongs to. The window ran from launch to t=253 s with the title arriving at 262, so BGM_102 was decoded somewhere inside a launch-to-just-before-title window -- but the probe fires on first decode and its lines carry a thread id rather than a timestamp, so a title BGM decoded moments before the title appears is equally consistent with the evidence. Cue 1103 is already the main menu, which makes 1102 as the title at least suggestive. The settling experiment is written down and not done. Refutation attempt on HANDOFF s BGM_103 wave sizes: exact match on both (3876864 / 3930112). The claim survives unchanged. Also a third route to two-stems-of-identical-duration, from the XMA1 header alone now that PsuedoBytesPerSec is read correctly: BGM_102 37.487/37.487, BGM_103 87.750/87.749, BGM_001 173.821/173.821. The one apparent disagreement resolves in the corpus s favour -- BGM_001 reads 173.821 here against the port s decoded 167.663, a gap of 6.158 s, and HANDOFF already records 6.15 s of trailing silence after its fade-out. Declared duration covers the encoded stream including that silence. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
41 lines
1.5 KiB
Rust
41 lines
1.5 KiB
Rust
//! List a sound bank's streams and their declared rates.
|
|
//!
|
|
//! cargo run -p sylpheed-formats --example bank_streams -- <disc> BGM_102.slb …
|
|
use sylpheed_formats::media::{self, DirectorySource};
|
|
use sylpheed_formats::{hash::name_hash, slb};
|
|
|
|
fn main() {
|
|
let mut a = std::env::args().skip(1);
|
|
let disc = a.next().expect("usage: bank_streams <disc> NAME.slb…");
|
|
let src = DirectorySource::new(std::path::PathBuf::from(&disc));
|
|
for name in a {
|
|
let h = name_hash(&name);
|
|
match media::read_sound_bank(&src, h) {
|
|
Ok(bytes) => {
|
|
let riffs = slb::to_xma_riffs(&bytes);
|
|
println!(
|
|
"{name} (hash {h:08x}, {} B on disc) header {:?} -> {} stream(s)",
|
|
bytes.len(),
|
|
slb::bank_header_len(&bytes),
|
|
riffs.len()
|
|
);
|
|
for (i, r) in riffs.iter().enumerate() {
|
|
let rate = if r.len() >= 0x28 {
|
|
u32::from_le_bytes(r[0x20..0x24].try_into().unwrap())
|
|
} else {
|
|
0
|
|
};
|
|
let payload = r.len() - 60;
|
|
println!(
|
|
" stream {i}: payload {payload} B ({} packets) declared {rate} B/s \
|
|
=> {:.3} s",
|
|
payload / 2048,
|
|
if rate > 0 { payload as f64 / rate as f64 } else { 0.0 }
|
|
);
|
|
}
|
|
}
|
|
Err(e) => println!("{name}: {e}"),
|
|
}
|
|
}
|
|
}
|