ComfyUI Extension: APZmedia Qwen TTS Nodes

Authored by APZmedia

Created

Updated

1 stars

Run ComfyUI workflows without the setup

No installs, no CUDA version roulette, no GPU sitting idle on your bill. Bring a workflow and run it in the browser.

ComfyUI nodes for Qwen3-TTS: voice design, voice library, segmented generation

README

APZmedia Qwen TTS — ComfyUI Node Suite

ComfyUI custom nodes for Qwen3-TTS: voice design, reusable voice library, voice cloning, per-segment emotion control, and flexible audio export. English UI throughout.


Requirements

  • ComfyUI with Python 3.10+ (3.12 recommended)
  • PyTorch 2.4+ — already in your ComfyUI venv; do not pip-install a second torch
  • GPU strongly recommended; CPU works with fp32 but is slow
  • Models download automatically from Hugging Face on first use

Install

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/APZmedia/ComfyUI-APZmedia-qwen-TTS
cd comfyui-apzmedia-qwen-tts
pip install -r requirements.txt

Or install via ComfyUI Manager once the package is published.


Models

Three Qwen3-TTS model families — load each with APZmedia: Model Loader:

| Model ID | Size | Use for | |----------|------|---------| | Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign | 1.7B | Voice Design, Voice Design Generate, Segmented Generate | | Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice | 1.7B | Custom Voice Generate (preset speakers) | | Qwen/Qwen3-TTS-12Hz-1.7B-Base | 1.7B | Voice Clone Generate, building embeddings in Voice Design | | Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice | 0.6B | Lightweight preset-speaker generation | | Qwen/Qwen3-TTS-12Hz-0.6B-Base | 0.6B | Lightweight cloning |


Nodes

APZmedia: Model Loader

Loads a Qwen3-TTS model. Outputs a QWEN_TTS_MODEL handle used by all generation nodes.

| Widget | Description | |--------|-------------| | model_name | Hugging Face model ID (dropdown) | | precision | bf16 (default, GPU), fp16, or fp32 (CPU fallback) | | device | auto, cuda, or cpu |


APZmedia: Voice Design

Creates a reusable voice identity from a natural-language description.

Requires two models: the VoiceDesign model generates a reference audio clip from your description; the Base model converts that clip into a speaker embedding (VoiceClonePromptItem) that can be reused across many generation calls.

This is a one-time setup step. After saving to the library you only need the Base model for generation.

| Input | Description | |-------|-------------| | model_design | VoiceDesign model handle | | model_base | Base model handle | | voice_description | Natural-language voice + style, e.g. "Deep authoritative male, slightly amused" | | reference_text | Short transcript spoken in the reference clip (≤ 20 words; must match audio exactly) | | language | Language of the reference text | | x_vector_only_mode | False (default): full in-context learning — best fidelity, needs accurate ref_text. True: speaker x-vector only — faster, ref_text not needed | | seed | Reproducibility seed |

| Output | Description | |--------|-------------| | voice_prompt | Speaker embedding — wire into Voice Clone Generate or Voice Library Save | | reference_audio | The generated reference clip — wire into Voice Library Save or preview | | reference_text | Passthrough — wire into Voice Library Save | | voice_description | Passthrough — wire into Voice Library Save as description |

Typical wiring:

[Model Loader: VoiceDesign]  [Model Loader: Base]
           ↓                         ↓
      model_design              model_base
                 ↘             ↙
             [Voice Design]
          ↙       ↓        ↓        ↘
   voice_prompt  audio  ref_text  voice_desc
        ↓          ↓        ↓         ↓
            [Voice Library Save]

APZmedia: Voice Design Generate

Generate speech with a natural-language voice direction. Single call, no voice identity saved. Uses the VoiceDesign model only.

| Input | Description | |-------|-------------| | model | VoiceDesign model handle | | text | Text to speak | | instruct | Voice + style direction, e.g. "Warm female, calm and serious" | | language | Output language | | seed | Reproducibility seed |


APZmedia: Custom Voice Generate

Generate speech with preset Qwen3-TTS speakers (Ryan, Vivian, etc.). Uses the CustomVoice model.

| Input | Description | |-------|-------------| | model | CustomVoice model handle | | text | Text to speak | | speaker_preset | Preset speaker dropdown | | speaker_name | (optional) Override with a custom speaker name not in the list | | language | Output language | | instruct | (optional) Emotion/style direction, e.g. "Very happy", "Speak in a calm and serious tone" | | seed | Reproducibility seed |


APZmedia: Voice Clone Generate

Generate speech using a saved voice identity. Uses the Base model with a voice_prompt embedding or a raw reference audio + transcript.

| Input | Description | |-------|-------------| | model | Base model handle | | text | Text to speak | | language | Output language | | seed | Reproducibility seed | | voice_prompt | (optional) Speaker embedding from Voice Design or Voice Library Loader | | ref_audio | (optional) Raw reference audio if no voice_prompt | | ref_text | (optional) Transcript for ref_audio (required unless x_vector_only_mode) | | instruct | (optional) Additional style direction | | x_vector_only_mode | Skip transcript-based ICL; use speaker x-vector only |

Provide either voice_prompt or ref_audio (not both required).


APZmedia: Voice Library Save

