use std::fs; use std::io::{Read, Seek, SeekFrom}; use std::process::Command; use sylpheed_formats::slb; fn rg(disc: &str, g: u64, n: usize) -> Vec { let mut segs = vec![]; let mut cum = 0u64; for i in 0..5 { let p = format!("{disc}/dat/sound.p{i:02}"); if let Ok(m) = fs::metadata(&p) { segs.push((cum, m.len(), p)); cum += m.len(); } } let mut out = vec![]; let (mut need, mut pos) = (n, g); for (base, len, path) in &segs { if need == 0 || pos >= base + len || pos < *base { continue; } let local = pos - base; let take = need.min((len - local) as usize); let mut f = fs::File::open(path).unwrap(); f.seek(SeekFrom::Start(local)).unwrap(); let mut b = vec![0u8; take]; f.read_exact(&mut b).unwrap(); out.extend_from_slice(&b); need -= take; pos += take as u64; } out } fn dur(w: &str) -> String { let o = Command::new("ffprobe") .args([ "-v", "error", "-show_entries", "format=duration:stream=channels", "-of", "default=nw=1:nk=1", w, ]) .output() .unwrap(); String::from_utf8_lossy(&o.stdout).replace('\n', " ") } fn movdur(disc: &str, m: &str) -> String { dur(&format!("{disc}/dat/movie/{m}")) } fn main() { let disc = std::env::var("SYLPHEED_DISC").unwrap(); // descriptor trailer global offsets (from scan) => cue N data = [desc(N-1)..desc(N)] // (id, end_off, movie) let cues = [ (1600u32, 437044592u64, "ADV.wmv"), (1601, 437345648, "RT01A.wmv"), (1602, 437712240, "RT01B.wmv"), (1603, 438080880, "RT01C_1.wmv"), (1604, 438451568, "RT01C_2.wmv"), (1605, 438789488, "RT02A.wmv"), ]; for k in 1..cues.len() { let (id, end, mov) = cues[k]; let start = cues[k - 1].1; let region = rg(&disc, start, (end - start) as usize + 12000); // +tail to include full data before next trailer let riffs = slb::to_xma_riffs(®ion); let mut total = 0.0f32; let mut parts = vec![]; for (j, r) in riffs.iter().enumerate() { let xp = format!("/tmp/cue{id}_{j}.xma.wav"); let wp = format!("/tmp/cue{id}_{j}.wav"); fs::write(&xp, r).unwrap(); let _ = Command::new("ffmpeg") .args(["-hide_banner", "-v", "error", "-y", "-i", &xp, &wp]) .status(); let d = dur(&wp); parts.push(d.clone()); total += d .split_whitespace() .next() .unwrap_or("0") .parse::() .unwrap_or(0.0); } // spanning? let span_adv_end = 437547264u64; let _spans = start < span_adv_end && end > span_adv_end || (start / 1_000 != end / 1_000); println!("cue {id} ({mov}): region[{start}..{end}] {} bytes, {} riff(s), Σ={:.1}s | movie={} parts={:?}", end-start, riffs.len(), total, movdur(&disc,mov), parts); } println!("\nWAVs at /tmp/cue16XX_*.wav (listen: RT01B=1602, RT01C_1=1603, RT01C_2=1604)"); }