Qwen3-TTS Save Voice ⚡
Stop re-extracting the same voice every session
- voice_clone_prompt
- audio
A VOICE_CLONE_PROMPT lives in RAM and dies with the workflow. Which means the same reference clip gets re-encoded every session, on every render, forever. Save Voice is the boring node that fixes it: give it a prompt, give it a name, and it's on disk.
This is the kind of utility you don't think about until you've spent a week doing voice tests, and then it's the first node you add.
What it writes
Two required inputs - voice_clone_prompt (a VOICE_CLONE_PROMPT, from Voice Clone Prompt or Load Speaker) and filename (default my_voice) - and it writes into models/qwen-tts/voices/:
<name>.qvp- the prompt itself, serialised.<name>.json- metadata holdingref_text, the transcript you typed in.<name>.wav- a preview, but only if you connect the optionalaudioinput.
That folder is the flybirdxx layout on purpose, so voices saved here are interchangeable with the source pack's nodes - and shared with them too, since both read and write the same directory. The path is <ComfyUI>/models/qwen-tts/voices/, not under the Qwen3-TTS model tree, which surprises people who go looking in the wrong folder.
There are no outputs. It's an output node: it runs last, does its side effect, and there's nothing to wire downstream.
The one input you must not skip
Connect audio.
It's optional, and skipping it is the trap. Qwen3-TTS Load Speaker builds its file dropdown from the audio files in that folder - .wav, .mp3, .flac - not from .qvp files. Save without the preview and you'll have a perfectly good prompt on disk that Load Speaker never lists, so you can't get it back into a graph through the node that's supposed to load it. The prompt isn't corrupt; it's just invisible.
So: voice_clone_prompt and audio both come off the same Voice Clone Prompt node - wire both. The transcript goes in ref_text so Load Speaker can restore it later, which matters because that transcript is what makes a prompt more than a speaker embedding.
The .wav write prefers torchaudio by default but falls back to soundfile and then to a plain stdlib 16-bit PCM write, so it works on an install with no audio backend at all. It never fails the save - a preview write error is a log warning, not a crashed run.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/ChrisColeTech/ComfyUI-GGUF-Loader
pip install -r ComfyUI-GGUF-Loader/requirements.txt
The pack's hard dependency is gguf; qwen-tts is the optional one the whole Qwen3-TTS family needs, and it's already listed. If the import fails, these nodes disappear from the menu with one line in the startup log - not an error dialog. ComfyUI Manager works too: search the pack title.
Where people get burned
Reading .qvp files from other people. The prompt file is a Python pickle, and loading one executes what's inside it. This pack's Load Speaker is honest about that - the code comment says it plainly: only ever load .qvp files you saved yourself. Downloadable "voice packs" of .qvp files are the same class of risk as a downloaded custom node, and the ComfyUI ecosystem has already had one memorable malware incident through exactly this channel: a node that ran code on import and ended with a federal prosecution. Don't add a second way in.
Filenames. Any directory part is stripped and the extension dropped, so my_voice.wav becomes my_voice and paths won't escape the voices folder - but an empty name raises filename must not be empty rather than writing something odd. Reusing a name overwrites the old voice, preview included. That's a feature until it isn't.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| voice_clone_prompt | VOICE_CLONE_PROMPT | — | |
| filename | STRING | my_voice | — |
| audioopt | AUDIO | Reference audio to save as a .wav preview alongside the prompt. | |
| ref_textopt | STRING | Transcript stored in the .json metadata and restored by Load Speaker. |
Outputs (0)
No outputs