Skip to content

Skills: document per-shot score ducking under voice-over (gain_audio regions) for H3 scored pieces #340

Closed

Description

@dkackman

tool/endpoint: mix_audio / gain_audio (tasks); templates/assemble-and-score

repro: A scored cuts piece whose H3 shots mix narration with action sound. Assemble with templates/assemble-and-score. Try world_gain 1.8 (default), 4.5 and 7.2.

expected: Some way to put dialogue on top of the score while leaving the action or melee sound where it was.

actual:

  • H3 renders narration ~24 dB above its own ambience, stable across one batch: shots with no voice-over were -54.46/-48.90/-46.15 dBFS mean, the two voice-over shots -33.83/-33.13.
  • Music3's score lands 6-15 dB above the narration.
  • The world arrives as one stream, so raising it lifts both:
    • world_gain 4.5: voice +5 dB, melee (music-only regions) -0.5 dB.
    • world_gain 7.2: voice +5 to +8 dB, melee -3.5 dB, and the score's own peaks start dropping after normalize.
  • No setting separates the two.

code:

proposed fix (design options, needs a decision):
(1) A duck_audio task, or a sidechain argument on mix_audio. It takes a key track (the world, which contains the speech) plus threshold, depth_db, attack_ms and release_ms, and pulls the target (score) down while the key's short-window envelope is above threshold.
(2) A cheaper variant: a task that emits gain_audio regions from a key track's envelope.
(3) Model-side: an H3 option to return dialogue as its own stem. Probably not available.
Wire (1) into assemble-and-score as an optional duck_score_db (default 0 = off).

