This branch predates CI on `main`. `cargo fmt --all` only; no behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
110 lines
4.4 KiB
Rust
110 lines
4.4 KiB
Rust
//! Is raising the start filter's 1.5 MB cap safe, disc-wide?
|
|
//!
|
|
//! `voice_region_fix_test.rs` shows that for `ADV` the predecessor start recovers
|
|
//! the decoder's own three byte_sizes exactly. But the cap exists to protect a
|
|
//! case: the code says *"only within one bank (~1.5 MB), else this is the first cue
|
|
//! in its block and the audio starts at the anchor itself"*. Raising it blindly
|
|
//! could pull a **previous asset's** streams into the region.
|
|
//!
|
|
//! So compare, per movie: the chunk list the resolver gives today against the one
|
|
//! the predecessor start gives. A safe change makes the FIRST chunk bigger and
|
|
//! leaves the rest identical. An unsafe one adds leading chunks.
|
|
//!
|
|
//! cargo run -p sylpheed-formats --example voice_region_cap_sweep
|
|
|
|
use sylpheed_formats::hash::name_hash;
|
|
use sylpheed_formats::media::{DirectorySource, DiscSource};
|
|
use sylpheed_formats::pak::PakArchive;
|
|
use sylpheed_formats::slb::{self, VoiceLang};
|
|
use sylpheed_formats::{movie_manifest, movie_voice};
|
|
|
|
fn main() {
|
|
let disc = std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC");
|
|
let src = DirectorySource::new(std::path::PathBuf::from(&disc));
|
|
let code = VoiceLang::English.code_pub();
|
|
let tpak = src.open_pak("dat/tables.pak").expect("tables.pak");
|
|
let manifest = tpak
|
|
.entries()
|
|
.iter()
|
|
.find_map(|e| tpak.read(e).ok().filter(|b| movie_manifest::is_manifest(b)))
|
|
.expect("manifest");
|
|
let marker = format!("{code}\\Movie\\VOICE_ADV.slb");
|
|
let registry = tpak
|
|
.entries()
|
|
.iter()
|
|
.find_map(|e| {
|
|
tpak.read(e)
|
|
.ok()
|
|
.filter(|b| b.windows(marker.len()).any(|w| w == marker.as_bytes()))
|
|
})
|
|
.expect("registry");
|
|
let ids = movie_voice::registry_voice_ids(®istry);
|
|
let stoc = src.read_file("dat/sound.pak").expect("sound.pak");
|
|
let entries = PakArchive::parse_toc(&stoc).expect("toc");
|
|
|
|
let (mut same, mut grew, mut extra, mut skip) = (0, 0, 0, 0);
|
|
for m in movie_manifest::parse(&manifest) {
|
|
let movie = m.movie;
|
|
let Some(token) = movie_manifest::voice_token(&manifest, &movie) else {
|
|
skip += 1;
|
|
continue;
|
|
};
|
|
let Some(&id) = ids.get(&token) else {
|
|
skip += 1;
|
|
continue;
|
|
};
|
|
let Some(anchor) = ["Movie", "etc", "Voice"].iter().find_map(|dir| {
|
|
let h = name_hash(&format!("{code}\\{dir}\\{token}.slb"));
|
|
entries
|
|
.binary_search_by_key(&h, |e| e.name_hash)
|
|
.ok()
|
|
.map(|i| entries[i].offset as u64)
|
|
}) else {
|
|
skip += 1;
|
|
continue;
|
|
};
|
|
let win_start = anchor.saturating_sub(2 * 1024 * 1024) & !3;
|
|
let Ok(window) = src.read_segment_range("dat/sound", win_start, 8 * 1024 * 1024) else {
|
|
skip += 1;
|
|
continue;
|
|
};
|
|
let Some(end_local) = movie_voice::find_descriptor(&window, id) else {
|
|
skip += 1;
|
|
continue;
|
|
};
|
|
let end = win_start + end_local as u64;
|
|
let cand = movie_voice::find_descriptor(&window, id.wrapping_sub(1))
|
|
.or_else(|| movie_voice::find_descriptor_before(&window, end_local))
|
|
.map(|o| win_start + o as u64)
|
|
.filter(|&s| s < end);
|
|
let today = cand.filter(|&s| end - s < 1_500_000).unwrap_or(anchor);
|
|
let Some(proposed) = cand else {
|
|
skip += 1;
|
|
continue;
|
|
};
|
|
if today == proposed {
|
|
same += 1;
|
|
continue;
|
|
}
|
|
let sizes = |s: u64| -> Vec<usize> {
|
|
src.read_segment_range("dat/sound", s, (end - s) as usize)
|
|
.map(|b| slb::to_xma_riffs(&b).iter().map(|r| r.len() - 60).collect())
|
|
.unwrap_or_default()
|
|
};
|
|
let (a, b) = (sizes(today), sizes(proposed));
|
|
let tail_same = a.len() == b.len() && a.iter().skip(1).eq(b.iter().skip(1));
|
|
let verdict = if a.len() == b.len() && tail_same && b[0] > a[0] {
|
|
grew += 1;
|
|
"first chunk GREW, tail identical"
|
|
} else if b.len() > a.len() {
|
|
extra += 1;
|
|
"EXTRA leading chunks"
|
|
} else {
|
|
extra += 1;
|
|
"changed otherwise"
|
|
};
|
|
println!("{movie:10} today {a:?}\n{:10} prop {b:?} {verdict}", "");
|
|
}
|
|
println!("\nunchanged {same} fixed-cleanly {grew} would-break {extra} skipped {skip}");
|
|
}
|