QuokkaiLab - Audio Conditioning Fix
LTX talking head moving its mouth wrong? This node feeds the model a mangled copy of your voice
- audio
- conditioning_audio
- mux_audio
- duration
- frame_count
- speech_start
- effective_duration
- trimmed_leading
- trimmed_trailing
The pitch is absurd on its face: to get better English lip-sync out of LTX, you take your clean speech, ring-modulate it at 70 Hz, band-pass it, and hand that to the conditioning encoder. You never hear the mangled version - it only drives the mouth, while the clean speech goes to the mux separately.
That's the whole idea behind QuokkaiLab Audio Conditioning - and it's an empirical production workaround, not a model-level fix.
What it is, and when you'd reach for it
LTX-2 became the local lip-sync model almost by accident: it was the first open-weights thing generating synced audio and video in one pass, and the community's verdict landed fast - the killer app is talking heads, not general video. The recurring complaint is weak or barely-there mouth motion on some English speech.
This node sits between LoadAudio and the audio encoder and changes nothing about your model, sampler, or prompts. In the pack's matched A/B - same image, voice, prompt and seed - the only difference is enable_fix. Run a pair on your own clip before you believe anything.
How the fix works
The recipe in the source is called ringmod70:
- Multiply the samples by
0.55 + 0.45*cos(2*pi*70*n/sr)- an amplitude modulation, not true ring mod. - Run a second-order Butterworth band-pass, 180–6500 Hz, forward and backward (
sosfiltfilt, so no phase smear). - Normalize the peak to 0.95, then paste the original samples back over everything before the first and after the last -40 dBFS crossing. Zeros stay zeros.
- Round-trip through PCM24, re-verifying rate, peaks and the first/last crossings.
No pitch shift, no time stretch, no compressor. Timing is shared too: trim, pad and the 8k+1 frame snap happen identically for both arms, and the node throws if the transformed audio lands differently. Nice paranoia - the driver and the clean track can't drift apart.
Inputs you actually touch
audio is your mono WAV. Stereo, batch size above one, non-finite samples, peaks at or above 1.0, rates at or below 13 kHz (the 6500 Hz filter needs headroom) and speech-free clips are all rejected. Two or three seconds of speech is the sweet spot.
Most defaults are fine. The three that matter:
enable_fix- the A/B switch. Off, both outputs carry clean audio.silence_after(0.5s) andsafety_margin(0.3s) - headroom so the clip fits the frame budget.mux_shift_ms- nudge the audible track against the picture if your audio lands late.
Leave silence_threshold_db at -40. The node hard-errors if you move it, because the recipe's boundary detection is validated at exactly that level.
Outputs
conditioning_audio is the driver - in the pack's graph it lands in the Preprocess group and gets encoded by LTXVAudioVAEEncode. mux_audio goes into the Decode group, where CreateVideo uses it as the soundtrack; it's always clean speech, fix on or off. Then the pacing set: duration and frame_count are the same length in two forms (1 + floor(duration*fps/8)*8), effective_duration is frame_count / fps, speech_start is the silence that ended up in front of the speech, and trimmed_leading/trimmed_trailing are what the trimmer cut - diagnostic gold when a render misaligns.
Install
Manager is the clean path once the Registry clears. The package is quokkailab-audio-conditioning (publisher quokkailab), but at the pack's publication check 1.0.0 was still pending - so search "QuokkaiLab Audio Conditioning" and fall back to git if it isn't listed:
cd ComfyUI/custom_nodes
git clone https://github.com/sducly/quokkai-lab-ltx25-lipsync-fix
cd ..
python -m pip install -r custom_nodes/quokkai-lab-ltx25-lipsync-fix/requirements.txt
That's NumPy (<2.5), SciPy pinned to 1.15.1 and SoundFile, plus libsndfile, which the wheels carry. No FFmpeg, no PyAV. Use the Python that runs ComfyUI, and restart after.
Two install gotchas. The repo's root __init__.py re-exports the class from custom_nodes/quokkailab_audio/, so a plain clone registers the node - just don't also hand-copy that inner folder into custom_nodes/, because that's two registrations of one class name. The pack's workflow also wants five LTX-2.5 files (a 22b distilled BF16 transformer, the Gemma text encoder, both VAEs, the latent upscaler). This node doesn't care; the graph won't run without them.
Where people get burned
The length error is the common one. Long speech produces Trimmed TTS too long for <= 5.00s at 24 fps; shorten by about X.XXXs. The node gives back the safety margin first, then trailing, then leading silence, and refuses rather than silently truncating. You can't raise max_duration past the 5.0 ceiling, so trim the recording.
Moving the threshold - one nudge off -40 and it errors out. People also lose an hour to a stereo or clipped export; both are rejected up front with a clear message.
Then the honest caveat from the pack itself: several matched human clips improved, two animated baselines already looked fine, and nobody knows why the fix helps. Searching for this pack gets you tumbleweed, so you're your own evidence base - run a baseline pair before restructuring a pipeline around it.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| audio | AUDIO | — | |
| trim_leading_silence | BOOLEAN | true | — |
| trim_trailing_silence | BOOLEAN | true | — |
| silence_threshold_db | FLOAT | -40-80–-10 | — |
| min_keep_ms | INT | 200–200 | — |
| silence_before | FLOAT | 0.000–4 | — |
| silence_after | FLOAT | 0.500–4 | — |
| safety_margin | FLOAT | 0.300–1 | — |
| mux_shift_ms | INT | 0-1000–1000 | — |
| fps | FLOAT | 181–60 | — |
| max_duration | FLOAT | 5.01–5 | — |
| enable_fix | BOOLEAN | true | — |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| conditioning_audio | AUDIO | — |
| mux_audio | AUDIO | — |
| duration | FLOAT | — |
| frame_count | INT | — |
| speech_start | FLOAT | — |
| effective_duration | FLOAT | — |
| trimmed_leading | FLOAT | — |
| trimmed_trailing | FLOAT | — |