ops(gate): the capture leg — stream to WAV, measured, speech log checked (STORY-445, gh-#777) - #789
Merged
Merged
Conversation
#777) Renders the gate leg's synthesised library (tone-loud.mp3 -12 LUFS, tone-quiet.mp3 -30 LUFS, sine + pink noise, loudnorm two-pass with an ebur128 measure-and-verify pass) and commits two size-capped CC0 clips with sourcing in SOURCES.md, per SPEC F178.3. Unpends the 7 T489 facts in Story445_CapturedAudio.cs.
tools/gate/measure_audio.sh <wav> --target <lufs> counts silence events (silencedetect, SILENCE_FLOOR -45 dB, SILENCE_SECS 2 s) and compares ebur128 integrated loudness with the target within TOL_LU 5. Prints one summary line on stdout; exit 0 pass, 1 fail, 2 usage or unreadable input. Un-skips the six PendingMeasure facts in Story445, which drive the real script through GateHarness.
…#777) After a passed fresh leg, --capture logs in to the api with the scratch's own admin password (read from its .env, never sourced, passed on stdin), reads Loudness:TargetLufs from GET /api/settings, records CAPTURE_SECS (default 360) of the stream with ffmpeg -reconnect 1, runs measure_audio.sh against it, and counts station.booth_log rows with a non-null segment_kind in the last 7 minutes. Every number lands in gate-report.md and .json (capture.target_lufs, silence_events, integrated_lufs, booth_log); a miss fails the leg naming the assertion: login, target, capture, silence, loudness, measure, booth_log. --capture without --fresh exits 2. The inline media synth now calls tools/gate/make_media.sh. FakeStation gains the real api's login cookie and settings array shape. Story445: the nine capture facts un-skipped plus two new sad-path scenarios (off-level, silent gap).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR-5 of the gh-#777 epic (STORY-445, SPEC F178.3, F178.5). The gate now listens to what it launched: a real capture off the stream, measured, with the speech log checked.
🏗️ What
tools/gate/make_media.sh <outdir>(T489): two 45 s MP3 tones at −12 and −30 LUFS (two-pass loudnorm, verified with ebur128 to ±1 LU) plus two CC0 clips fromtools/gate/media/(≤ 1 MB each,SOURCES.mdnames creator and URL). The gate's inline synth is gone; it calls this script.tools/gate/measure_audio.sh <wav> --target <lufs>(T490):silencedetect(SILENCE_FLOOR −45 dB, SILENCE_SECS 2 s) event count andebur128integrated loudness within TOL_LU 5 of the target. One summary line on stdout; exit 0 pass, 1 fail, 2 usage or an input ffmpeg cannot measure.--capturelogs in to the api with the scratch's own admin password (grepped from its.env, passed on stdin, never sourced or exported), readsLoudness:TargetLufsfromGET /api/settings, recordsCAPTURE_SECS(default 360) of the stream withffmpeg -reconnect 1, measures it, and countsstation.booth_logrows with a non-nullsegment_kindin the last 7 minutes. Every number lands in the md and json report; a miss fails the leg naming the assertion (login,target,capture,silence,loudness,measure,booth_log).--capturewithout--freshexits 2.GateHarness.FakeStationnow mirrors the real api: login cookie, 401 without it, settings as an array of{key, value}with a string value.Story445_CapturedAudio.cs: all facts green, plus two sad-path scenarios added in review (an off-level capture failsloudness, a silent gap failssilence).🔌 T492 — the real capture on the dev box (v5.8.3)
The integrated reading sits 4.7 LU under the target, inside the ±5 LU tolerance but close to it. The first minutes of a fresh station are mostly speech and the gate tones at −12/−30 average out under the target, so a longer capture on a fuller library should land nearer −16. Worth an ear on the next LLL rather than a tighter tolerance now.
🔍 Review rounds worth knowing
set -einside a$(ffmpeg …)capture). Fixed; exit 2 with ffmpeg's tail.if ! v=$(cmd); then s=$?reads the negated pipeline's 0, so a silence or loudness miss reportedpassed. Fixed tos=0; v=$(cmd) || s=$?, and the two new sad-path facts pin it.✅ Gate
dotnet test GenWave.sln --filter "Category!=Integration" -- xUnit.MaxParallelThreads=3: all nine projects green (Host 2965 passed / 153 skipped; 0 failed).bash -nandshellcheckclean on all three scripts.📝 Follow-ups
CAPTURE_SECSabove 420 undercounts (commented in the script).launch.shprunes unused images older than 7 days on success; the gate triggers it. Stop a co-located station withdocker compose stop, neverdown.