Save a voice to a named folder on disk (WAV + metadata JSON).

| Input | Description | |-------|-------------| | audio | Reference audio to save | | name | Subfolder name for this voice | | library_path | Absolute folder path. Empty → ComfyUI/output/apzmedia_voice_library/ | | voice_prompt | (optional) Noted in session; embedding is not serialized (WAV is the durable format) | | ref_text | (optional) Wire from Voice Design's reference_text output | | description | (optional) Wire from Voice Design's voice_description output |

Library structure on disk:

apzmedia_voice_library/
  narrator_warm/
    reference.wav
    metadata.json   ← name, description, created, sample_rate, ref_text
  nervous_teen/
    reference.wav
    metadata.json

APZmedia: Voice Library Loader

Load a saved voice and rebuild its speaker embedding. Requires the Base model.

| Input | Description | |-------|-------------| | model_base | Base model handle | | library_path | Folder containing voice subfolders | | voice_name | Subfolder name of the voice to load | | x_vector_only_mode | See Voice Design for explanation |

| Output | Description | |--------|-------------| | reference_audio | The saved WAV as ComfyUI AUDIO | | voice_prompt | Rebuilt speaker embedding — wire into Voice Clone Generate |

Use APZmedia: Voice Library List to see what voices are available before typing a name.


APZmedia: Voice Library List

Browse available voices in a library folder. Useful to discover voice names before using Voice Library Loader.

| Input | Description | |-------|-------------| | library_path | Library folder to inspect |

Outputs a formatted STRING listing each voice name, description, and ref_text preview.


APZmedia: Segmented Generate

Generate a multi-segment script where each segment has its own voice direction. Uses inline [voice: ...] markup. VoiceDesign model only.

Markup syntax

[voice: description] text to speak [/voice]

Plain text outside tags uses default_instruct.

Example:

[voice: warm and welcoming] Good morning, and welcome to the show. [/voice]
[voice: tense and hushed] What I'm about to tell you must not leave this room. [/voice]
[voice: cheerful and upbeat] But first — today's sponsor! [/voice]

Segments are generated sequentially and concatenated into one audio output.

| Input | Description | |-------|-------------| | model | VoiceDesign model handle | | script | Full script with [voice: ...] markup | | default_instruct | Voice direction for text outside tags | | language | Language for all segments | | seed | Reproducibility seed |

| Output | Description | |--------|-------------| | audio | Concatenated audio of all segments | | segment_count | Number of segments processed |


APZmedia: Audio Saver

Save audio to disk at any absolute path with a filename template.

| Input | Description | |-------|-------------| | audio | ComfyUI AUDIO to save | | output_path | Absolute folder path. Empty → ComfyUI output folder | | filename_template | Template string with tokens (see below) | | sample_rate | Output sample rate (8000–48000 Hz, default 24000) | | speaker | (optional) Used in {speaker} token | | text_preview | (optional) Used in {text_preview} token | | seed | (optional) Used in {seed} token |

Filename tokens:

| Token | Expands to | |-------|-----------| | {date} | 20260329 | | {datetime} | 20260329_143022 | | {speaker} | Value of the speaker input | | {text_preview} | First ~40 chars of text_preview, sanitized | | {seed} | Seed value as string |

Example template: {datetime}_{speaker}_{text_preview}.wav


Complete workflows

Workflow 1 — Quick generation with voice direction

[Model Loader: VoiceDesign] → [Voice Design Generate]
                                  text: "Hello world"
                                  instruct: "Warm, friendly female"
                                       ↓
                                    [Audio Saver]

Workflow 2 — Design a voice, save to library, reuse

[Model Loader: VoiceDesign]   [Model Loader: Base]
          ↓                          ↓
     model_design               model_base
               ↘                ↙
            [Voice Design]
         ↙    ↙      ↓       ↘
  voice_prompt audio ref_text voice_desc
                  ↓      ↓        ↓
              [Voice Library Save]  name: "narrator"

── later, in another workflow ──

[Model Loader: Base] → [Voice Library Loader]  voice_name: "narrator"
                                ↓ voice_prompt
                        [Voice Clone Generate]  text: "Any line you want"
                                ↓
                          [Audio Saver]

Workflow 3 — Multi-character script

[Model Loader: VoiceDesign]
          ↓
  [Segmented Generate]
    script:
      [voice: gruff old man] I've seen things you wouldn't believe. [/voice]
      [voice: curious young woman] Like what? [/voice]
      [voice: gruff old man, quieter] Things best forgotten. [/voice]
          ↓
    [Audio Saver]

Audio format

All generation nodes output a ComfyUI AUDIO dict:

  • waveform: torch.Tensor shaped [1, 1, samples], float32, range [-1, 1]
  • sample_rate: integer (typically 24000 Hz from Qwen3-TTS)

Compatible with ComfyUI's native PreviewAudio node and any node that accepts AUDIO.


Optional: FlashAttention 2

Reduces VRAM usage on CUDA with bf16/fp16. Install per the Qwen3-TTS README. The nodes detect and use it automatically.


License

MIT — see LICENSE.

Run ComfyUI workflows without the setup

No installs, no CUDA version roulette, no GPU sitting idle on your bill. Bring a workflow and run it in the browser.

Learn more