Lyric Forced Align
Your lyric sheet is right and Whisper is wrong — this node pins every word to the audio anyway
- audio
- alignment
- lrc
- info
Here's the situation: you have a song and you have the real lyrics - from the lyric sheet, the liner notes, wherever. What you don't have is a timestamp for each line. Whisper will hand you one, but its transcript is wrong in exactly the spots you care about, and it drifts. LyricForcedAlign skips the transcription step entirely. It takes the audio and your known-good lyric sheet and stamps a start and end time onto every ground-truth word. That's forced alignment: the model isn't guessing what was said, it's placing words you already have.
It's the engine of the comfyui_lyric_align pack - the audio route. You feed it audio plus lyrics, get a full alignment back, and then LyricSliceByTime turns that into "what's sung between T and T+D".
How it works
Under the hood it uses torchaudio's MMS_FA pipeline, a wav2vec2-based CTC forced aligner. The neat part of CTC forced alignment: the model is constrained to emit your words in your order. It can't reorder them or drop them, only decide when each one happened. That's why four identical chorus lines stop being ambiguous - time separates them, and each occurrence gets its own span instead of collapsing into one guess.
Inputs and outputs that matter
- audio (AUDIO): the full track, not a clip. And per the pack's own showcase workflow, feed it the isolated vocal stem - VocalRemovalNode's output 0 - rather than the full mix. Alignment sticks to a clean voice far better than a voice buried in instruments. Slice afterwards with LyricSliceByTime.
- lyrics (STRING): your ground-truth sheet, one line per lyric line. Blank lines are kept as section breaks, so keep the sheet formatted like the song rather than one paragraph.
- chunk_seconds: the one that saves your VRAM. Default 0 runs a single pass, fine up to about two minutes on a 24 GB card. Set 60 for a full song - wav2vec2 attention is quadratic in length, so one pass over a whole track can exhaust memory.
- device: cuda by default, falls back to cpu automatically if there's no CUDA.
Outputs are three strings: alignment (JSON - wire this into LyricSliceByTime or save it), lrc (a ready timestamped lyric file you can drop into any player), and info (diagnostics: how many words and lines aligned, the median score).
Three things that'll trip you up
- Confidence scores around 0.2 on singing are normal. MMS_FA is a speech model, and sung vocals aren't speech. A low score is not a failed alignment - judge the LRC, not the numbers.
- Only
a-zand the apostrophe align. Digits, punctuation and accents are stripped before alignment. They survive in the output text but get no timestamp - "café" aligns as "cafe". - The first run downloads a 1.18 GB checkpoint, so the first queue looks like it's hung. It isn't.
Install
ComfyUI Manager, search "comfyui_lyric_align", or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_lyric_align
Then restart ComfyUI. The pack declares torchaudio and rapidfuzz as dependencies. If your Python env lacks torchaudio, pip install torchaudio - make sure the version matches your torch, which is the usual way audio nodes break in ComfyUI (the whole audio layer is a bolt-on fighting dependency conflicts; see the ecosystem KB for how normal that is).
Troubleshooting
- Out of memory on a long track → set
chunk_secondsto 60. - "No alignable words in the lyrics" → your sheet is all numbers or punctuation. Add some letters.
- Timestamps look shifted → you fed it a clip instead of the whole track, or the full mix instead of the vocal stem. Re-run on the full-length vocal.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| audio | AUDIO | The FULL track, not a clip. Slice afterwards with Lyric Slice By Time. | |
| lyrics | STRING | Ground-truth lyric sheet, one line per lyric line. Blank lines are kept as section breaks. | |
| deviceopt | COMBO | cuda | 2 options: cuda, cpu |
| chunk_secondsopt | FLOAT | 00–600 | 0 = one pass over the whole track (fine to ~2 min on 24 GB). Set 60 for long tracks: wav2vec2 attention is quadratic in length, so a full song can exhaust VRAM in a single pass. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| alignment | STRING | — |
| lrc | STRING | — |
| info | STRING | — |