Nodes/ZONOS2 TTS (Emotion)/ZONOS2 Voice Clone (Emotion)
ComfyUI Node

ZONOS2 Voice Clone (Emotion)

The Emotion Dials Nobody Else Has

By shiwano·Created about a month ago·Updated 27 days ago· 0
ZONOS2 Voice Clone (Emotion)
  • zonos2_model
  • reference_audio
  • audio
textHello! This is ZONOS2 running natively inside ComfyUI.
clean_speaker_backgroundfalse
accurate_modetrue
max_new_tokens1024
temperature1.15
top_k106
top_p0.00
min_p0.18
repetition_window50
repetition_penalty1.20
repetition_codebooks8
speaking_ratedefault
loudness_lufsdefault
estimated_snrdefault
maximum_pausedefault
estimated_bandlimit_hzdefault
leading_silencedefault
trailing_silence3: 0.25-0.5
seed0
emotionnone
emotion_strength1.00
emotion_valence0.00
emotion_arousal0.00
emotion_cfg_scale1.00

The whole reason this fork exists is in the node name. Upstream ZONOS2 already does zero-shot voice cloning in ComfyUI - you hand it 5–30 seconds of someone talking and it writes new lines in their voice. shiwano's "Emotion" fork adds the thing ZONOS2's own research shipped but the original ComfyUI port ignored: emotion directions you can actually dial. That makes ZONOS2 Voice Clone (Emotion) the node people install this pack for.

How it works

Mechanically it's ZONOS2's audio-only cloning path, and it's a good one. Your reference_audio noodle goes through an ECAPA-TDNN speaker encoder that distills the clip down to a single 2048-dimensional speaker embedding. No reference transcript needed, ever - that's the "audio-only" part. The model conditions on that fixed embedding rather than the waveform, which is great for identity transfer and the reason accent and cadence are a separate question (more on that below). The emotion bit: after the model projects the speaker vector into hidden space, the node adds an official emotion direction vector shipped in the pack's emotion_directions/ folder. Identity stays intact; only delivery shifts.

The inputs

Inputs, from the top. zonos2_model from the loader, text to speak, and reference_audio (required - load a file with a Load Audio node first). Then clean_speaker_background (default false): this is a flag describing the recording, not a denoiser. Leave it off for anything with room tone, noise, or reverb; enable it only for genuinely clean studio speech. accurate_mode (default true) adds ZONOS2's accurate-cloning token for stricter identity adherence; disable it for looser, more expressive takes - and the emotion controls play best with it off.

Then the emotion bank, the reason you're here:

  • emotion - none, happy, sad, angry, surprised.
  • emotion_strength - 0–3, default 1.0. One is already "the calibrated amount," because the pack folds ZONOS2's internal per-emotion strengths into the weights. Push past ~1.5 and the voice starts to distort.
  • emotion_valence and emotion_arousal - continuous -1 to 1 affect axes mixed alongside the chosen emotion. Negative valence is unpleasant, negative arousal is calm.
  • emotion_cfg_scale - 1–3, default 1.0 (off). Above 1 the node also generates an unguided twin and amplifies the difference: stronger emotion at roughly double generation time. Upstream's suggested starting point is 1.5, used with accurate_mode off.

Everything else is the shared ZONOS2 control surface - max_new_tokens, temperature/top_k/min_p, seed, and the seven conditioning buckets, identical to the Voice Generation node.

The accent trap

Where people get burned is expectation-setting, not setup. The speaker embedding captures identity far more reliably than accent or prosody, so the classic complaint - "the voice matches but the accent doesn't" - is a model limitation, not a bug in the node. The README says it straight: use a reference that clearly demonstrates the accent you want, ideally in the target language, and try several seeds. Keep references in the 5–30 s sweet spot, single speaker, minimal music and reverb; anything over 60 s gets clipped to the first minute with a CLI warning.

Installing

Install is the same pack as the other two nodes:

cd ComfyUI/custom_nodes
git clone https://github.com/shiwano/zonos2-tts-comfyui-emotion.git
../venv/bin/python zonos2-tts-comfyui-emotion/install.py

Or ComfyUI Manager → search "ZONOS2 TTS (Emotion)", then restart. Same Transformers 5.0–5.12 requirement, same first-run model download. One memory note: emotion_cfg_scale above 1 adds a batch row for the unguided twin - about 65 MiB of KV cache at the default token count. Minor, but it's why the node reads slower in guidance mode.

Heads-up for anyone with saved upstream workflows: this fork renames every node to the Zonos2Emotion* keys with "(Emotion)" suffixes, so old graphs won't auto-map. It's a two-minute rebuild, but rebuild you must.

If your project needs a voice that sounds genuinely happy, furious, or devastated, this is the local option that actually has the dial. Just clone someone you're allowed to clone.

CategoryZONOS2 TTS (Emotion)

Inputs (26)

