Qwen TTS Multi Speaker Node
Write a script, tag the speakers, get a finished voiceover with music
- speaker_prompts
- model
- background_music
- AUDIO
If you've been piecing together multi-character TTS by generating each line separately and stitching audio files in an editor, this node is the thing that replaces that whole chore. You paste a script with [speaker] tags, connect a dict of voices, and it renders the entire dialogue as one audio file - with per-line gaps, per-line volume, and optional background music with ducking. It's a tiny "audiobook mixer" hiding inside a node pack.
The workflow to get here: build voices with the Voice Clone Prompt node, save them, load them back through a Speaker Bank (which outputs a DICT mapping names → voice prompts), then connect that dict here. The multi-speaker node then walks your script line by line.
The dialogue format
dialogue_text is a multiline script. Every block starts with a tag line, then the spoken lines follow:
[Narrator]It was a cold morning in the valley.
[Alice,400,1.0,overlap]I hate the cold.
[Bob,600,0.8]Well, at least it's quiet.
The comma parts after the name are optional and in this order:
- gap in ms - silence before this character speaks (second value).
- volume - 0.8 is quieter, 1.5 louder (third value).
- mode -
overlap(default) lets the previous line's tail bleed into this one instead of hard-cutting. There's a crossfade path in the code for smooth transitions between speakers.
Speaker names must match the keys in the speaker_prompts dict. A typo raises a clear "Speaker 'x' not found" error rather than silently dropping the line.
The inputs that matter
- model - the
base_modelfromQwenTTSModelDownloader(this is the plain TTS model, not the clone or design one). - speaker_prompts - the DICT from a Speaker Bank.
- dialogue_text - your script, above.
- language - per-model language choice; Auto usually does fine for mixed content.
The audio-post section is where this node punches above its weight:
- background_music - optional AUDIO that plays under the dialogue.
- music_volume, music_loop, music_trim - master music level, loop the track to cover long dialogue, and trim it to the final speech length.
- ducking - the music automatically dips while someone talks and swells between lines.
ducking_strength(0.05–0.9) is how much it attenuates during speech - the tooltip says it's relative to the current music volume.ducking_fade_mssmooths the transitions so it doesn't pump. - soft_limiter - a gentle tanh limiter that catches clipping when several speakers and music stack. If your mix sounds like it's peaking, flip it on instead of hand-fixing levels.
- The usual sampling dials (temperature, top_p, top_k, repetition_penalty,
max_new_tokens_per_line, seed) apply per line.
Output is a single AUDIO object. Save it with any audio saver and your voiceover is done.
Install
Part of Vantage-Nodes:
cd ComfyUI/custom_nodes
git clone https://github.com/vantagewithai/Vantage-Nodes.git
pip install -r requirements.txt
or ComfyUI Manager → search "Vantage-Nodes" → Install → restart. Download the Qwen3 TTS models with QwenTTSModelDownloader first.
Common issues
- "Speaker 'x' not found" - the dict key and script tag don't match, or the voice was never saved/loaded. Case-insensitive matching helps, but exact names are safer.
- Music swallows the dialogue - you left ducking off and music_volume at 0.4. Turn on ducking, or drop music_volume.
- Long scripts run very long - this generates and mixes line by line. Budget real time for a 2-minute script. It does use a progress bar, so you're not staring at a frozen screen.
Inputs (23)
| Name | Type | Default | Description |
|---|---|---|---|
| dialogue_text | STRING | — | |
| speaker_prompts | DICT | — | |
| model | QWEN_TTS_MODEL | — | |
| device | COMBO | inherit | 5 options: inherit, auto, cuda, mps, cpu |
| attention | COMBO | inherit | 6 options: inherit, auto, sage_attn, flash_attn, sdpa, eager |
| language | COMBO | Auto | 11 options: Auto, Chinese, English, Japanese, Korean, French, +5 |
| background_musicopt | AUDIO | — | |
| music_volumeopt | FLOAT | 0.400–2 | — |
| music_loopopt | BOOLEAN | true | — |
| music_trimopt | BOOLEAN | true | — |
| music_fade_in_msopt | INT | 5000–10000 | — |
| music_fade_out_msopt | INT | 5000–10000 | — |
| duckingopt | BOOLEAN | false | — |
| ducking_strengthopt | FLOAT | 0.250.05–0.9 | Music attenuation factor during speech (relative to current music volume) |
| ducking_fade_msopt | INT | 2000–2000 | — |
| seedopt | INT | 0 | — |
| max_new_tokens_per_lineopt | INT | 2048 | — |
| top_popt | FLOAT | 0.80 | — |
| top_kopt | INT | 20 | — |
| temperatureopt | FLOAT | 1.00 | — |
| repetition_penaltyopt | FLOAT | 1.05 | — |
| soft_limiteropt | BOOLEAN | false | — |
| unload_model_after_generateopt | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| AUDIO | AUDIO | — |