Skip to content

Commit 36c5a5b

Browse files
vanceingallsclaude
andcommitted
docs(plans): fix pre-existing oxfmt formatting drift in audio-fx-presets
Blocks the regression workflow's required preflight gate. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 7ad64a1 commit 36c5a5b

1 file changed

Lines changed: 53 additions & 47 deletions

File tree

‎plans/audio-fx-presets.md‎

Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ to keep clearing.
3131

3232
### What already exists, so this does not duplicate it
3333

34-
- **`skills/hyperframes-audio`** teaches the effect *families* and when to
34+
- **`skills/hyperframes-audio`** teaches the effect _families_ and when to
3535
reach for each ("Reach for a family by the problem, not the name"), and
3636
documents carve. It contains **no recipes and no named looks** — it explains
3737
the why, and stops short of the one-click. This catalog is the complement,
3838
not a rewrite. It also already fixes the canonical order this doc adopts:
39-
*"corrective filtering goes early, character in the middle, and a limiter
40-
last."*
39+
_"corrective filtering goes early, character in the middle, and a limiter
40+
last."_
4141
- **`carveBandsToChain()`** already proves the mechanism: an analysis produces
4242
an ordinary `HfAudioFxChain`, which the rack then owns like any other.
4343
- **Demand is real and internal.** Cortex carries user asks for
@@ -65,7 +65,7 @@ them with this effect set. Any catalog that quietly implies otherwise is lying.
6565

6666
Premiere Pro's **Essential Sound** panel is the closest analogue to what is
6767
being asked for, and it is the design worth stealing. The author tags a clip by
68-
*what it is* — Dialogue, Music, SFX, Ambience — and then gets a small set of
68+
_what it is_ — Dialogue, Music, SFX, Ambience — and then gets a small set of
6969
outcome-named controls rather than effects:
7070

7171
- **Loudness**, with an Auto-Match that normalises to a broadcast target
@@ -94,17 +94,17 @@ ring mod. Out of scope unless a new effect is added.
9494

9595
## 3. What our 15 effects reach
9696

97-
| Family | Effects | Reaches |
98-
| --- | --- | --- |
99-
| Filter | `highpass` `lowpass` `peaking` `lowshelf` `highshelf` | tone shaping, band isolation, rumble/mud removal, presence |
100-
| Dynamics | `gain` `compressor` `limiter` `gate` | levelling, consistency, ceilings, room-tone gating |
101-
| Nonlinear | `saturate` `bitcrush` | warmth, grit, distortion, digital degradation |
102-
| Time | `delay` `reverb` `chorus` `phaser` | space, slap, width, wow/flutter, movement |
97+
| Family | Effects | Reaches |
98+
| --------- | ----------------------------------------------------- | ---------------------------------------------------------- |
99+
| Filter | `highpass` `lowpass` `peaking` `lowshelf` `highshelf` | tone shaping, band isolation, rumble/mud removal, presence |
100+
| Dynamics | `gain` `compressor` `limiter` `gate` | levelling, consistency, ceilings, room-tone gating |
101+
| Nonlinear | `saturate` `bitcrush` | warmth, grit, distortion, digital degradation |
102+
| Time | `delay` `reverb` `chorus` `phaser` | space, slap, width, wow/flutter, movement |
103103

104104
Plus two force multipliers the catalog depends on:
105105

106106
- **Automation lanes** on `gain` and on most effect parameters — so a preset can
107-
be a *moving* treatment, not just a static one.
107+
be a _moving_ treatment, not just a static one.
108108
- **Offline analysis** (`powerSpectrum`, `windowDb`, `analyseCarveDynamics`,
109109
`analyseCarveDuck`) already runs in the panel over decoded audio. This is what
110110
makes the adaptive tier possible without new machinery.
@@ -133,13 +133,13 @@ The carve pattern: read the decoded samples, measure something, emit a chain
133133
and/or automation lanes. **The machinery for this is already built and shipped**
134134
— what carve does with a voice against a bed generalises:
135135

