re: which ADV stream sits where -- settled by level, not by waveform
Completes ask #4. The three chunks were dumped from the resolved voice region and decoded; the assignment is ctx0 -> FL/FR, ctx1 -> FC with LFE silent, ctx2 -> BL/BR. Two instruments failed first and both look like results, so both are recorded. Envelope correlation with a per-pair lag search returns 0.86-0.95 for EVERY chunk against EVERY channel, because all six residual channels share the dialogue's activity timing -- that is an instrument with no resolving power, not a finding. Sample-level correlation returns about zero, because the chunks do not start with the movie and the XMA decode's framing offset is unknown. Level settles it under the same 0.600 gain the bed uses: each stream lands within 0.5 dB of exactly one residual pair and misses the others by 4-6 dB. The ratio test is immune to chunk 0 being a clipped tail of ctx0 -- chunk0 - chunk2 is +5.88 dB against FL - BL at +6.18 dB, agreeing to 0.30 dB, where a swap would be wrong by 11.76 dB. Structural confirmation: chunk 1 is the only chunk with a digitally silent channel and LFE is the only output channel with an empty residual (-115.73 dBFS), one to one; and the internal L/R correlations track the residual pairs' (0.932 vs 0.918, 0.962 vs 0.929). Worth having on its own: the same 0.600 scales both the movie bed and the voice, so it is one mixer gain rather than two. Reach: levels, not waveforms; one boot, one movie; and whether 0.600 is a fixed constant or a volume setting is still unknown. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
This commit is contained in:
41
crates/sylpheed-formats/examples/adv_voice_dump.rs
Normal file
41
crates/sylpheed-formats/examples/adv_voice_dump.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//! Dump `ADV`'s voice chunks as RIFF/XMA, so each can be decoded and identified.
|
||||||
|
//!
|
||||||
|
//! `intro-audio-decomposed.md` measured that the intro's output is the movie's own
|
||||||
|
//! WMA Pro 5.1 track at 0.600 **plus** three streams occupying a front pair, a
|
||||||
|
//! centre (with a silent partner) and a rear pair. What it could **not** say is
|
||||||
|
//! *which* stream sits where — the assignment there is by position, not content.
|
||||||
|
//! The port needs that to weight a positional downmix.
|
||||||
|
//!
|
||||||
|
//! This writes the chunks out so they can be decoded (ffmpeg has `xma2`) and
|
||||||
|
//! correlated against the per-channel residuals.
|
||||||
|
//!
|
||||||
|
//! cargo run -p sylpheed-formats --example adv_voice_dump -- OUTDIR [MOVIE]
|
||||||
|
|
||||||
|
use sylpheed_formats::media::{self, DirectorySource, DiscSource};
|
||||||
|
use sylpheed_formats::slb::{self, VoiceLang};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out = std::env::args().nth(1).expect("OUTDIR");
|
||||||
|
let movie = std::env::args().nth(2).unwrap_or_else(|| "ADV".into());
|
||||||
|
let disc = std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC");
|
||||||
|
let src = DirectorySource::new(std::path::PathBuf::from(&disc));
|
||||||
|
std::fs::create_dir_all(&out).expect("outdir");
|
||||||
|
|
||||||
|
let (start, end) = media::resolve_movie_voice_region(&src, &movie, VoiceLang::English)
|
||||||
|
.expect("voice region");
|
||||||
|
let bytes = src
|
||||||
|
.read_segment_range("dat/sound", start, (end - start) as usize)
|
||||||
|
.expect("region");
|
||||||
|
println!("{movie}: region {start}..{end} = {} B", end - start);
|
||||||
|
|
||||||
|
let riffs = slb::to_xma_riffs(&bytes);
|
||||||
|
println!("{} RIFF chunk(s)", riffs.len());
|
||||||
|
for (i, r) in riffs.iter().enumerate() {
|
||||||
|
let p = format!("{out}/{movie}_{i}.xma");
|
||||||
|
std::fs::write(&p, r).expect("write");
|
||||||
|
// the probe reports `byte_size` = RIFF total - 60; print both so the
|
||||||
|
// dump can be tied to a specific XMA context by its own number
|
||||||
|
println!(" chunk {i}: {} B byte_size-equivalent {} -> {p}",
|
||||||
|
r.len(), r.len() as i64 - 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2565,9 +2565,31 @@ not apply to this capture** — the measured map is the identity. So the census'
|
|||||||
silent LFE. Measure channel order per capture; a 6×6 matrix that comes out a clean
|
silent LFE. Measure channel order per capture; a 6×6 matrix that comes out a clean
|
||||||
permutation is its own control.
|
permutation is its own control.
|
||||||
|
|
||||||
⚠️ Reach: one boot, one movie. **Which** of the three XMA contexts is front, centre
|
✅ **UPDATE — the assignment is now determined, so your weights are unblocked:**
|
||||||
or rear is *not* determined — the assignment above is by position. And whether 0.600
|
|
||||||
is a fixed mix constant or a volume setting is unknown.
|
| stream | `byte_size` | → | downmix weight you cited |
|
||||||
|
|---|---|---|---|
|
||||||
|
| ctx0 | 1 294 336 | **FL, FR** | 0.4142 |
|
||||||
|
| ctx1 | 1 118 208 | **FC** (LFE silent) | 0.2929 |
|
||||||
|
| ctx2 | 1 171 456 | **BL, BR** | 0.2929 |
|
||||||
|
|
||||||
|
Settled by **level**, under the same 0.600 gain the bed uses: each stream lands
|
||||||
|
within **0.5 dB** of exactly one residual pair and misses the others by 4–6 dB.
|
||||||
|
Ratio test (immune to chunk 0 being a clipped tail): chunk0 − chunk2 = +5.88 dB
|
||||||
|
against FL − BL = +6.18 dB, agreeing to 0.30 dB; swapped it would be wrong by 11.76.
|
||||||
|
Structural confirmation: ctx1 is the only stream with a digitally silent channel and
|
||||||
|
LFE is the only channel with an empty residual. ✅ **One mixer gain, not two** — the
|
||||||
|
same 0.600 scales bed and voice.
|
||||||
|
|
||||||
|
🔴 **Two instruments failed first and both looked convincing** — worth knowing
|
||||||
|
before you try to reproduce it. Envelope correlation returns **0.86–0.95 for every
|
||||||
|
stream against every channel**, because all six channels share the dialogue's
|
||||||
|
timing; that is no resolving power, not a result. Sample-level correlation returns
|
||||||
|
≈ 0, because the chunks do not start with the movie.
|
||||||
|
|
||||||
|
⚠️ Reach: levels, not waveforms — three numbers agreeing to 0.5 dB plus a 1:1
|
||||||
|
structural match. One boot, one movie. Whether 0.600 is a fixed mix constant or a
|
||||||
|
volume setting is still unknown.
|
||||||
[`intro-audio-decomposed.md`](../re/structures/intro-audio-decomposed.md) ·
|
[`intro-audio-decomposed.md`](../re/structures/intro-audio-decomposed.md) ·
|
||||||
[numbers](../re/data/intro-audio-decomposition.txt)
|
[numbers](../re/data/intro-audio-decomposition.txt)
|
||||||
|
|
||||||
|
|||||||
46
docs/re/data/adv-stream-assignment.txt
Normal file
46
docs/re/data/adv-stream-assignment.txt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Which ADV voice stream sits where -- the assignment, and how it was settled.
|
||||||
|
#
|
||||||
|
# 2026-08-30. Chunks dumped by examples/adv_voice_dump.rs from the resolved
|
||||||
|
# movie voice region (dat/sound 433930240..437044592), decoded with ffmpeg's
|
||||||
|
# xma decoder to f32le 48 kHz stereo.
|
||||||
|
#
|
||||||
|
# chunk bytes byte_size probe ctx dur L rms R rms L/R r R silent
|
||||||
|
# 0 806972 806912 ctx0 TAIL 84.55s -24.79 -24.81 +0.932 53.1%
|
||||||
|
# 1 1118268 1118208 ctx1 137.32s -20.33 -inf +0.000 100.0%
|
||||||
|
# 2 1171516 1171456 ctx2 137.32s -30.67 -30.68 +0.962 53.6%
|
||||||
|
#
|
||||||
|
# ctx0's full byte_size is 1294336; the region resolver starts at the
|
||||||
|
# predecessor cue's trailer, so chunk 0 is its clipped tail (62 %).
|
||||||
|
#
|
||||||
|
# 🔴 WHAT DID NOT WORK: envelope correlation cannot discriminate.
|
||||||
|
# Every residual channel shares the dialogue's activity timing, so a
|
||||||
|
# per-pair lag search returns 0.86-0.95 for EVERY chunk against EVERY
|
||||||
|
# channel. Recorded because it looks like a strong result and is not.
|
||||||
|
#
|
||||||
|
# 🔴 Sample-level correlation also fails: the chunks do not start with the
|
||||||
|
# movie and the XMA decode's framing offset is unknown, so r ~ 0.
|
||||||
|
#
|
||||||
|
# ✅ WHAT SETTLES IT: level, under the SAME 0.600 gain the bed uses.
|
||||||
|
#
|
||||||
|
# chunk level x0.600 nearest residuals (|error| dB)
|
||||||
|
# 0L -24.79 -29.23 FL 0.05 FR 0.06 FC 3.96
|
||||||
|
# 0R -24.81 -29.25 FL 0.03 FR 0.04 FC 3.98
|
||||||
|
# 1L -20.33 -24.77 FC 0.50 FL 4.51 FR 4.52
|
||||||
|
# 2L -30.67 -35.11 BL 0.35 BR 0.38 FR 5.82
|
||||||
|
# 2R -30.68 -35.12 BL 0.34 BR 0.37 FR 5.83
|
||||||
|
#
|
||||||
|
# Ratio test, immune to any worry about chunk 0 being clipped:
|
||||||
|
# chunk0L - chunk2L = +5.88 dB ; FL - BL = +6.18 dB -> agree to 0.30 dB
|
||||||
|
# swapped, the ratio would be wrong by 11.76 dB
|
||||||
|
#
|
||||||
|
# Structural confirmation: chunk 1 is the ONLY chunk with a digitally silent
|
||||||
|
# channel (R, 100 %), and LFE is the ONLY output channel with an empty
|
||||||
|
# residual (-115.73 dBFS). One-to-one.
|
||||||
|
#
|
||||||
|
# Internal L/R correlation also tracks:
|
||||||
|
# chunk0 +0.932 <-> FL/FR residual +0.918
|
||||||
|
# chunk2 +0.962 <-> BL/BR residual +0.929
|
||||||
|
#
|
||||||
|
# ==> ctx0 (1294336) -> FL, FR
|
||||||
|
# ==> ctx1 (1118208) -> FC, LFE silent
|
||||||
|
# ==> ctx2 (1171456) -> BL, BR
|
||||||
@@ -93,9 +93,63 @@ clean permutation is its own control.**
|
|||||||
## Reach
|
## Reach
|
||||||
|
|
||||||
⚠️ **One boot, one movie.** `ADV` only.
|
⚠️ **One boot, one movie.** `ADV` only.
|
||||||
⚠️ **The stream→channel assignment is by position, not by content.** Which of the
|
✅ **The assignment is now determined** — see the section below. It was open when
|
||||||
three XMA contexts is the front, centre or rear stream is *not* determined here —
|
this page was first written.
|
||||||
that needs the streams decoded and correlated individually, which was not done.
|
|
||||||
⚠️ `--gpu=null`, so no video cross-check.
|
⚠️ `--gpu=null`, so no video cross-check.
|
||||||
✅ The 0.600 gain is measured on this run; whether it is a fixed mix constant or a
|
✅ The 0.600 gain is measured on this run; whether it is a fixed mix constant or a
|
||||||
volume setting is not established.
|
volume setting is not established.
|
||||||
|
|
||||||
|
|
||||||
|
## ✅ Which stream is which (2026-08-30, later)
|
||||||
|
|
||||||
|
The three chunks were dumped from the resolved voice region
|
||||||
|
(`examples/adv_voice_dump.rs`) and decoded:
|
||||||
|
[`../data/adv-stream-assignment.txt`](../data/adv-stream-assignment.txt).
|
||||||
|
|
||||||
|
| chunk | `byte_size` | probe ctx | L rms | R rms | R silent |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 0 | 806 912 | **ctx0, clipped tail** (full 1 294 336) | −24.79 | −24.81 | 53.1 % |
|
||||||
|
| 1 | 1 118 208 | ctx1 | −20.33 | **−inf** | **100 %** |
|
||||||
|
| 2 | 1 171 456 | ctx2 | −30.67 | −30.68 | 53.6 % |
|
||||||
|
|
||||||
|
### 🔴 Two instruments failed first, and both look convincing
|
||||||
|
|
||||||
|
* **Envelope correlation cannot discriminate.** A per-pair lag search returns
|
||||||
|
**0.86–0.95 for every chunk against every channel**, because all six residual
|
||||||
|
channels share the dialogue's activity timing. A number that high reads as a
|
||||||
|
result; it is the instrument having no resolving power. Recorded so nobody
|
||||||
|
reports it as one.
|
||||||
|
* **Sample-level correlation returns ≈ 0.** The chunks do not start with the movie
|
||||||
|
and the XMA decode's framing offset is unknown.
|
||||||
|
|
||||||
|
### ✅ Level settles it, under the same 0.600 gain
|
||||||
|
|
||||||
|
| chunk | level | × 0.600 | nearest residuals (error, dB) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 0L | −24.79 | −29.23 | **FL 0.05** · FR 0.06 · FC 3.96 |
|
||||||
|
| 1L | −20.33 | −24.77 | **FC 0.50** · FL 4.51 |
|
||||||
|
| 2L | −30.67 | −35.11 | **BL 0.35** · BR 0.38 · FR 5.82 |
|
||||||
|
|
||||||
|
Each stream lands within **0.5 dB** of exactly one residual pair and misses the
|
||||||
|
others by ~4–6 dB. **The same 0.600 that scales the movie bed also scales the
|
||||||
|
voice** — which is itself worth having: it is one mixer gain, not two.
|
||||||
|
|
||||||
|
✅ **Ratio test, immune to chunk 0 being clipped:** chunk0 − chunk2 = **+5.88 dB**
|
||||||
|
against FL − BL = **+6.18 dB**, agreeing to **0.30 dB**; swapped, the ratio would be
|
||||||
|
wrong by **11.76 dB**.
|
||||||
|
|
||||||
|
✅ **Structural confirmation.** Chunk 1 is the *only* chunk with a digitally silent
|
||||||
|
channel, and LFE is the *only* output channel with an empty residual (−115.73 dBFS).
|
||||||
|
One to one. And the internal L/R correlations track: chunk 0 **+0.932** against the
|
||||||
|
FL/FR residual's **+0.918**, chunk 2 **+0.962** against BL/BR's **+0.929**.
|
||||||
|
|
||||||
|
| stream | → |
|
||||||
|
|---|---|
|
||||||
|
| ctx0 · 1 294 336 | **FL, FR** |
|
||||||
|
| ctx1 · 1 118 208 | **FC** (LFE silent) |
|
||||||
|
| ctx2 · 1 171 456 | **BL, BR** |
|
||||||
|
|
||||||
|
⚠️ **Reach.** Levels, not waveforms — this is an argument from three numbers
|
||||||
|
agreeing to 0.5 dB and a 1:1 structural match, not from a matched waveform. One
|
||||||
|
movie, one boot. And chunk 0 is a clipped tail, which is why the ratio test is
|
||||||
|
quoted alongside the absolute match.
|
||||||
|
|||||||
Reference in New Issue
Block a user