Stage Manager π¬
Stage Manager π¬
- model
- role_A_audio
- role_B_audio
- role_C_audio
- role_D_audio
- role_E_audio
- role_F_audio
- role_G_audio
- audio_mix
- audio_role_A
- audio_role_B
- audio_role_C
- audio_role_D
- audio_role_E
- audio_role_F
- audio_role_G
- srt_content
If you want one voice reading one line, the pack's Custom Voice, Voice Design, and Voice Clone nodes are simpler. Qwen3TTSStageManager is for when you want a scene: a narrator, two characters, a voice in your head, and a coherent timeline - all from one node, with subtitles. It's the flagship of ComfyUI-kaola-Qwen-TTS and the reason the pack's example workflow is literally called qwen3_tts_full_studio. The name is hype; the thing mostly delivers.
The pitch: you feed it a model, a script, and a casting sheet, and it casts roles, generates each line, places everything on a timeline, mixes it, and hands you a full stereo track plus per-role stems and an SRT subtitle file. Without it, the same scene is a rat's nest of individually wired Voice Design and Clone nodes fighting over timing. With it, the graph stays almost flat.
How it works
Under the hood it's a mini director with three jobs.
Casting. Your role_definitions box lists one role per line: Name [A]: description, or just Name: description. The [A]β[G] brackets are explicit slot assignments; leave them off and the node auto-assigns the first free slot. The real trick is that the description is dual-purpose. If the matching audio slot (role_A_audio β¦ role_G_audio) has a wire plugged in - ideally from the pack's Ref Audio node so it carries a transcript - that role becomes clone mode and the description is ignored. No wire? Then the description is used as a voice design prompt: "a deep, husky 50-year-old detective" becomes the instruction that invents the voice. So a single scene can mix an AI-designed king with a cloned recording of you, per role.
Script. Each line is Name: line - Chinese colons οΌ work, and so do inline emotions: Wizard: (Mysterious) The seal is broken. gets merged into that role's design instruction. Lines without a name continue the previous speaker. There's a second, explicit format - 1 00:00:00,000 --> 00:00:01,500 Name: line - for frame-accurate placement; otherwise lines stack on the timeline with my_turn_interval of silence between them. Before generating, it pre-scans the script and hard-fails with a readable list of any role that appears in the script but isn't in role_definitions - that error alone has saved me more debugging than any log line.
Mix. Every generated line is placed on a per-role track buffer at 24 kHz, the role tracks are summed into audio_mix, and each line gets a timestamp. Outputs: audio_mix, audio_role_A through audio_role_G, and srt_content with precise HH:MM:SS,mmm timing.
Inputs worth touching
model- aQWEN3_TTS_MODELfrom the pack's Model Loader. Use the VoiceDesign checkpoint: it does both design and zero-shot cloning. Base also works; the CustomVoice checkpoint is for preset speakers elsewhere, and mismatching model types raises an error.scriptandrole_definitions- the two text boxes above. This is 90% of your actual work.overlap_handling-ignore(let clips overlap),shift_start(push the late one back), ortruncate(cut to fit) when explicit timestamps collide.my_turn_interval- seconds of gap between auto-placed lines; 0.5 is a good default, raise it for ponderous dialogue.save_to_file+filename_prefix- when on, writes_MIX.wavand every role stem into ComfyUI's output folder.temperature,top_p,seed- the usual sampling dials;seedis per-line (seed + line index), so changing it re-rolls everything.
Feed srt_content to the pack's Save File node for a real .srt, and audio_mix to SaveAudio. enable_text_normalization on by default is correct - leave it.
Install and models
cd ComfyUI/custom_nodes
git clone https://github.com/kana112233/ComfyUI-kaola-Qwen-TTS
cd ComfyUI-kaola-Qwen-TTS
pip install -r requirements.txt
Restart ComfyUI, or search ComfyUI-kaola-Qwen-TTS in ComfyUI Manager. The qwen-tts dependency force-pins a transformers version, which can clash with other packs - the usual audio-in-ComfyUI tax. Models auto-download to your HuggingFace cache or live in ComfyUI/models/qwen3_tts/; the 1.7B needs ~4GB+ VRAM, and the 0.6B is the escape hatch on smaller cards. Install flash-attn on NVIDIA if you want faster inference.
Where people get burned
The missing-role error (fix: add the role to role_definitions), and the silent failure where a line that's only [sound effects] or brackets generates nothing - the code literally logs a note that pure-bracket text often produces empty audio. Reference clips under 400 samples throw, so keep your clones to a few seconds. And set expectations on likeness: Qwen3-TTS cloning trails VibeVoice and Chatterbox on raw similarity, per the community, so lean on design for distinctive voices and save cloning for voices you can't describe. For a one-node dialogue scene with subtitles, nothing else in ComfyUI gets you there this fast.
Inputs (22)
| Name | Type | Default | Description |
|---|---|---|---|
| model | QWEN3_TTS_MODEL | β | |
| script | STRING | Narrator: The adventure begins. Hero: Let's go! | β |
| role_definitions | STRING | Narrator [A]: A clear, neutral voice. Hero [B]: A brave, young voice. | β |
| my_turn_interval | FLOAT | 0.50β5 | β |
| overlap_handling | COMBO | ignore | 3 options: ignore, shift_start, truncate |
| top_popt | FLOAT | 1.000β1 | β |
| temperatureopt | FLOAT | 0.700β2 | β |
| repetition_penaltyopt | FLOAT | 1.050β2 | β |
| seedopt | INT | 00β18446744073709550000 | β |
| save_to_fileopt | BOOLEAN | false | β |
| filename_prefixopt | STRING | stage_manager | β |
| role_A_audioopt | AUDIO | β | |
| role_B_audioopt | AUDIO | β | |
| role_C_audioopt | AUDIO | β | |
| role_D_audioopt | AUDIO | β | |
| role_E_audioopt | AUDIO | β | |
| role_F_audioopt | AUDIO | β | |
| role_G_audioopt | AUDIO | β | |
| languageopt | COMBO | Auto | 11 options: Auto, Chinese, English, Japanese, Korean, German, +5 |
| max_new_tokensopt | INT | 20481β8192 | β |
| top_kopt | INT | 501β100 | β |
| enable_text_normalizationopt | BOOLEAN | true | β |
Outputs (9)
| Name | Type | Description |
|---|---|---|
| audio_mix | AUDIO | β |
| audio_role_A | AUDIO | β |
| audio_role_B | AUDIO | β |
| audio_role_C | AUDIO | β |
| audio_role_D | AUDIO | β |
| audio_role_E | AUDIO | β |
| audio_role_F | AUDIO | β |
| audio_role_G | AUDIO | β |
| srt_content | STRING | β |