source: dw-findings-ledger DW-03 (A#18, A#14), triaged 2026-09-22 against develop f11ac2a. Related: #187 (per-region gain), #199.


Filed from Don's dw findings ledger (dw-findings-ledger.html, DW-03). 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).

Activity

  1. changed the title [-]Proposal: voice-driven ducking (sidechain) for mix_audio, since H3's single world track can't lift dialogue without lifting action sound[/-] [+]Skills: document per-shot score ducking under voice-over (gain_audio regions) for H3 scored pieces[/+] on Sep 22, 2026
  2. dkackman commented on Sep 22, 2026

    @dkackman
    OwnerAuthor

    Disposition (Don, 2026-09-22): narrowed to a skill/doc change. Do not build the engine proposal above.

    Why the proposal as written is rejected: a sidechain keyed on the world track can't separate dialogue from action, because the world track carries both. It would duck the score under the melee too, which is exactly where the score peaks. Speech-keyed ducking would need new speech-detection surface (transcribe_audio returns text only, no timestamps). That can come back as its own proposal if manual ducking proves painful.

    Scope for this issue:

    • In the dw plugin skills that cover scored H3 pieces (dw:minimax-h3, dw:series-episodes, and wherever templates/assemble-and-score / dissolve-between-shots are taught), add a short recipe. When some shots carry voice-over and the score buries them, duck the score under just those shots with gain_audio (No per-region gain task; ducking requires a five-step slice/gain/rejoin chain #187): one region per voice-over shot, with start_frame = the running sum of the preceding shots' num_frames, num_frames = that shot's length, and fps the cut's rate. Apply it to the score before the mix step. That means a local variant of the template, or a pre-processed score passed as score.
    • Name the measured symptom so agents recognise it: narration ~24 dB over its own ambience, with a Music 3 score 6–15 dB over the narration. Raising world_gain lifts the action sound with the voice (4.5 → voice +5 dB, melee −0.5 dB; 7.2 → voice +5…+8 dB, and the score's peaks drop after normalize).
    • Say what not to do: don't reach for world_gain to fix intelligibility.

    Plugin change only: merge to develop, no server restart. (Recorded by claude-opus-5-5 via anthropic in the triage session with Don.)

  3. dkackman commented on Sep 23, 2026

    @dkackman
    OwnerAuthor

    triage: batch with #354 — both are Don-narrowed doc-only changes to plugins/dw/skills (H3/speech skills) and tool docstrings; one session, one deploy. Work per Don's disposition comment, not the original engine proposal. (claude-opus-5-5 via anthropic, triage session)

  4. added a commit that references this issue on Sep 23, 2026
  5. dkackman commented on Sep 23, 2026

    @dkackman
    OwnerAuthor

    Fixed and deployed. Worked as claude-sonnet-5 (Anthropic).

    Added a ducking recipe to the three skills that teach a scored H3 piece:

    • plugins/dw/skills/minimax-h3/SKILL.md - the primary recipe, under the "A piece with cuts" bullet: a score burying voice-over is not a world_gain fix (the world track carries narration and action together - narration ~24 dB over its own ambience, score 6-15 dB over that - so raising it lifts both). Duck the score instead, before passing it as score: one gain_audio (No per-region gain task; ducking requires a five-step slice/gain/rejoin chain #187) step per voice-over shot, chained, start_frame = running sum of preceding shots' num_frames, num_frames that shot's length, fps the cut's rate, negative gain_db (-6 to -10). Notes dissolve-between-shots eats a dissolve_frames per seam, so its sum isn't plain addition.
    • plugins/dw/skills/series-episodes/SKILL.md - same recipe referenced from the match_levels step of the five-beat procedure, since that's the other place assemble-and-score's mixing is taught.
    • plugins/dw/skills/minimax-music3/SKILL.md - pointer added to the "A score under a film or a cuts piece" bullet, pointing back at minimax-h3's recipe.

    minimax-h3/SKILL.md was trimmed elsewhere (wording only, no content dropped) to stay under the 12KB skill size cap after the addition - final size 12278 bytes.

    Shipped: commit 96e2ea2 on develop (merged from fix/340-354-score-ducking-and-transcription-route), plugin-only change - no server restart required for this part, but the same commit also carries #354's fix, which does need one; both are now live on lem (deployed at 2026-09-23 12:34 UTC, healthy at 96e2ea2).

    tests/test_plugin_skills.py (52 tests, all pinned substrings/size caps) passes.

    Batched with #354 per the triage comment on #340 - see that issue for its own summary.

  6. dkackman commented on Sep 23, 2026

    @dkackman
    OwnerAuthor

    Verified by claude-opus-5-5 via anthropic (tester, verify session), against lem develop @ 4aaeef7 and plugin tree at origin/develop.

    What I ran:

    • I loaded dw:minimax-h3 through the Skill tool. The ducking recipe sits under "A piece with cuts" and covers every point in Don's scope:
      • "not a world_gain fix"
      • the measured symptom (narration ~24 dB over its own ambience, score 6-15 dB over that; raising world_gain lifts both)
      • duck the score before passing it as score
      • one gain_audio (No per-region gain task; ducking requires a five-step slice/gain/rejoin chain #187) step per voice-over shot, chained
      • start_frame = running sum of the preceding shots' num_frames, num_frames = that shot's length, fps = the cut's rate, negative gain_db
      • the dissolve-between-shots caveat
    • dw:series-episodes: the match_levels beat says voice-over burial isn't fixed by match_levels or world_gain, and points to the minimax-h3 recipe.
    • dw:minimax-music3: the "A score under a film or a cuts piece" bullet points to the same recipe.

    Adjacent checks (does the recipe work as written?):

    • get_task("gain_audio"): the task takes gain_db, start_frame, num_frames and fps. These are the parameter names the recipe uses.
    • validate_workflow on an inline two-step chain following the recipe: gain_audio on asset:qa-cast/ep20-score.wav (start_frame 124, num_frames 141, fps 24, gain_db -8), then gain_audio on previous_result:duck1 (start_frame 265, num_frames 124). Result: valid: true, no warnings.

    Not covered: Don's scope asked for "don't reach for world_gain" and the measured-symptom wording. Both are present. Whether a -6 to -10 dB duck is enough in practice is a listening judgement. Nothing was generated this session, so I didn't test it.

    No regression case added: this is a doc-only change, and a skill-text pin belongs in tests/test_plugin_skills.py, not in an MCP suite.

  7. added
    status:verifiedTester confirmed the fix via a real MCP call
    and removed on Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    owner:testerTester's turn to actstatus:verifiedTester confirmed the fix via a real MCP call

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions