diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index 883c0c7d..caab3b39 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -3624,3 +3624,46 @@ and whose role is not."* provenance is the XMA probe showing `ADV`'s three streams decoding during the run, which for an audio question evidences the thing recorded rather than what was on screen. + +## The stripping control passes — `S00A` is obtainable, and the gate is cleared + +The Decoder made this the gate on `S00A`, and it is the right call: `ADV` plays +itself on boot so it can be captured with `--gpu=null` at 0.96× real time, but +`S00A` starts ~4.5 s after Ⓐ on a save slot, which needs a **driven** run, which +needs screens, which rules out `--gpu=null`. So `S00A` is necessarily the 0.70× +rendered route with ~10 % additive padding — and is only worth a boot if +stripping that padding is exact. + +**It is.** A real music+SFX bed (137.37 s, carrying 454 genuine zero runs of its +own) had 1 149 holes inserted at 8.37/s to +9.9 % length, matching the observed +ALSA profile, then was stripped and correlated in the low band: + +| | *r* | lag | margin | +|---|---|---|---| +| original vs itself — **ceiling** | 1.000 | 0.0 s | +0.141 | +| **padded** vs original — what padding costs | **0.436** | −12.2 s | **+0.006** | +| **stripped** vs original — recovered | **1.000** | **0.0 s** | **+0.142** | +| stripped vs original-also-stripped | 1.000 | 0.0 s | +0.143 | + +**Two things worth reading off that table.** + +First, **padding at that profile destroys correlation completely** — r 0.436, +margin +0.006, which is the known-absent regime. That independently confirms, on +a file whose contents I control, that the earlier captures were unusable for the +reason claimed rather than for some other reason. + +Second, **recovery does not require stripping both sides.** The stripped capture +matches the *unstripped* source at the ceiling. That matters operationally: the +port's reference assets never need touching. + +⚠️ **What the control does not license.** Stripping removes genuine silence too +and cannot tell the two apart. On this material the genuine runs total 0.71 s in +137 s and cost nothing measurable; on material that is mostly silence they would. +And the whole thing rests on the **substituted-versus-additive** distinction — it +is valid for Xenia's ALSA padding, which inserts, and it is vandalism on a +PulseAudio monitor capture, which substitutes. `tools/port/strip-padding` says so +in its header before it says anything else, because running it on the wrong +artefact would look like it worked. + +Its output is **byte-identical** to the control's own stripping, so the tool and +the experiment are the same operation rather than two implementations that agree. diff --git a/tools/port/strip-padding b/tools/port/strip-padding new file mode 100755 index 00000000..0b09333c --- /dev/null +++ b/tools/port/strip-padding @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# Remove driver-inserted silence from a capture, exactly. +# +# tools/port/strip-padding in.wav out.wav +# +# WHEN THIS IS VALID, AND WHEN IT IS VANDALISM. The distinction is the whole +# tool and getting it backwards destroys the artefact: +# +# * PulseAudio's monitor SUBSTITUTES silence. It advances on a wall clock and +# replaces audio that existed when the producer was late. Information is +# gone; deleting the holes compresses time unevenly and repairs nothing. +# DO NOT RUN THIS ON A MONITOR CAPTURE. +# * Xenia's ALSA writer PADS. It inserts silence between samples the guest +# emitted when its ring is empty (`alsa_audio_driver.cc:359`). Nothing is +# lost and nothing is overwritten, so removing the padding is EXACT -- it +# hands back the contiguous stream the guest produced. +# +# CONTROLLED, not argued. A real music+SFX bed (137.37 s, with 454 zero runs of +# its own) had 1 149 holes inserted at 8.37/s to +9.9 % length, matching the +# observed ALSA profile, then was stripped: +# +# original vs itself r 1.000 lag 0.0 s margin +0.141 [ceiling] +# PADDED vs original r 0.436 lag -12.2 s margin +0.006 [destroyed] +# STRIPPED vs original r 1.000 lag 0.0 s margin +0.142 [recovered] +# +# Frame counts: original 6 593 984, stripped 6 559 880, and the original stripped +# of its own genuine zero runs 6 560 044 -- a difference of 164 frames, 3.4 ms in +# 137 s, from inserted holes abutting genuine ones and merging. +# +# ⚠️ It removes GENUINE silence too, and cannot tell the two apart -- that is why +# the reference above is the unstripped original: recovery does not depend on +# stripping both sides. On this material the genuine runs total 0.71 s in 137 s +# and cost nothing measurable. On material that is mostly silence they would. +set -euo pipefail +in="${1:?usage: strip-padding IN.wav OUT.wav}"; out="${2:?usage: strip-padding IN.wav OUT.wav}" +python3 - "$in" "$out" <<'PYEOF' +import array, struct, sys, wave +src, dst = sys.argv[1], sys.argv[2] +w = wave.open(src); ch = w.getnchannels(); rate = w.getframerate() +if w.getsampwidth() != 2: + print("strip-padding: 16-bit PCM only (got %d-bit)" % (w.getsampwidth()*8)); raise SystemExit(2) +n = w.getnframes(); a = array.array('h'); a.frombytes(w.readframes(n)); w.close() +MIN = max(1, rate // 1000) # a gap is a run, not a sample +sil = bytearray(n) +for f in range(n): + b = f * ch + if not any(a[b+c] for c in range(ch)): sil[f] = 1 +keep = array.array('h'); f = 0; removed = 0; holes = 0 +while f < n: + s = f + if sil[f]: + while f < n and sil[f]: f += 1 + if f - s < MIN: keep.extend(a[s*ch:f*ch]) + else: removed += f - s; holes += 1 + else: + while f < n and not sil[f]: f += 1 + keep.extend(a[s*ch:f*ch]) +k = len(keep) // ch +o = wave.open(dst + ".partial", "wb") # temp name, renamed on completion +o.setnchannels(ch); o.setsampwidth(2); o.setframerate(rate) +o.writeframes(keep.tobytes()); o.close() +import os; os.replace(dst + ".partial", dst) +print("%s: %d frames (%.3f s) -> %s: %d frames (%.3f s)" + % (src, n, n/rate, dst, k, k/rate)) +print(" removed %d run(s) totalling %.3f s (%.2f %% of the input)" + % (holes, removed/rate, 100.0*removed/n)) +PYEOF