Nodes/Lyrebird/Voice Cleanup
ComfyUI Node

Voice Cleanup

The unglamorous Lyrebird node you'll run on every take

By agarzon·Created 27 days ago·Updated 27 days ago· 2
Voice Cleanup
  • audio
  • AUDIO
◄high_pass_hz80►
◄hum_removaloff►
◄noise_reduction0.50►
◄gate_threshold_db-80►
◄de_ess0.00►
◄normalize_lufs-16►

Audio got bolted onto ComfyUI late, and it shows. The models are good - Chatterbox, ACE-Step, MMAudio all earn their place - but none of them care whether your input was recorded in a nice room. Hand them a phone recording with a fridge humming in the background and they faithfully synthesize the fridge.

Voice Cleanup is the boring half of ComfyUI-Lyrebird doing the boring job: take a raw voice recording, leave the voice, remove the room. No model, no weights, no GPU - a fixed-order DSP chain in numpy and scipy that costs you one node instead of the six-node soup you'd otherwise build out of unrelated audio packs.

What it actually does

The chain runs in one fixed order, which is the whole reason to let an author decide it for you:

high-pass → mains-hum notch → noise reduction → gate → de-ess → loudness normalize

Mechanically, from the shipped source: a second-order Butterworth high-pass for rumble, notch filters at your mains frequency plus four harmonics above it, spectral gating for broadband hiss, a noise gate, a 4–9 kHz band whose top gets compressed and mixed back over the dry signal, then integrated loudness to your target and a smoothed -1 dBFS peak limiter.

Two behaviours are worth knowing before you file a bug. Empty or silent input comes straight back untouched, and loudness normalization is skipped on clips shorter than 0.4 seconds - integrated loudness on a 200 ms fragment is meaningless. So if you're testing with a stub clip and the LUFS setting appears to do nothing, that's why.

The knobs you'll actually touch

Three of the six matter in normal use:

  • noise_reduction - the one people crank. The default 0.5 is a sensible middle; it maps to prop_decrease in spectral gating, and pushing it to 1.0 buys you less hiss and pays for it in that watery, phasey "underwater" texture on the consonants. If you need 1.0, your source was too noisy to save.
  • hum_removal - pick the mains frequency for your region, 60 Hz in North America, 50 Hz in Europe and most of Asia. Choose wrong and the notch lands where there's no hum, so you'll hear no change at all and conclude the node is broken. It notches the fundamental plus four harmonics, so it cleans the buzz you can hear and the ones you can't.
  • normalize_lufs - defaults to -16, with off, -14, -19 and -23 available. -16 is fine for web video, -14 if you're heading somewhere that pushes loudness, -23/-19 for EBU-ish broadcast.

The other three are situational: high_pass_hz at 80 removes rumble and desk thumps (0 turns it off, which you want if there's real bass content); gate_threshold_db sits at -80, i.e. off, and wants maybe -40 only if you need silence between phrases, since pushing it up chops word tails; de_ess is off by default and exists for genuinely spiky sibilance - 1.0 will give your speaker a lisp.

One output, AUDIO, plain and boring. That's the nice part: core AUDIO wires straight to Voice FX, SaveAudio, PreviewAudio, or an audio-driven avatar later in the chain.

Installing it

Graphically: ComfyUI Manager → Custom Nodes Manager → search Lyrebird → Install → restart. Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/agarzon/ComfyUI-Lyrebird.git
pip install -r ComfyUI-Lyrebird/requirements.txt

Then restart. The pack wants ComfyUI ≥ 0.4.0 - it's built on the newer comfy_api.latest IO schema, so on an older build the import fails outright rather than degrading gracefully.

Dependencies are the real install story: numpy, scipy, pedalboard (pinned away from the broken 0.9.25), pyworld-prebuilt, noisereduce, pyloudnorm. That pyworld-prebuilt is the troublemaker in a shared environment: it provides the same pyworld module as the ordinary package, so another pack that wants upstream pyworld will fight it, and whichever landed last wins. Python 3.10 or newer.

Where it goes wrong

The failure modes are mostly self-inflicted by over-processing, and they're audible rather than fatal. Crank noise reduction and de-ess together and you get the classic "AI podcast" sound: every breath stripped out, every sibilant flattened into a puff. Do the pass, listen, then undo half of what you just did.

Two practical notes. This is CPU work on numpy arrays, so it's quick for a voice clip and slow for a long file - spectral gating isn't free. And there's no sample-rate conversion anywhere in the chain, so what goes in comes out at the same rate and nothing downstream in a lip-sync pipeline gets surprised.

Finally: run it before Voice FX, not after. FX is a character effect that will happily amplify hiss along with the voice, and cleaning up a monster voice is much harder than cleaning the input.

Categoryaudio/Lyrebird

Inputs (7)

NameTypeDefaultDescription
audioAUDIO—
high_pass_hzINT800–200Removes rumble below this frequency. 0 = off.
hum_removalCOMBOoffNotches out mains hum and its harmonics.
noise_reductionFLOAT0.500–1How much background noise to remove.
gate_threshold_dbFLOAT-80-80–-20Silences audio quieter than this. -80 = off.
de_essFLOAT0.000–1Tames harsh 's' and 'sh' sounds.
normalize_lufsCOMBO-16Target loudness in LUFS, with a -1 dBFS peak limit.

Outputs (1)

NameTypeDescription
AUDIOAUDIO—