Clone a voice in 30 seconds.
Synthesise for hours.
Zero-shot voice cloning on Apple Silicon. IndexTTS2 adds native MLX cloning with emotion, tempo, and pause controls; CosyVoice 3 handles transcript-conditioned multilingual cloning; Chatterbox Flash covers the CoreML T3 + S3Gen path. No fine-tuning, no per-character pricing, no audio ever leaving the device.
Which voice is real?
A 30-second blind comparison of a real voice, the same voice cloned locally by Speech Studio on a MacBook, and the same voice cloned by ElevenLabs in the cloud. Speech Studio is the open-source Mac app on top of speech-swift — Apache 2.0, github.com/soniqo/speech-studio.
Where on-device cloning changes the math.
Cloud TTS bills per character and locks the voice on a server. On-device cloning lets you ship apps and creator tools where the voice belongs to your user and the synthesis cost is zero per use.
YouTube voiceovers, course modules, marketing clips — your founder's voice across every episode.
Same voice, nine languages. Cross-lingual cloning keeps the speaker identity even when the words switch.
Let the listener pick their narrator — a celebrity, a parent, a family voice — from a 30-second sample.
Lecturers can record once, then have lessons re-narrated automatically as their text scripts evolve.
One CLI call. One reference clip.
IndexTTS2 uses reference audio directly and exposes emotion, speaking-rate, and pause controls. CosyVoice 3 remains the transcript-conditioned multilingual default when you have the reference transcript.
# IndexTTS2 — native MLX zero-shot cloning
speech speak "Welcome to the demo." \
--engine indextts2 \
--voice-sample ref.wav \
--indextts2-emotion eager \
--indextts2-speaking-rate 1.35 \
--indextts2-max-pause 0.05 \
--output out.wav
# CosyVoice 3 — transcript-conditioned multilingual cloning
speech speak "Welcome to the demo." \
--engine cosyvoice \
--voice-sample ref.wav \
--cosy-reference-transcript "Transcript of ref.wav (its text content)..." \
--output out.wavimport CosyVoiceTTS
import AudioCommon
let model = try await CosyVoiceTTSModel.fromPretrained()
let refAudio = try AudioFileLoader.load(
url: URL(fileURLWithPath: "ref.wav"), targetSampleRate: 16_000)
let cacheDir = try HuggingFaceDownloader.getCacheDirectory(
for: "aufklarer/CosyVoice3-0.5B-MLX-bf16")
let tokenizer = try SpeechTokenizerModel.fromSafetensors(
at: cacheDir.appendingPathComponent("speech_tokenizer.safetensors"))
let profile = try model.extractVoiceProfile(
audio: refAudio, sampleRate: 16_000,
speechTokenizer: tokenizer,
referenceTranscript: "Transcript of the reference clip."
)
let audio = model.synthesize(
text: "Welcome to the demo.",
voiceProfile: profile,
language: "english"
)Five cloning paths, one stack.
IndexTTS2 is the native MLX path for identity-first cloning with emotion and pacing controls. CosyVoice 3 remains the transcript-conditioned multilingual default, Chatterbox Flash is the CoreML route, and Qwen3-TTS ICL is the English/Mandarin fallback.
| Engine | How | Languages | Best for |
|---|---|---|---|
| IndexTTS2 | reference audio + semantic GPT + emotion/style conditioning | batch synthesis | Identity-first local cloning, emotion presets/vectors, speaking-rate and pause control. |
| CosyVoice 3 zero-shot | prompt_token + prompt_feat + transcript | 9 (zh/en/ja/ko/de/es/fr/it/ru) | Default. Highest identity capture, multilingual creative work. |
| Chatterbox Flash CoreML | Flash T3 CoreML + S3Gen CoreML with MLX reference conditioning | 23 upstream / English path validated | CoreML voice-cloning path. Measured RTF 0.59, TTFT 0.27 s with a 512-token audio bucket. |
| Qwen3-TTS ICL | In-context-learning with reference audio | EN, ZH | English-first projects, when you don't need the other 7 languages. |
| CosyVoice 3 (legacy) | 192-d CAM++ speaker embedding only | 9 | Bundles without the speech tokenizer. Material drop in identity match. |
Pick a bundle by runtime path.
IndexTTS2 ships as an expanded fp16 MLX bundle with auxiliary models. CosyVoice 3 provides bf16 and 8-bit bundles when you want the transcript-conditioned multilingual path.
Five rules from the production tests.
- 15–30 s of clean speech. No background music, no overlapping voices, no heavy compression. The reference embeds the speaker — anything else in the clip leaks into the clone.
- 2Always pass the transcript.
--cosy-reference-transcriptgives the LLM the linguistic context for the prompt audio. Skipping it costs accuracy and produces mid-utterance drifts. - 3Long-form text is auto-segmented. The synthesiser splits on sentence boundaries and reuses the same voice profile across segments — voice stays consistent across chapters or full podcasts.
- 4The 8-bit bundle sounds cleaner. Same architecture, lower quantisation noise in the LLM logits — picks more text-aligned speech tokens, drifts less on long output.
- 5Reuse
voiceProfileacross calls.extractVoiceProfile(…)runs the S3 tokenizer + mel extractor + CAM++ once per reference. Reuse the resulting struct across every synthesis call.
Component guides.
Architecture, CLI, Swift API, cloning internals.
CoreML Flash T3 + S3Gen cloning path, CFG, emotion control.
IndexTTS2 + CosyVoice + Qwen3-TTS ICL + CAM++ side by side.
Native MLX zero-shot cloning with emotion, tempo, and pause controls.
12 Hz codec LM, EN / ZH ICL cloning.
48 kHz cloning + ultimate (audio + transcript) cloning, 30 langs.
WeSpeaker / CAM++ — the encoders behind the clones.
