Skip to content

No per-region gain task; ducking requires a five-step slice/gain/rejoin chain #187

Closed

Description

@dkackman

tool/endpoint: list_tasks / audio task family (slice_audio, mix_audio, normalize_audio, pair_audio) repro: duck one scene under another — e.g. lower a dialogue track between two timestamps. normalize_audio is whole-track; mix_audio layers everything from sample 0 with no offset/region. The only way is slice_audio → gain (a full-track normalize on the slice) → mix_audio → rejoin → re-pair_audio — five extra steps for what one gain_audio(start_frame, num_frames, gain_dbfs) would do. expected: a gain_audio (or a mix_audio region/gain parameter) task that applies a gain to a region of a track, expressed in frames or seconds, so a scene can be ducked in one step. actual: no such task exists. list_tasks shows the slice/loop/mix/pair family but nothing that applies a per-region gain. impact: ducking is an ordinary editing operation (C-F016/C-F018/C-F024-adjacent); five-step chains accumulate arithmetic errors and are easy for an agent to get wrong. This is the lowest-effort, highest-value task addition after ASR.

Activity

  1. dkackman commented on Sep 17, 2026

    @dkackman
    OwnerAuthor

    triage: batch with #185 — same files (dw/tasks/audio_utils.py, dw/tasks/task.py, dw/task_domains.py, docs/TASKS.md) and one deploy; #185 is the lowest number so its session ships both. Not a duplicate — no existing task applies a gain to a region (normalize_audio is whole-track, mix_audio has no offset). A new gain_audio(audio, gain_db, start_frame, num_frames, sample_rate=None) alongside slice_audio is an ordinary task addition, not a step-7 decision; register it in task.py, declare its domains (num_frames > 0, start_frame >= 0) in task_domains.py so tests/test_task_domains.py pins them, and give it the same sample_rate reinterpretation caveat slice_audio carries (#180). Not batched with #188 — that one pulls a helper model onto lem and is a session of its own. Triaged by model opus via provider anthropic.

  2. added 2 commits that reference this issue on Sep 17, 2026
  3. dkackman commented on Sep 17, 2026

    @dkackman
    OwnerAuthor

    Shipped: a new gain_audio task.

    gain_audio(audio, gain_db, start_seconds=None, duration_seconds=None, start_frame=None, num_frames=None, fps=None, sample_rate=None) applies a gain (dB, negative ducks / positive boosts) to a region of a track in one step, replacing the five-step slice_audio → gain → mix_audio → rejoin → pair_audio chain for ducking a scene.

    Commit: 1f3c8f1, merged to develop at 09875d9, deployed to lem (get_task("gain_audio") confirms the live schema matches).

    Model sonnet via provider anthropic.

    Proposed regression case (not added to the suite, for the tester to place): in tests/test_audio_utils.py (or wherever slice_audio's region tests live), build a track, call gain_audio on a middle region with a negative gain_db, and assert only that region's samples changed (scaled by the expected linear gain) while samples outside the region are bit-identical to the source. A second case: a region whose start_frame/num_frames (with fps) extends past the track's end should return output the same length as the input (clipped, not padded).

  4. dkackman commented on Sep 17, 2026

    @dkackman
    OwnerAuthor

    Verified over MCP against dw 0.4.0-beta.6 on lem, workspace qa-verify-187, fixture asset:qa-cast/ep11-bed.wav (19.667 s, 32 kHz mono, peak −28.886 dBFS). Model opus via provider anthropic.

    Schema. get_task("gain_audio") lists audio, gain_db (required), start_seconds/duration_seconds, start_frame/num_frames/fps, sample_rate, device, with domains (start_* non_negative, duration_seconds/num_frames/fps/sample_rate positive).

    Repro — duck a middle region (seconds). Job 6751bf30fdb4: gain_audio {gain_db: -12, start_seconds: 5, duration_seconds: 3} → succeeded in 1.1 s. get_gallery_metadata(envelope=true) on the output vs. the source asset, second by second:

    • seconds 5, 6, 7: peak −28.886 → −40.883 dBFS (−11.997 dB), RMS −50.78 → −62.78 (−12.00 dB)
    • every other second (0–4, 8–19): rms_dbfs and peak_dbfs numerically identical to the source, to full float precision
    • duration_seconds 19.666656 unchanged, sample rate/channels unchanged

    Adjacent 1 — frames, positive gain, region past the end. Job bc12d804d750: {gain_db: 6, start_frame: 400, num_frames: 200, fps: 24} (frame 400 = 16.667 s; region would end at 25 s on a 19.67 s track) → succeeded in 0.6 s. Output duration still 19.666656 s — clipped, not padded, as the hand-off says. Seconds 16–18 peak −28.886 → −22.884 (+6.00 dB); the final partial second −50.22 → −44.24 (+5.98); seconds 0–15 identical to the source.

    Adjacent 2 — domain pins. validate_workflow with start_frame: -1, num_frames: 0 → valid: false, two errors at steps[0].task.arguments.start_frame / .num_frames, each naming gain_audio and the bound.

    Observation (not a bounce). gain_audio with gain_db and no region at all validates (valid: true, plan returned) and then fails at run time in 0.6 s with a clear message: "gain_audio needs either 'start_seconds'/'duration_seconds' or 'start_frame'/'num_frames'/'fps' to address the region to gain". Same class as the validate_workflow-doesn't-know-cross-argument-rules gap noted on #185/S-F041; the runtime refusal is immediate and well-worded, so I'm recording it here rather than filing.

    Expected behavior from the issue body is met: a one-step per-region gain, addressable in seconds or frames, in place of the five-step chain. Closing as completed. Regression case added to regression-suite-smoke.md (S-F042) — the implementer's proposed pytest-level sample assertions belong in the dw repo's own suite; the MCP-side case pins the same properties through the per-second envelope.

  5. added
    status:verifiedTester confirmed the fix via a real MCP call
    and removed on Sep 17, 2026
  6. added a commit that references this issue on Sep 19, 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

    enhancementNew feature or requestowner: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