Nodes/ComfyUI-SRT-subtitles-VoxCPM/VoxCPM SRT Processor (from Scratch)
ComfyUI Node

VoxCPM SRT Processor (from Scratch)

Paste an SRT file, get back a full voice track — from scratch

By judian17·Created 10 months ago·Updated 10 months ago· 7
VoxCPM SRT Processor (from Scratch)
  • model
  • cache_group
  • AUDIO
srt_text1 00:00:00,500 --> 00:00:02,000 speaker1 Hello world.
normalize_texttrue
stretch_methodlibrosa
stretch_n_fft320
stretch_hop_length8
keep_model_loadedtrue
cfg_value2.0
inference_timesteps30
seed-1
retry_max_attempts3
retry_threshold6.00

This is the pack's headline node, and it does exactly what the name says: give it an SRT subtitle file and the speaker caches, and it generates a complete voice track from nothing - no source audio required. It's the difference between "edit the audio I already have" and "make audio that matches these subtitles." If you're producing narration, a dub for a video with no existing dialogue, or an audiobook from a transcript, this is the one you're here for.

How it works

The node parses your SRT into entries (index, start, end, speaker, text), builds a silent audio timeline long enough to hold the last subtitle, then processes line by line. For each line it generates speech with VoxCPM using that speaker's cached voiceprint, optionally time-stretches it to fit the subtitle's duration, and drops it at the right moment on the timeline. Everything comes out as a single mono AUDIO track at 16 kHz.

The SRT format decides the mode. If your cache group has exactly one speaker, no prefix is needed - every line just reads Hello world!. With two or more caches, multi-speaker mode kicks in and every line needs speaker1 Hello world! style prefixes that match the cache names. Lines that reference a speaker not in the cache group get skipped with a warning, not an error - so check the console if audio mysteriously goes missing mid-sentence.

The inputs that matter

Most of the common synth knobs carry over from the README:

  • normalize_text (default on) - reads "50" as "fifty" instead of "five zero" via the wetext normalizer.
  • stretch_method - none, librosa, or pydub. pydub sounds better but needs FFmpeg installed and in PATH; librosa is the default and can get "metallic" artifacts, which stretch_n_fft / stretch_hop_length (defaults 320 / 8) partially tame. Note stretching only fires when the generated audio is longer than the subtitle slot - it never speeds up a short line to fill space.
  • cfg_value (default 2.0) - balanced; higher can improve results but gets unstable.
  • inference_timesteps (default 30) - more steps, better quality, slower. The README notes 10 is already usable.
  • seed (default -1 = random) - set it to reproduce a take.
  • retry_max_attempts (3) and retry_threshold (6.0) - VoxCPM compares generated audio length to text length; if the ratio blows past the threshold it counts it a failure, discards it and re-rolls a new seed. For very slow speakers, raise the threshold to 8–10, or set attempts to 0 to disable.
  • keep_model_loaded (default on) - off if you want the model shoved back to CPU after the run to free VRAM.

Installing it

Ship of the pack judian17/ComfyUI-SRT-subtitles-VoxCPM:

cd ComfyUI/custom_nodes
git clone https://github.com/judian17/ComfyUI-SRT-subtitles-VoxCPM

Restart, or install via ComfyUI Manager (search "SRT subtitles VoxCPM"). First run auto-downloads openbmb/VoxCPM-0.5B into models/TTS; the pack pulls in librosa, pydub, soundfile and the torch/transformers stack. If you don't need pydub stretching, you can skip FFmpeg - everything else works without it. Wire the output into core SaveAudio and you're done.

Categoryaudio/tts

Inputs (13)

NameTypeDefaultDescription
modelVOXCPM_MODEL
cache_groupCACHE_GROUP
srt_textSTRING1 00:00:00,500 --> 00:00:02,000 speaker1 Hello world.
normalize_textBOOLEANtrue
stretch_methodCOMBOlibrosa3 options: none, librosa, pydub
stretch_n_fftINT320128–8192
stretch_hop_lengthINT88–2048
keep_model_loadedBOOLEANtrue
cfg_valueFLOAT2.01–10
inference_timestepsINT301–100
seedINT-1-1–9223372036854776000
retry_max_attemptsINT30–10
retry_thresholdFLOAT6.002–20

Outputs (1)

NameTypeDescription
AUDIOAUDIO