🧚 Narrator Switcher (Beta test)
Narrator Switcher, beta and honest about it
- sample_audio_narator
- sample_audio_1
- sample_audio_2
- sample_audio_3
- sample_audio_4
- sample_audio_5
- remove_silence
- audio
- text
If F5-TTS-Advance TH is the solo mic, this node is the radio drama. Narrator Switcher takes one multi-line script, splits it into [Speaker]text segments, and voices each one with a different cloned voice - a narrator plus up to five characters - then hands you a single concatenated audio file. It's built for exactly what the name says: fairy tales, audiobooks, Thai dialogue scenes.
And yes, "(Beta test)" is in the display name. This is a wrapper around the pack's own F5TTS_Advance node, and it behaves like a beta: it works, it's clever, and it has rough edges you should know about before you trust it with a 20-minute script.
How it works
Under the hood it isn't a new model - it instantiates F5TTS_Advance and calls its synthesize step once per line of your script, then concatenates the waveforms and returns JSON saying who said what. The flow:
- Every line that starts with
[Name]is parsed for its speaker; the tag is matched case-insensitively (and trailing colons are stripped, so[Narrator:]works too). - A line without a tag falls back to the narrator voice, which makes it a natural default for scene descriptions.
- Each speaker you define needs three inputs: char_name_N, sample_audio_N (their reference clip), and sample_text_N (what that clip says).
- It then runs one full F5-TTS pass per segment and stitches it all together.
The outputs are audio (the full concatenated waveform) and text - a JSON string with a {speaker, text} entry per line, which is genuinely useful if you're syncing subtitles afterward.
The inputs that matter
The required set is small: text (the multiline script), sample_audio_narator + sample_text_narator (the fallback voice), model_path (same VIZINTZOR/F5-TTS-THAI/model/model_1000000.pt default as the rest of the pack), and seed.
Then the character block, repeated five times: char_name_1 / sample_audio_1 / sample_text_1 through _5. A couple of practical notes: only fill in a character slot you actually have a clip for - an empty or unnamed slot is skipped, and any tag that doesn't match a defined character silently falls back to the narrator. And because each speaker gets a full F5-TTS generation, your total runtime scales with the number of lines: a 50-line script is 50 generations. This is not a real-time tool; it's a "let it bake while you get coffee" tool.
All the F5TTS_Advance dials carry over - speed, remove_silence, max_chars, nfe_step, cfg_strength - and they apply to every segment. If one character's pacing is off you're re-rendering the whole script, so get your reference clips right first.
The honest beta checklist
- Quality is per-clip. The narrator's reference voice is what every un-tagged line uses, so a weak narrator clip drags the whole piece down. Five seconds of clean audio per character, ideally in the same recording conditions, makes a bigger difference than any sampler setting.
- Gaps between segments. Each line is generated independently, so pauses between speakers are whatever F5-TTS decided;
cross_fade_duration(default 0.15) is your only glue. - Concatenation is naive. It literally
torch.cats the chunks - no crossfade between them beyond that, and if you setremove_silenceon, each line gets its own trimming. Fine for short dialogue, not a polished mixing console.
Installing and troubleshooting
Same pack, same install - Manager search "F5-TTS-TH" or the manual clone below. The submodule step is the one that bites:
cd ComfyUI/custom_nodes
git clone https://github.com/gordon123/ComfyUI-F5-TTS-TH.git
cd ComfyUI-F5-TTS-TH
git submodule update --init --recursive
pip install -r requirements.txt
If a speaker comes out in the narrator's voice, your tag doesn't match char_name_N exactly - the match is case-insensitive but whitespace-sensitive. If a line comes out garbage, it's the same max_chars/long-text issue as the base node; keep individual utterances under a couple hundred characters. And remember the underlying model's weights are CC-BY-NC-4.0 - non-commercial - so this is for hobby storytelling, not the audiobook you plan to sell.
For a beta, it's surprisingly usable for short multi-voice pieces. Just don't blame it when a 200-line fairy tale takes a while - that's the price of doing zero-shot voice cloning on five different voices in a single node.
Inputs (28)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | — | |
| sample_audio_narator | AUDIO | — | |
| sample_text_narator | STRING | — | |
| model_path | STRING | VIZINTZOR/F5-TTS-THAI/model/model_1000000.pt | — |
| seed | INT | -1 | — |
| char_name_1opt | STRING | Character1 | — |
| sample_audio_1opt | AUDIO | — | |
| sample_text_1opt | STRING | — | |
| char_name_2opt | STRING | Character2 | — |
| sample_audio_2opt | AUDIO | — | |
| sample_text_2opt | STRING | — | |
| char_name_3opt | STRING | Character3 | — |
| sample_audio_3opt | AUDIO | — | |
| sample_text_3opt | STRING | — | |
| char_name_4opt | STRING | Character4 | — |
| sample_audio_4opt | AUDIO | — | |
| sample_text_4opt | STRING | — | |
| char_name_5opt | STRING | Character5 | — |
| sample_audio_5opt | AUDIO | — | |
| sample_text_5opt | STRING | — | |
| remove_silenceopt | BOOL | true | — |
| speedopt | FLOAT | 1.00.1–5 | — |
| cross_fade_durationopt | FLOAT | 0.150–1 | — |
| nfe_stepopt | INT | 321–128 | — |
| cfg_strengthopt | FLOAT | 2.00–10 | — |
| sway_sampling_coefopt | FLOAT | -1.0-5–5 | — |
| fix_durationopt | FLOAT | 0.00–30 | — |
| max_charsopt | INT | 2501–1000 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| audio | AUDIO | — |
| text | STRING | — |