NameTypeDefaultDescription
zonos2_modelZONOS2_MODELConnect the zonos2_model output from ZONOS2 Model Loader.
textSTRINGHello! This is ZONOS2 running natively inside ComfyUI.UTF-8 text to synthesize.
reference_audioAUDIOReference voice AUDIO noodle. 5-30 seconds of clear, single-speaker speech is recommended. Use a sample that clearly demonstrates the accent you want, with little silence, music, or reverb. Audio longer than 60 seconds is clipped to the first 60 seconds with a CLI warning.
clean_speaker_backgroundBOOLEANfalseOfficial ZONOS2 clean/noisy conditioning flag. Leave disabled for ordinary recordings or any audible room tone, noise, reverb, or ambience. Enable only for genuinely clean studio-like speech.
accurate_modeBOOLEANtrueEnable the official ZONOS2 accurate-cloning token for stricter speaker-embedding adherence. It can improve identity matching, but it does not guarantee transfer of accent, cadence, emotion, or other prosody. Disable for looser, potentially more expressive conditioning.
max_new_tokensINT102432–6000Maximum DAC-code frames the model may generate. More frames allow longer speech but increase generation time and KV-cache memory. Generation can stop earlier when ZONOS2 emits end-of-audio.
temperatureFLOAT1.150–2Sampling randomness. Lower values are steadier; higher values add variation but can reduce clarity. 0 uses greedy sampling. The official ZONOS2 default is 1.15.
top_kINT1060–1026Keep only the K most likely tokens in each audio codebook before sampling. 0 disables Top-K filtering. The official default is 106.
top_pFLOAT0.000–1Keep the smallest token set whose combined probability reaches this value. 0 disables Top-P filtering. ZONOS2 normally uses Min-P instead.
min_pFLOAT0.180–1Remove tokens whose probability is below this fraction of the most likely token. 0 disables Min-P. The official default is 0.18.
repetition_windowINT500–512Number of recent generated frames checked for repeated audio tokens. 0 disables repetition tracking.
repetition_penaltyFLOAT1.201–2Reduces the probability of recently generated tokens to discourage loops. 1.0 disables the penalty. The official default is 1.2.
repetition_codebooksINT8-1–9Apply repetition penalty to this many codebooks starting from codebook 0. -1 applies it to all 9; 0 disables it for every codebook. The official default is 8.
speaking_rateCOMBOdefaultOptional ZONOS2 speaking-rate conditioning in cleaned UTF-8 bytes per second. Lower ranges generally produce slower speech. Default leaves speaking rate unconditioned.
loudness_lufsCOMBOdefaultOptional target integrated loudness in LUFS. More-negative ranges are quieter; less-negative ranges are louder. Default leaves loudness unconditioned.
estimated_snrCOMBOdefaultOptional estimated signal-to-noise ratio in dB. Higher ranges bias toward cleaner audio; lower ranges can reproduce noisier recording characteristics. Default leaves SNR unconditioned.
maximum_pauseCOMBOdefaultOptional maximum internal pause duration in seconds. Lower ranges favor tighter delivery; higher ranges permit longer pauses. Default leaves maximum pause unconditioned.
estimated_bandlimit_hzCOMBOdefaultOptional estimated recording bandlimit in Hz. Higher ranges bias toward wider-band, brighter audio; lower ranges can sound more bandwidth-limited. Default leaves bandlimit unconditioned.
leading_silenceCOMBOdefaultOptional amount of silence before speech begins. Default leaves leading silence unconditioned.
trailing_silenceCOMBO3: 0.25-0.5Requested silence after speech ends. Bucket 3 (0.25-0.5 seconds) is the official ZONOS2 default. Select default to leave it unconditioned.
seedINT00–9223372036854776000Sampling seed. A positive value makes generation repeatable for identical inputs and settings. 0 uses the current random state.
emotionCOMBOnoneOfficial ZONOS2 emotion direction added to the speaker vector after the model projects it. Speaker identity is preserved and only delivery shifts. Select none to leave conditioning untouched, which reproduces the output of a build without emotion support.
emotion_strengthFLOAT1.000–3Multiplier on top of the strengths ZONOS2 calibrated for each direction (3.0 for most, 4.0 for surprised), so 1.0 already gives the intended amount. Raise it for a stronger reading; large values distort the voice. 0 disables emotion.
emotion_valenceFLOAT0.00-1–1Continuous affect axis mixed in alongside the selected emotion. Negative is unpleasant, positive is pleasant, 0 leaves the axis unused.
emotion_arousalFLOAT0.00-1–1Continuous affect axis mixed in alongside the selected emotion. Negative is calm, positive is excited, 0 leaves the axis unused.
emotion_cfg_scaleFLOAT1.001–3Official ZONOS2 emotion classifier-free guidance. 1.0 disables it. Above 1.0 the model also generates an unguided twin and amplifies the difference, which strengthens the emotion at roughly double the generation time. Upstream recommends 1.5 with accurate_mode disabled.

Outputs (1)

NameTypeDescription
audioAUDIOVoice-cloned mono speech as native ComfyUI AUDIO at 44.1 kHz.