136-
| Script | Reuses | Emits |
137-
| --- | --- | --- |
138-
| Voice carve *(shipped)* | `analyseCarveBands` | peaking cuts + per-band lanes |
139-
| Auto-duck *(shipped, inside carve)* | `analyseCarveDuck` | one volume lane |
140-
| De-esser | `analyseCarveDynamics`, re-parameterised (see §5e) | lane on a peaking cut |
141-
| Leveller | `windowDb` walk | lane on a `gain` node |
142-
| Tone match | `powerSpectrum` vs a target curve | 3–5 peaking nodes |
136+
| Script | Reuses | Emits |
137+
| ----------------------------------- | -------------------------------------------------- | ----------------------------- |
138+
| Voice carve _(shipped)_ | `analyseCarveBands` | peaking cuts + per-band lanes |
139+
| Auto-duck _(shipped, inside carve)_ | `analyseCarveDuck` | one volume lane |
140+
| De-esser | `analyseCarveDynamics`, re-parameterised (see §5e) | lane on a peaking cut |
141+
| Leveller | `windowDb` walk | lane on a `gain` node |
142+
| Tone match | `powerSpectrum` vs a target curve | 3–5 peaking nodes |
143143

144144
This is the strongest argument in the doc: **none of them needs new DSP** —
145145
only a different question asked of code that already runs. One (de-ess) needs
@@ -157,6 +157,7 @@ presence EQ → saturation → limiter last.**
157157

158158
**`voice-clean` — "Clean Voice"** · the safe default, roughly Premiere's
159159
Dialogue preset
160+
160161
```
161162
highpass frequency 80 q 0.707 poles 2
162163
peaking frequency 250 gain -3 q 1.2 (mud)
@@ -166,6 +167,7 @@ limiter limit -1 attack 5 release 50
166167
```
167168

168169
**`voice-broadcast` — "Broadcast"** · denser, more forward
170+
169171
```
170172
highpass frequency 90 q 0.707 poles 2
171173
peaking frequency 400 gain -3 q 1.4
@@ -177,6 +179,7 @@ limiter limit -1 attack 5 release 60
177179
```
178180

