The 6-channel capture I spent an iteration refuting was corrupt, and the Decoder found the cause: PulseAudio remapping between two mismatched channel maps, where a 6-channel remap SILENTLY DROPS AND DUPLICATES. Its control -- six channels, six tones, same sink, same parec -- came back 400/3200/200/800/800/200 for an input of 400/800/200/1600/3200/6400. Two source channels gone entirely. So the negative was right, and the byte-identical pair I reported was the thread that unravelled it. Worth recording precisely, because it nearly went unreported: it began as an idle look at two channels whose peak AND RMS matched to six decimals, and it only became evidence because a coincidence at six decimals is cheaper to hash than to explain. `tools/port/check-capture` makes that check one command -- split the file, hash every channel, fail on any duplicate pair -- and AUDIO-VERIFICATION.md gains a section 5 saying to run it FIRST, every time, plus the two conditions the same incident produced: start the recorder before the process, and log what was on screen against the recording's own clock so a miss is diagnosable. Controlled both directions, because a checker nobody controlled is what this incident is about: six distinct tones PASS; the remap's own output pattern FAILS naming all four pairs; the corrupt capture FAILS on ch2 == ch5. THE KNOWN-BAD CONTROL IS THE POINT. All six of its channels report a peak of -18.063656 dB, identical to six decimals, while containing three duplicate pairs. A level check cannot see this failure. That is why the tool hashes rather than measures, and why the corrupt capture's "plausible per-channel levels" were never evidence. The tool says of itself that it is necessary, not sufficient. Withdrawn with the file, both the Decoder's: "all six channels carry signal", and the non-zero-surround observation offered as weak support for 5.1. Unaffected: the three-XMA-context concurrency result, read from the emulator's log rather than the audio path, on two independent boots. The corrupt file is dropped from the exchange so the next agent cannot pick it up and repeat the work. Nothing in the export changed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
78 lines
3.5 KiB
Bash
Executable File
78 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Provenance check for a multichannel capture, BEFORE anybody analyses it.
|
|
#
|
|
# tools/port/check-capture /path/to/capture.wav
|
|
#
|
|
# WHY THIS EXISTS. A 6-channel capture of the game's own output was analysed at
|
|
# length -- three controls, a drift test, a written-up negative -- and the file
|
|
# was corrupt. PulseAudio was remapping between two mismatched channel maps, and
|
|
# a 6-channel remap SILENTLY DROPS AND DUPLICATES: right duration, right channel
|
|
# count, plausible per-channel levels, no error anywhere. Two of the six channels
|
|
# were byte-identical copies of two others and two source channels were simply
|
|
# gone.
|
|
#
|
|
# The Decoder proved it with a control that needs no emulator and no disc: six
|
|
# channels each carrying a different tone through the same sink and the same
|
|
# `parec` invocation. Channels came back 400 / 3200 / 200 / 800 / 800 / 200 for
|
|
# an input of 400 / 800 / 200 / 1600 / 3200 / 6400 -- see
|
|
# `docs/re/audio-capture-channel-map-trap.md`. Setting the sink's `channel_map`
|
|
# to the guest's own and passing the same map to `parec` returns all six.
|
|
#
|
|
# THE DETECTABLE SIGNATURE IS AN EXACT DUPLICATE PAIR. Two channels of a real
|
|
# surround mix are never byte-identical over 70 s. Levels are not enough to catch
|
|
# it -- the corrupt file's per-channel peaks looked entirely reasonable, and it
|
|
# was only equal peak AND equal RMS to six decimals that prompted a hash.
|
|
#
|
|
# This is a NECESSARY check, not a sufficient one: passing it means the capture
|
|
# has no duplicated channels, not that it recorded the right thing.
|
|
set -euo pipefail
|
|
f="${1:?usage: check-capture FILE.wav}"
|
|
|
|
# Queried one field at a time. A combined `-show_entries` prints two values on
|
|
# ONE comma-separated line, and `read -r ch rate dur` then puts "48000,6" in
|
|
# `$ch` -- which every later arithmetic test rejects, in a script whose whole
|
|
# job is to be trusted about a file.
|
|
probe() { ffprobe -v error -select_streams a:0 -show_entries "$1" -of csv=p=0:nk=1 "$f" | head -1; }
|
|
ch=$(probe stream=channels)
|
|
rate=$(probe stream=sample_rate)
|
|
dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0:nk=1 "$f" | head -1)
|
|
printf '%s: %sch %sHz %.3fs\n' "$f" "$ch" "$rate" "$dur"
|
|
|
|
if [ "$ch" -lt 2 ]; then echo " single channel -- nothing to compare"; exit 0; fi
|
|
|
|
layout=5.1; [ "$ch" = 2 ] && layout=stereo
|
|
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
|
|
map=""; for i in $(seq 0 $((ch-1))); do map="$map -map [c$i] $tmp/c$i.wav"; done
|
|
split=""; for i in $(seq 0 $((ch-1))); do split="$split[c$i]"; done
|
|
# shellcheck disable=SC2086
|
|
ffmpeg -hide_banner -v error -y -i "$f" \
|
|
-filter_complex "channelsplit=channel_layout=$layout$split" $map
|
|
|
|
declare -a sums
|
|
for i in $(seq 0 $((ch-1))); do
|
|
s=$(ffmpeg -hide_banner -v error -i "$tmp/c$i.wav" -f md5 - | cut -d= -f2)
|
|
peak=$(ffmpeg -hide_banner -v info -i "$tmp/c$i.wav" -af astats -f null - 2>&1 \
|
|
| grep -m1 "Peak level dB" | sed 's/.*: //')
|
|
sums[i]="$s"
|
|
printf ' ch%-2d peak %-12s %s\n' "$i" "$peak" "$s"
|
|
done
|
|
|
|
dupes=0
|
|
for i in $(seq 0 $((ch-1))); do
|
|
for j in $(seq $((i+1)) $((ch-1))); do
|
|
if [ "${sums[i]}" = "${sums[j]}" ]; then
|
|
echo " 🔴 ch$i and ch$j are BYTE-IDENTICAL"
|
|
dupes=1
|
|
fi
|
|
done
|
|
done
|
|
|
|
if [ "$dupes" = 1 ]; then
|
|
echo "FAIL: duplicated channels. A surround remap drops and duplicates silently;"
|
|
echo " channels are missing from this file. Do not analyse it -- fix the"
|
|
echo " sink's channel_map and re-record. See docs/port/AUDIO-VERIFICATION.md."
|
|
exit 1
|
|
fi
|
|
echo "PASS: no duplicated channels. (Necessary, not sufficient -- this says"
|
|
echo " nothing about whether the right thing was recorded.)"
|