CB Load Speaker ⚡️
Stop re-uploading the same voice clip every time
- ref_audio
- ref_text
The problem it solves is a small one that you hit constantly
Zero-shot voice cloning needs two things: a few seconds of reference audio, and - for most engines - the exact words that were spoken in it. Chatterbox clones from roughly five to ten seconds of clean speech; F5-TTS does the same job from a short clip, and both are happy on 8GB of VRAM.
So every TTS session starts the same way: dig out the reference wav, drop it in an audio loader, and retype the line if the node you're using wants a transcript. Do that across four workflows and three test characters and you've got wav files scattered through your inputs folder and no idea which one belonged to which script line.
CB Load Speaker is the storage end of that. You file a voice once - clip plus transcript, under a name - and from then on you pick it from a dropdown. This is the "library" half of a pair; CB Save Speaker writes the entries.
How it works
The speaker widget is a combo that the node builds by scanning your speakers folder at load time. For every .json in there it checks that a matching audio file actually exists, then sorts the survivors case-insensitively. If none survive, you get a single entry: [no speakers saved].
Pick a name and it resolves the base path, prefers the audio filename recorded inside the JSON, and if that's missing falls back to any .mp3, .wav or .mp4 whose base name matches the speaker name. The audio is decoded through PyAV if it's installed, then torchaudio, then a plain-Python wave fallback - so a WAV always works even on a bare install. The transcript comes from the JSON, checked against ref_text, then text, then transcription.
Two outputs, both useful: ref_audio (AUDIO) goes into your TTS node's reference input, ref_text (STRING) goes into whatever field that engine wants the reference line in.
By default everything lives in models/SPEAKERS, and that's a real choice by the author rather than an accident - your voice library sits with your models, not in output/ where it'd get mixed into generated junk. You can change it in the pack's config.json:
{ "speakers_folder": "models/SPEAKERS" }
A relative path resolves against your ComfyUI root, an absolute path is taken as-is, and ~ and environment variables get expanded.
Inputs and outputs
| | |
|---|---|
| speaker (combo, required) | the saved speaker you want, from models/SPEAKERS |
| ref_audio (AUDIO, output) | the reference clip |
| ref_text (STRING, output) | the transcript stored with it |
Installing it
Manager → Custom Nodes Manager → search ComfyUI CoolB Nodes → Install → restart. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/CoolBreeze164/ComfyUI-CoolB-Nodes
No model downloads. The README notes av, numpy and torchaudio ship with ComfyUI; the source backs that up, with every one of those imports wrapped in try/except and a pure-WAV fallback behind them.
Common issues
A voice you just saved isn't in the dropdown. The list is built when ComfyUI reads the node's schema, so it's a snapshot. Refresh the page; if it's still missing, restart ComfyUI. Also confirm the entry has both halves - a .json and an audio file with the matching base name. An orphan wav dropped into the folder by hand won't show up at all, because the JSON is what registers the speaker.
Empty or silent output. With [no speakers saved] selected, the node returns a one-sample silent tensor rather than raising. Downstream TTS then gets a useless reference clip instead of a clear error, which is worth knowing before you spend twenty minutes debugging the TTS node.
It picked up the wrong file. If several audio files share a speaker's base name, the audio_file recorded in the JSON wins; without one, the match order is whatever the filesystem hands back for .mp3/.wav/.mp4. Include an .mp4 that happens to share the name and it can be the one it grabs. Fix it by re-saving the speaker, or check audio_file in the JSON.
The transcript is empty. Older or hand-written sidecars may not carry ref_text. The node checks ref_text, text and transcription, so any of those keys works - but it won't guess, and an empty reference text quietly degrades some cloning engines.
Cloning caveats belong here too. Zero-shot voice cloning from a clip is the point of these nodes, and it's also where the ethical line sits - Chatterbox ships a watermark by default, F5-TTS doesn't, and neither stops you cloning a voice you have no business using. Library-side advice: keep it to voices you have permission to use.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| speaker | COMBO | [no speakers saved] | 1 options: [no speakers saved] |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| ref_audio | AUDIO | — |
| ref_text | STRING | — |