179181
**`voice-warm` — "Close & Warm"** · intimate, less processed
182+
180183
```
181184
highpass frequency 70 q 0.707 poles 2
182185
lowshelf frequency 180 gain +2
@@ -191,7 +194,7 @@ consonant intelligibility sits around 2–4 kHz.
191194

192195
### 5b. Repair — honestly named (static)
193196

194-
These are the *reachable half* of Premiere's Repair section. The names must not
197+
These are the _reachable half_ of Premiere's Repair section. The names must not
195198
promise noise removal.
196199

197200
**`rumble-cut` — "Cut Rumble"** — `highpass` 100 Hz, poles 2. Two stacked nodes
@@ -210,13 +213,15 @@ and broad on purpose; sibilance proper is a script (§5e), not a fixed cut.
210213
### 5c. Character (static)
211214

212215
**`telephone` — "Telephone"** · the researched 300–3400 Hz band, steepened
216+
213217
```
214218
highpass frequency 300 q 0.707 poles 2 ×2 stacked (24 dB/oct)
215219
lowpass frequency 3400 q 0.707 poles 2 ×2 stacked
216220
peaking frequency 1200 gain +6 q 1.2 (the "honk")
217221
peaking frequency 550 gain -4 q 1.0 (de-mud)
218222
saturate type tanh threshold -18 output -2 (circuit colour)
219223
```
224+
220225
The registry maxes at 12 dB/oct per node (`poles: "2"`), so the classic
221226
24 dB/oct skirts need **two stacked nodes each**. Worth encoding once here
222227
rather than having every author rediscover it.
@@ -249,14 +254,14 @@ fake wow and flutter, which is a genuinely nice use of an effect we have.
249254

250255
### 5e. Adaptive scripts
251256

252-
**`de-ess` — "Soften Sibilance"** — *must be a script, not a preset.* A fixed
257+
**`de-ess` — "Soften Sibilance"** — _must be a script, not a preset._ A fixed
253258
−6 dB at 7 kHz dulls the whole voice; a de-esser only acts when sibilance is
254259
present. Run the carve pattern against the track's own 5–8 kHz band and emit a
255260
`peaking` node at the measured centre with a **lane on its gain** that dips only
256261
during sibilant windows. Sibilance centres around 5–6 kHz for lower voices,
257262
7–8 kHz for higher — measure it rather than assuming.
258263

259-
`analyseCarveDynamics` cannot be reused *unchanged* here, and this is the one
264+
`analyseCarveDynamics` cannot be reused _unchanged_ here, and this is the one
260265
place in §5e that needs work rather than a new caller. Its hop is
261266
`max(FRAME, length / POINT_BUDGET)` — 85 ms at best and ~150 ms on a
262267
real-length track — while sibilants are 50–150 ms events, so at that resolution
@@ -302,29 +307,29 @@ The rack is drawn as the signal path it is: numbered nodes on a dashed spine
302307
running from an `IN` terminal to an `OUT`, leader-dotted dimension lines,
303308
three-letter stage tags, family colour restricted to the node ring and the tag.
304309

305-
**Why it won over the louder options:** it is the only one that *adds
306-
information*. Chain order is load-bearing — a limiter first and a limiter last
310+
**Why it won over the louder options:** it is the only one that _adds
311+
information_. Chain order is load-bearing — a limiter first and a limiter last
307312
are different sounds — and nothing in the panel communicated it. It is also the
308313
quietest, which matters on a surface authors stare at while mixing.
309314

310315
**What the drawing carries that the current rack cannot say:**
311316

312-
| Drawn as | Instead of |
313-
| --- | --- |
314-
| `IN` names the source, `OUT` names the destination and the FX tail | nothing — the tail was invisible |
315-
| Numbered nodes 01…06 | implicit top-to-bottom order |
316-
| Bypassed node: ring drawn open, wire beside it solid and unbroken | a row at 50% opacity |
317-
| Preset nodes gathered under a right-hand brace with its name | no grouping at all |
318-
| An automated parameter's value reads **live at the playhead** and ticks while the transport runs, marked `~` | the stale seed the lane already replaced |
319-
| A measuring module gets a second ring | nothing distinguishes carve from a hand-set chain |
317+
| Drawn as | Instead of |
318+
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- |
319+
| `IN` names the source, `OUT` names the destination and the FX tail | nothing — the tail was invisible |
320+
| Numbered nodes 01…06 | implicit top-to-bottom order |
321+
| Bypassed node: ring drawn open, wire beside it solid and unbroken | a row at 50% opacity |
322+
| Preset nodes gathered under a right-hand brace with its name | no grouping at all |
323+
| An automated parameter's value reads **live at the playhead** and ticks while the transport runs, marked `~` | the stale seed the lane already replaced |
324+
| A measuring module gets a second ring | nothing distinguishes carve from a hand-set chain |
320325

321326
That last pair is the static-versus-script distinction from §4, delivered as
322327
drawing rather than documentation.
323328

324329
**Automated parameters show numbers, not shapes.** An earlier pass drew each
325330
lane's envelope inside the module; that was dropped. The lane already has a home
326331
in the timeline, and a second small drawing of it in the rack is decoration —
327-
what the rack is missing is the *current* value. The panel already receives it:
332+
what the rack is missing is the _current_ value. The panel already receives it:
328333
`FxSectionProps.liveAutomationValues` exists precisely because "an automated
329334
parameter's stored number is only the seed the lane replaced, so a rack that
330335
shows it stands still while the carve is audibly working". So the row is an
@@ -347,13 +352,13 @@ forcing each direction to find another answer is what separated them.
347352
**Family hues**, chosen to sit on `#0C0C0E` without competing with the studio's
348353
`#3CE6AC` accent:
349354

350-
| Family | Hue | Why |
351-
| --- | --- | --- |
352-
| Filter | `#4FA8FF` | the measuring family |
353-
| Dynamics | `#FFB443` | grips the signal |
354-
| Nonlinear | `#FF6B5C` | the only generative family |
355-
| Time | `#B98CFF` | atmosphere, not control |
356-
| Smart | `#3CE6AC` | the studio's own accent — reserved for modules that act on their own |
355+
| Family | Hue | Why |
356+
| --------- | --------- | -------------------------------------------------------------------- |
357+
| Filter | `#4FA8FF` | the measuring family |
358+
| Dynamics | `#FFB443` | grips the signal |
359+
| Nonlinear | `#FF6B5C` | the only generative family |
360+
| Time | `#B98CFF` | atmosphere, not control |
361+
| Smart | `#3CE6AC` | the studio's own accent — reserved for modules that act on their own |
357362

