Files
LlamaCasty/TASKS/task-12-master-limiter.md
gramps 87509bcf99 docs: restructure TASKS.md into a catalog — one file per task in TASKS/
TASKS.md is now the index (status table, open items, research pointer).
33 files: 32 task files + 1 research facts file. The full take-saga
narrative and all design decisions are preserved verbatim; the catalog
makes the queue readable without opening every task body. Schema and
AGENTS.md updated to reflect the new layout.
2026-09-05 16:31:46 -07:00

32 lines
2.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASK 12 — Master limiter on the live mix (2026-08-15)
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
**Queued by the creator during the TRAX discussion:** "should the soundtrack be limited to avoid
squandering resources / should it cap at 20% / how do the three sound events balance?" Review
conclusions (all three instincts checked out, only ONE real gap):
- **File size — no guard needed.** `MusicPlayer` uses `MediaFoundationReader`, which **streams from
disk** (progressive source): memory is flat (~a few MB) regardless of file size; CPU negligible.
- **20% cap — already enforced by construction.** `MusicPlayer.MusicVolume = 0.20f` + music rides the
SAME WASAPI loopback (and therefore the same gain) as game audio, so music:game is always exactly
**0.20:1 at any slider position** — it literally cannot rise above 20% of the current desktop volume.
- **The gap:** `AudioMixer.FillAndMix` summed mic + loopback with **no output ceiling** — mic 100% +
loud game/music could pass 0 dBFS and clip the AAC encode.
**Shipped:**
1. ✅ **`Services/Audio/MasterLimiter.cs`** (pure, unit-tested) — a **−1 dBFS ceiling** (`Ceiling =
0.891`), **instant attack per frame** (a hot frame is scaled exactly to the ceiling — no overshoot),
**smoothed release** toward unity so loud passages don't pump; gain never exceeds 1 (no boosting).
Applied at the end of `AudioMixer.FillAndMix`, right before the pipe write.
2. ✅ **Unit tests** — over-ceiling frames trimmed to ≤ ceiling; sub-ceiling frames never boosted; gain
recovers to unity after the loud frame ends.
3. ✅ **ONE integration test** (`MasterLimiter_CapsTheLiveMix_OnThePipe`) — real mixer + pipe harness:
a 0.95 loopback bed (hotter than the ceiling) is capped to exactly 0.891 on the wire while staying
audible.
4. ✅ **Docs in the same commit** — `ai.md` (go-live audio section), `Services/index.md` (new row).
No changes to `MusicPlayer`, the 0.20 cap, the ducker, or the meter zones. Build 0 warnings.