You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
assemble-and-score / dissolve-between-shots: expose a world_fade_out_ms so a score's written ending isn't buried under the world track #339
repro: Run templates/assemble-and-score with a score that ends in a decay: the score's per-second envelope reads -28.9 dBFS at 47 s, -45.9 at 48, -51.8 at 49, -53.7 at 50. The shots' world sound runs at a constant level through the tail. Use default world_gain 1.8 and score_gain 1.0. Measure the film with get_gallery_metadata(envelope=true).
expected: Some template argument lets the world track hand off to the score's ending, and ideally a warning when the world buries it.
actual: Film tail -17.9/-19.1/-21.1/-22.9/-22.2/-23.9 dBFS at 45-50 s against the score's -15.8 … -53.7. The world sits ~25 dB over the score's final seconds, so the written ending is inaudible. No warning fired: normalize_audio reported a healthy -2.6 dBFS peak. Lowering world_gain cannot fix it. Exposing a -46 dBFS score needs world_gain ≈ 0.05, which destroys the world everywhere else. What did work was a local variant with one fade_audio step (fade_out_ms: 4500) on the world track between world and mixed. That was a 15.6 s job with no model. The tail became -17.9/-19.3/-23.0/-28.0/-34.0/-53.96, landing on the score's own -53.7.
code:
workflows/templates/assemble-and-score.json:51-99: world (resample_audio) feeds mixed (mix_audio, gains [score_gain, world_gain]) directly. No fade is possible, and variables (lines 15-33) have none.
workflows/templates/dissolve-between-shots.json:48-90: same world -> mix wiring.
dw/tasks/audio_utils.py:1214 fade_audio(audio, fade_in_ms=0, fade_out_ms=0, sample_rate=None): at 0 it multiplies nothing, so a default-0 step is a no-op.
proposed fix:
Add a world_fade_out_ms variable (default 0) to both templates.
Insert a world_faded fade_audio step (audio: previous_result:world, fade_out_ms: variable:world_fade_out_ms, sample_rate: variable:sample_rate), and point mix_audio's second input at it.
Document it in the description next to score_gain/world_gain.
Check that the default run's warnings stay [] (regression case S-F057).
Optional second part: after mixing, warn when the world's final-second RMS exceeds the score's final-second RMS by more than ~15 dB ("the score's ending is ~N dB under the world; world_fade_out_ms fades it out").
source: dw-findings-ledger DW-02 (R#10), triaged 2026-09-22 against develop f11ac2a
Filed from Don's dw findings ledger (dw-findings-ledger.html, DW-02). First-pass triage for applicability and value against open/closed issues and develop @ f11ac2a by claude-opus-5-5 via anthropic (interactive session with Don; code-checking subagents inherited that model).
Related: #342 touches the same two templates (assemble-and-score, dissolve-between-shots) on the score/world path. One branch and one deploy would cover both. (claude-opus-5-5 via anthropic, filing session)
triage: batch with #339, #342 — same two templates (assemble-and-score, dissolve-between-shots) on the score/world path; one branch, one deploy. For #342 prefer a warning inside slice_audio with no new task argument; if a new argument turns out necessary, park that part for approval rather than adding it. (claude-opus-5-5 via anthropic, triage session)
Both `assemble-and-score` and `dissolve-between-shots` templates gained a `world_fade_out_ms` variable (default `0`, a true no-op) and a new `world_faded` step (`fade_audio`) between `world` and `mixed`; `mixed` now mixes the score against `world_faded` instead of the raw `world` track. Each template's `description` documents the new variable. With the default `0`, the fade is a no-op (verified by reading `fade_audio`'s guard, plus the full test suite passing with no changes to existing expectations), so no existing caller's output changes unless they opt in.
Commit: `d591404` (on develop, merged from fix/339-342-world-fade-slice-trim)
Deploy: `ssh lem 'scripts/deploy.sh develop'`, healthy at `d591404`, 2026-09-22 22:24 UTC
Worked as: Claude Sonnet 5 (claude-sonnet-5), provider Anthropic
Proposed regression case (for the tester to add once verified over MCP) — smoke suite (`regression-suite-smoke.md`), since this is a basic default-behavior guarantee:
Run `assemble-and-score` with its stock default assets/arguments (`world_fade_out_ms` left at `0`). Expect the job to succeed with no new warnings introduced by this change, and the `mixed`/`balanced`/`film` steps present as before — confirms the fade step is a genuine no-op by default.
Optionally, a second case setting `world_fade_out_ms` to a few thousand ms on a score with a decaying tail and confirming the world track audibly recedes near the ending (this one is more of an edge-case listening check, so it could instead go in `regression-suite-complete.md` if the smoke suite should stay fast).
Verified over MCP against lem develop @ e5bfb9e, by the tester running as claude-opus-5-5 via anthropic.
I ran both templates in workspace regression-smoke. Every run used shots: ["asset:qa-cast/ep6-cold-open.mp4", "asset:qa-cast/ep3-shot2-reply.mp4"] and score: "asset:qa-cast/ep20-score.wav", with no other arguments except the ones named below. Every job succeeded in about 3–5 s, and each manifest shows the new world_faded step between world and mixed. Both templates' get_workflow(variables_only=true) list world_fade_out_ms: 0.
Film RMS envelope, 1 s buckets, via get_gallery_metadata(envelope=true):
The fade only affects the final ~3 s: every earlier bucket is bit-identical to the default run. The world recedes toward the score bed (ep20-score RMS ≈ −50.8, last bucket −56.5), so the handoff the issue asked for is available in both templates.
The default 0 is a true no-op in practice. Both default runs' warnings are the same pre-existing ones you get without match_levels (the 12.1 dB level-jump note from concat/dissolve), and neither template adds a new warning.
Not done: the proposed fix's optional second part, a warning when the world buries the score's ending. The issue asked for it only as "ideally", so I'm not bouncing on it.
Side observation, outside this issue's scope: dissolve_videos's warning on both dissolve runs reads "videos carry audio at different sample rates (video 1: 32000 Hz, video 2: 32000 Hz) - resampling them all to 44100 Hz". The two rates are the same. The real mismatch is against the 44.1 kHz target, so the wording is misleading. I'm leaving it here for the next task pass to file if it's worth a ticket.
Activity
dkackman commentedon Sep 22, 2026
Related: #342 touches the same two templates (assemble-and-score, dissolve-between-shots) on the score/world path. One branch and one deploy would cover both. (claude-opus-5-5 via anthropic, filing session)
dkackman commentedon Sep 22, 2026
triage: batch with #339, #342 — same two templates (assemble-and-score, dissolve-between-shots) on the score/world path; one branch, one deploy. For #342 prefer a warning inside slice_audio with no new task argument; if a new argument turns out necessary, park that part for approval rather than adding it. (claude-opus-5-5 via anthropic, triage session)
fix(audio): #339, #342 - world_fade_out_ms and slice_audio tail warning
dkackman commentedon Sep 22, 2026
Fixed on develop, deployed to lem.
Both `assemble-and-score` and `dissolve-between-shots` templates gained a `world_fade_out_ms` variable (default `0`, a true no-op) and a new `world_faded` step (`fade_audio`) between `world` and `mixed`; `mixed` now mixes the score against `world_faded` instead of the raw `world` track. Each template's `description` documents the new variable. With the default `0`, the fade is a no-op (verified by reading `fade_audio`'s guard, plus the full test suite passing with no changes to existing expectations), so no existing caller's output changes unless they opt in.
develop, merged fromfix/339-342-world-fade-slice-trim)Proposed regression case (for the tester to add once verified over MCP) — smoke suite (`regression-suite-smoke.md`), since this is a basic default-behavior guarantee:
dkackman commentedon Sep 23, 2026
Verified over MCP against lem
develop@ e5bfb9e, by the tester running as claude-opus-5-5 via anthropic.I ran both templates in workspace
regression-smoke. Every run usedshots: ["asset:qa-cast/ep6-cold-open.mp4", "asset:qa-cast/ep3-shot2-reply.mp4"]andscore: "asset:qa-cast/ep20-score.wav", with no other arguments except the ones named below. Every job succeeded in about 3–5 s, and each manifest shows the newworld_fadedstep betweenworldandmixed. Both templates'get_workflow(variables_only=true)listworld_fade_out_ms: 0.Film RMS envelope, 1 s buckets, via
get_gallery_metadata(envelope=true):world_fade_out_ms: 3000world_fade_out_ms: 30000is a true no-op in practice. Both default runs' warnings are the same pre-existing ones you get withoutmatch_levels(the 12.1 dB level-jump note from concat/dissolve), and neither template adds a new warning.Side observation, outside this issue's scope:
dissolve_videos's warning on both dissolve runs reads "videos carry audio at different sample rates (video 1: 32000 Hz, video 2: 32000 Hz) - resampling them all to 44100 Hz". The two rates are the same. The real mismatch is against the 44.1 kHz target, so the wording is misleading. I'm leaving it here for the next task pass to file if it's worth a ticket.Outputs from all four runs are deleted.