358363
**This needs almost no new plumbing.** `group` is already on every effect in the
359364
registry, so hue and lettering are derived, not hand-assigned. And every module
@@ -368,7 +373,7 @@ and starts reading as a collage on a surface authors stare at while mixing.
368373

369374
**Preset menu**: grouped by the same families, so the colour picked in the menu
370375
is the colour that appears in the rack. Each row carries the number of modules
371-
it drops in — which quietly teaches that a preset *is* a chain. Smart entries
376+
it drops in — which quietly teaches that a preset _is_ a chain. Smart entries
372377
say "measures" instead of a count, which is the entire static-vs-adaptive
373378
distinction delivered in one word.
374379

@@ -386,12 +391,12 @@ Mirror colour grading, because the author already understands that surface.
386391

387392
```ts
388393
export interface HfAudioFxPreset {
389-
id: string; // "telephone"
390-
label: string; // "Telephone"
394+
id: string; // "telephone"
395+
label: string; // "Telephone"
391396
family: "voice" | "repair" | "character" | "space";
392-
description: string; // one line, in the author's language
393-
chain: HfAudioFxChain; // an ordinary chain — nothing special
394-
automation?: HfAutomation; // for presets that move
397+
description: string; // one line, in the author's language
398+
chain: HfAudioFxChain; // an ordinary chain — nothing special
399+
automation?: HfAutomation; // for presets that move
395400
}
396401
```
397402

@@ -408,7 +413,7 @@ Four notes:
408413
`mix` parameter, which is the natural hook if intensity is wanted later —
409414
note it, don't build it.
410415
4. **Scripts need a separate registry** with an `analyse(samples, sampleRate) →
411-
{ chain, automation }` contract, because they cannot be static data. Carve is
416+
{ chain, automation }` contract, because they cannot be static data. Carve is
412417
the reference implementation.
413418

414419
### Two things that will otherwise be filed as bugs
@@ -459,9 +464,10 @@ Internal: `wiki/decisions/vst-studio-integration-cancelled.md`;
459464
[voice loudness and gain boosting](https://heygen.slack.com/archives/C07BR8QRE4T/p1769062551169729).
460465

461466
External:
467+
462468
- [Adobe Podcast Enhance Speech guide](https://thepodcastconsultant.com/blog/adobe-podcast-enhance) and [Adobe vs Descript shootout](https://thepodcasthaven.com/adobe-speech-enhancement-vs-descript-studio-sound-a-shootout/) — Tier 1 boundary
463469
- [Premiere Pro Essential Sound panel guide](https://josephnilo.com/blog/the-ultimate-guide-to-the-premiere-pro-essential-sound-panel/) and [Envato's dialogue walkthrough](https://photography.tutsplus.com/articles/how-to-use-the-essential-sound-panel-to-edit-dialogue-in-premiere-pro--cms-41936) — the intent-panel model
464470
- [Rode's podcast processing guide](https://rode.com/en-us/about/news-info/a-guide-to-audio-processing-and-fx-for-podcasting), [Podigy on podcast EQ](https://www.podigy.co/podcasters-eq) and [iZotope on de-essing](https://www.izotope.com/en/learn/the-dos-and-donts-of-de-essing.html) — voice chain values and sibilance ranges
465-
- [CapCut voice filters](https://www.capcut.com/tools/voice-filters) and [its full effect list](https://irda27987s-random-pages.fandom.com/wiki/All_Voice_Filters_and_Voice_Characters_in_App!_(Capcut)) — Tier 3 vocabulary
471+
- [CapCut voice filters](https://www.capcut.com/tools/voice-filters) and [its full effect list](<https://irda27987s-random-pages.fandom.com/wiki/All_Voice_Filters_and_Voice_Characters_in_App!_(Capcut)>) — Tier 3 vocabulary
466472
- [Telephone effect settings](https://voxbooster.com/blog/telephone-voice-effect-online/) and [Audiotent's walkthrough](https://www.audiotent.com/blogs/production-tips/create-telephone-vocal-effect) — the 300–3400 Hz band and its refinements
467473
- [LUFS targets per platform 2026](https://www.forasoft.com/learn/audio-for-video/articles-audio/lufs-targets-per-platform-2026) and [podcast loudness standards](https://sone.app/blog/podcast-loudness-standards-2026-spotify-apple-youtube) — why `level-out` must not claim LUFS

0 commit comments

Comments
 (0)