Shorts audio skill
Clean the audio on a talking-head recording without making it sound processed — constant-gain loudness, rumble removal, and when (not) to denoise.
by timscheuerai·MIT license·★ 37 Stars on the repo·GitHub ↗
npx degit timscheuerai/content-vault/skills/shorts-audio#main ~/.claude/skills/shorts-audioChecked ·commit main
Inside this skill
SKILL.md · the author's own words# shorts-audio Stage 2 of shorts-edit. **Two traps, both silent, both cost hours.** Quiet recordings cause both. The reference takes sat at **−43 LUFS** and needed **+26 dB**. --- ## TRAP A: `loudnorm` silently pumps `loudnorm` with `linear=true` promises a single constant gain. **It abandons that promise without warning** whenever the required gain would push the true peak past the ceiling — which +26 dB always does. It falls back to *dynamic* mode: per-frame gain riding. Pumping, breathing, a squashed unnatural tone.
Word-for-word excerpt, not a result. Read the full SKILL.md ↓
Files of Shorts audio
Show the full text93 lines
shorts-audio
Stage 2 of shorts-edit. Two traps, both silent, both cost hours.
Quiet recordings cause both. The reference takes sat at −43 LUFS and needed +26 dB.
TRAP A: loudnorm silently pumps
loudnorm with linear=true promises a single constant gain.
It abandons that promise without warning whenever the required gain would push the true peak past the ceiling — which +26 dB always does. It falls back to dynamic mode: per-frame gain riding. Pumping, breathing, a squashed unnatural tone.
This — not the denoiser — was the actual cause of "the audio sounds artificial". Removing the denoiser alone did not fix it, which is exactly why it cost so much time.
Fix: never use loudnorm for gain. Measure the true peak, apply ONE constant
volume=XdB that lands it at −1.5 dBTP, and accept whatever LUFS falls out.
Verified pure: correlation 0.999975 with the source waveform, residual 43 dB down (just AAC noise), no limiter ever engaged. Mathematically, the output is the input times a number.
TRAP B: every denoiser reconstructs the voice, and you can hear it
afftdn with tn=1 (blind tracking) guesses the noise spectrum moment to moment.
Guessing wrong is precisely what makes musical burbling.
Learning the profile from real silence in the take is far better — asendcmd … sn start/stop around the longest silence:
| chain | noise reduction | speech level |
|---|---|---|
| highpass 60Hz only | 11.2 dB | −0.1 dB |
| RNNoise (arnndn) | 17.6 dB | −0.1 dB |
| learned print, nr=12 | 23.0 dB | −0.1 dB |
And it still didn't ship. On headphones, every spectral denoiser — blind, learned, even a 50/50 wet/dry blend — was audible as an unnatural tone, because they all reconstruct the signal rather than merely attenuating it. The user listened to all of them and chose the honest one.
SHIPPED: no denoiser.
highpass=f=60+ a constant gain. Nothing else.
If a genuinely noisy take needs help, print12@50 (a 50% blend) was the best compromise.
Two ordering rules that silently defeat the filters
The denoiser must run BEFORE the trims. Its
asendcmdtimestamps point at silence in the ORIGINAL take, and the edit throws that silence away. Applied after the cut, the sample window falls outside the clip, the command never fires, and afftdn quietly reverts to blind mode — the exact thing that sounded fake. The floor betrays it: −54 dB (blind) vs −64.8 dB (learned).Gain must precede ANY denoiser. RNNoise is trained on speech at normal levels. Fed −68 dBFS audio it sees silence and does literally nothing (measured: 0 dB of extra reduction). Gain it first and the same filter removes 23 dB.
What did NOT work
- A noise gate. Intuitive — mute the gaps — and useless: after the edit the cut is 96% speech. There are no gaps left to gate. The audible noise is under the voice.
- Notch filters. The noise looked like 60Hz mains harmonics at coarse FFT resolution. At fine resolution it isn't: 69% of the voice-band noise is broadband room tone. Notching mangled the voice (correlation 0.77) to buy 3 dB.
The mono-SFX clipping trap
amix negotiates a common channel layout. A mono SFX bed makes it pick mono, which
silently downmixes the stereo voice — and that downmix pushed the peak from −1.62 dB to
+0.83 dB (clipping). Pin aformat=channel_layouts=stereo on both sides of the mix.
Known tradeoff: the clips are quiet (−18 to −23 LUFS)
Peak-normalizing with no limiting and no compression lands below the −14/−16 social norm. That is the honest ceiling for zero dynamics processing; getting louder means compressing, which is what was rejected. Platforms normalize on playback.
The real fix is at the source: raise the input gain when recording.
| 1 | |
| 2 | name shorts-audio |
| 3 | description Clean the audio on a talking-head recording without making it sound processed — constant-gain loudness, rumble removal, and when (not) to denoise. Use when recording audio sounds weird, artificial, pumping, quiet, or noisy, or when asked to denoise or normalize a video's audio. |
| 4 | |
| 5 | |
| 6 | # shorts-audio |
| 7 | |
| 8 | Stage 2 of shorts-edit. **Two traps, both silent, both cost hours.** |
| 9 | |
| 10 | Quiet recordings cause both. The reference takes sat at **−43 LUFS** and needed **+26 dB**. |
| 11 | |
| 12 | |
| 13 | |
| 14 | ## TRAP A: `loudnorm` silently pumps |
| 15 | |
| 16 | `loudnorm` with `linear=true` promises a single constant gain. |
| 17 | |
| 18 | **It abandons that promise without warning** whenever the required gain would push the true |
| 19 | peak past the ceiling — which +26 dB always does. It falls back to *dynamic* mode: per-frame |
| 20 | gain riding. Pumping, breathing, a squashed unnatural tone. |
| 21 | |
| 22 | **This — not the denoiser — was the actual cause of "the audio sounds artificial".** |
| 23 | Removing the denoiser alone did not fix it, which is exactly why it cost so much time. |
| 24 | |
| 25 | **Fix: never use `loudnorm` for gain.** Measure the true peak, apply ONE constant |
| 26 | `volume=XdB` that lands it at −1.5 dBTP, and accept whatever LUFS falls out. |
| 27 | |
| 28 | Verified pure: **correlation 0.999975** with the source waveform, residual 43 dB down (just |
| 29 | AAC noise), no limiter ever engaged. Mathematically, the output is the input times a number. |
| 30 | |
| 31 | |
| 32 | |
| 33 | ## TRAP B: every denoiser reconstructs the voice, and you can hear it |
| 34 | |
| 35 | `afftdn` with `tn=1` (blind tracking) *guesses* the noise spectrum moment to moment. |
| 36 | Guessing wrong is precisely what makes musical burbling. |
| 37 | |
| 38 | Learning the profile from real silence in the take is **far** better — `asendcmd … sn |
| 39 | start/stop` around the longest silence: |
| 40 | |
| 41 | | chain | noise reduction | speech level | |
| 42 | |---|---|---| |
| 43 | | highpass 60Hz only | 11.2 dB | −0.1 dB | |
| 44 | | RNNoise (arnndn) | 17.6 dB | −0.1 dB | |
| 45 | | **learned print, nr=12** | **23.0 dB** | **−0.1 dB** | |
| 46 | |
| 47 | **And it still didn't ship.** On headphones, every spectral denoiser — blind, learned, even |
| 48 | a 50/50 wet/dry blend — was audible as an unnatural tone, because they all *reconstruct* the |
| 49 | signal rather than merely attenuating it. The user listened to all of them and chose the |
| 50 | honest one. |
| 51 | |
| 52 | > **SHIPPED: no denoiser. `highpass=f=60` + a constant gain. Nothing else.** |
| 53 | |
| 54 | If a genuinely noisy take needs help, `print12@50` (a 50% blend) was the best compromise. |
| 55 | |
| 56 | |
| 57 | |
| 58 | ## Two ordering rules that silently defeat the filters |
| 59 | |
| 60 | **The denoiser must run BEFORE the trims.** Its `asendcmd` timestamps point at silence |
| 61 | in the ORIGINAL take, and the edit throws that silence away. Applied after the cut, the |
| 62 | sample window falls outside the clip, the command never fires, and afftdn **quietly |
| 63 | reverts to blind mode** — the exact thing that sounded fake. The floor betrays it: |
| 64 | −54 dB (blind) vs −64.8 dB (learned). |
| 65 | |
| 66 | **Gain must precede ANY denoiser.** RNNoise is trained on speech at normal levels. Fed |
| 67 | −68 dBFS audio it sees silence and does **literally nothing** (measured: 0 dB of extra |
| 68 | reduction). Gain it first and the same filter removes 23 dB. |
| 69 | |
| 70 | |
| 71 | |
| 72 | ## What did NOT work |
| 73 | |
| 74 | **A noise gate.** Intuitive — mute the gaps — and useless: after the edit the cut is |
| 75 | **96% speech**. There are no gaps left to gate. The audible noise is *under* the voice. |
| 76 | **Notch filters.** The noise looked like 60Hz mains harmonics at coarse FFT resolution. |
| 77 | At fine resolution it isn't: **69% of the voice-band noise is broadband** room tone. |
| 78 | Notching mangled the voice (correlation 0.77) to buy 3 dB. |
| 79 | |
| 80 | ## The mono-SFX clipping trap |
| 81 | |
| 82 | `amix` negotiates a common channel layout. A **mono** SFX bed makes it pick mono, which |
| 83 | silently downmixes the stereo voice — and that downmix pushed the peak from −1.62 dB to |
| 84 | **+0.83 dB (clipping)**. Pin `aformat=channel_layouts=stereo` on **both** sides of the mix. |
| 85 | |
| 86 | ## Known tradeoff: the clips are quiet (−18 to −23 LUFS) |
| 87 | |
| 88 | Peak-normalizing with **no limiting and no compression** lands below the −14/−16 social |
| 89 | norm. That is the honest ceiling for zero dynamics processing; getting louder means |
| 90 | compressing, which is what was rejected. Platforms normalize on playback. |
| 91 | |
| 92 | The real fix is at the source: **raise the input gain when recording.** |
| 93 |
Discussion
Browse more free Claude skills.