VoxCPM2 voice cloning on Mac

Run VoxCPM2 locally on Apple Silicon with MLX to clone a voice or design one from a text description. This OpenBMB model produces 48 kHz speech in 30 languages. Listen to the examples, then try the CLI with the reference recording and its transcript.

Audio samples · Clone a voice with the CLI · VoxCPM2 vs Qwen3-TTS

Voice cloning samples

These English clips come from the published FLEURS comparison. The reference and generated speech use different sentences. Each output is one representative sample; the comparison metrics average multiple clips.

Reference audioEnglish · 16 kHz

Reference transcript: One can only wonder what the keyboard will become when something newer comes along.

VoxCPM2 bf16English · 48 kHz

Generated text: While he was working at the hospital Liggins began to investigate premature labor during his spare time.

Qwen3-TTS Base 1.7B bf16 ICLEnglish · 24 kHz

Generated text: While he was working at the hospital Liggins began to investigate premature labor during his spare time.

Clone a voice with the CLI

Download Reference audio as reference.wav. The command uses its exact transcript; replace both the recording and transcript when using your own voice sample.

speech speak "Hello from the cloned voice." \
    --engine voxcpm2 \
    --voxcpm2-variant bf16 \
    --voice-sample reference.wav \
    --voxcpm2-prompt-audio reference.wav \
    --voxcpm2-prompt-text "One can only wonder what the keyboard will become when something newer comes along." \
    --seed 42 \
    --output clone.wav

What it is

Architecture

Five cooperating components produce a 48 kHz waveform:

ComponentDescription
MiniCPM-4 base LM28-layer MiniCPM-4 with LongRoPE, GQA (16 Q / 2 KV heads, 128 head dim), and SwiGLU MLP. Conditions on text tokens + audio latents.
Residual LM8-layer MiniCPM-4 variant without rotary embeddings. Refines the base LM hidden state per generated audio patch.
FSQ + Local DiT estimatorScalar-quantised hidden states drive a 12-layer Diffusion Transformer (V2) operating on 64-dim audio latents in patches of 4. CFG-zero-star Euler solver, 10 timesteps default.
AudioVAE V2Causal convolutional decoder. Reads 16 kHz reference audio + emits 48 kHz waveform (3× upsample baked in).
Stop headPer-step binary classifier on the LM hidden state. Argmax = 1 ends generation after minTokens patches.

Bundles

The current CLI supports bf16 and int8 bundles converted from the upstream openbmb/VoxCPM2 checkpoint. Quantization applies to the language-model and diffusion projections; the audio decoder stays at full precision.

BundleQuantisationSizeHuggingFace
bf16None (reference)~5.0 GBaufklarer/VoxCPM2-MLX-bf16
int8MLX QuantizedLinear, group size 64~3.0 GBaufklarer/VoxCPM2-MLX-int8

Round-trip ASR (Qwen3-ASR 0.6B, 8-sentence harness, M-series Apple Silicon):

VariantWERRTF
bf162.04 %1.38
int80.00 %1.02
int4 (retired)4.08 %0.83

The CLI defaults to bf16; choose int8 for a smaller download. int4 is retired and appears in the table only as a historical measurement.

Quick start

import VoxCPM2TTS

let tts = try await VoxCPM2TTSModel.fromPretrained()  // defaults to bf16
let audio = try await tts.generate(text: "Hello from VoxCPM2.", language: "english")
// audio: [Float] at 48 kHz mono

Select the int8 bundle explicitly:

let tts = try await VoxCPM2TTSModel.fromPretrained(
    modelId: "aufklarer/VoxCPM2-MLX-int8"
)

Voice design (instruction-driven)

Pass a natural-language style description; the model conditions synthesis on it without a reference audio sample:

let audio = try await tts.generateVoxCPM2(
    text: "Welcome to the show.",
    instruct: "A young woman, gentle and warm voice."
)

Voice cloning

Single-reference cloning from a 16 kHz mono clip:

let ref = try AudioFileLoader.load(url: URL(fileURLWithPath: "speaker.wav"),
                                   targetSampleRate: 16000)
let audio = try await tts.generateVoxCPM2(
    text: "This is a cloned voice.",
    refAudio: ref
)

Ultimate cloning — pass both reference audio and the matching transcript so the LM can also condition on the lexical context, preserving prosody and accent more faithfully:

let audio = try await tts.generateVoxCPM2(
    text: "Hello from the cloned voice.",
    refAudio: ref,
    promptText: "this is what the reference clip actually said",
    promptAudio: ref
)

CLI

speech speak "Hello there." \
    --engine voxcpm2 \
    --voxcpm2-variant int8 \
    --output hello.wav

# Voice design
speech speak "Welcome to the show." \
    --engine voxcpm2 \
    --voxcpm2-instruct "A young woman, gentle and warm voice." \
    --output design.wav

# Voice cloning
speech speak "This is a cloned voice." \
    --engine voxcpm2 \
    --voice-sample speaker.wav \
    --output clone.wav

Flags: --voxcpm2-variant {bf16,int8}, --voxcpm2-instruct, --voxcpm2-ref-audio, --voxcpm2-prompt-audio + --voxcpm2-prompt-text, --voxcpm2-cfg-value, --voxcpm2-timesteps, --voxcpm2-max-tokens, --voxcpm2-min-tokens, --seed for reproducible synthesis.

VoxCPM2 vs Qwen3-TTS

Published English results for ten FLEURS reference/target pairs per model: mean WER and UTMOS, median RTF. Lower WER and RTF are better; UTMOS predicts naturalness and is not a human rating. These results do not establish a universal ranking.

ModelWER ↓RTF ↓UTMOS ↑
VoxCPM2 bf161.8%1.112.97
Qwen3-TTS Base 1.7B bf16 ICL2.4%1.703.50

Full five-language voice-cloning comparison and methodology.

Picking among speech-swift TTS modules

Kokoro-82MQwen3-TTSCosyVoice3VoxCPM2VibeVoice 1.5B
Params82M0.6 / 1.7 B0.5B2B1.5B
Sample rate24 kHz24 kHz24 kHz48 kHz24 kHz
BackendCoreML (ANE)MLX, CoreMLMLXMLXMLX
Languages1010930EN + ZH
Voice designFixed presets——Instruction-driven—
Voice cloning—ICL referenceZero-shot referenceReference + ultimateRaw audio + transcript
Long-formShort/mediumStreamingStreamingStreaming patchesUp to 90 min
Pick VoxCPM2 when…

…you need 48 kHz output (music / broadcast applications) or natural-language voice design without a reference clip. For maximum-quality short-form English TTS with smaller download, CosyVoice3 or Qwen3-TTS are lighter. For long-form podcast / audiobook in EN/ZH, VibeVoice 1.5B is purpose-built.

Responsible use

Voice cloning is included. Obtain consent for any voice you clone and don't use the model to impersonate individuals, generate disinformation, or commit fraud. The full safety guidance from openbmb/VoxCPM2 applies.

Local native inference

VoxCPM2 supports weightPrecision: .float16 for an unquantized checkpoint. Its main parameters use FP16; AudioVAE and some computation remain FP32. INT8 checkpoints are rejected for this mode.

Explicit tokenizerDirectory loading uses staged tokenizer files without modifying them or needing a separate cache. Incremental speech decodes bounded causal windows while retaining the AudioVAE left context.

Speech with stream: true returns NDJSON audio events at 48 kHz, followed by done or error. Cancel by requestID at /v1/inference/cancel. GET /v1/inference/capabilities and /v1/inference/provenance report model identities, parameter dtypes, asset pins, and memory counters.

API details