Voices & speed
The voice set
The Kokoro INT8 kit ships 103 voices. Every voice has an id, an index into voices.bin, a language, and a label:
| Prefix | Language | Example ids |
|---|---|---|
zf_ | Chinese, female | zf_001, zf_002, … |
zm_ | Chinese, male | zm_009, … |
af_ | English (American), female | af_maple, af_sol |
bf_ | English (British), female | bf_vale |
Voice entries follow the KokoroVoiceManifest shape:
interface KokoroVoiceManifest {
id: string; // "zf_001"
index: number; // position in voices.bin
language: "en" | "zh";
label: string; // human-readable label
}Only Recommended voices are certified
Voices are marked recommended or experimental in the model manifest. Only recommended voices have passed the Beta corpus. The certified set is zf_001, zm_009, af_maple, af_sol, and bf_vale — everything else is Experimental. Chinese prosody and punctuation pauses vary noticeably between voices, so evaluate any other voice on your own content before shipping it.
Switching voices
Pass voiceId per request:
const tts = createTts({
model: kokoroZhInt8,
voiceId: "zf_001",
numThreads: 4,
});
await tts.load();
const chinese = await tts.synthesizeToFile({ text: "你好。" });
const english = await tts.synthesizeToFile({
text: "Hello.",
voiceId: "af_maple",
});Changing the voice does not reload the model. The ONNX session is created once; a different voiceId just selects a different style embedding from voices.bin for that synthesis. Switching is cheap.
To change the default, set it on the client and keep using one voice:
const tts = createTts({ model: kokoroZhInt8, voiceId: "af_maple" });Speed
speed is a multiplier on the generated audio, valid from 0.5 to 2.0:
await tts.synthesizeToFile({ text: "慢一点。", speed: 0.8 });
await tts.synthesizeToFile({ text: "Faster now.", speed: 1.4 });Values outside the range are rejected before inference runs.
Speed is a hard range, not a hint
0.5 and 2.0 are the extremes. Beyond them the SDK throws rather than clamping silently, so validate any user-facing speed control yourself.
Tuning threads
numThreads maps to the ONNX Runtime intra-op thread count:
const tts = createTts({
model: kokoroZhInt8,
voiceId: "zf_001",
numThreads: 4,
});More threads is not automatically better — on mobile, oversubscribing cores can cost more than it gains. Benchmark on your target hardware with result.elapsedMs (which excludes model load) and pick the best value.
Text length limits
| Limit | Value |
|---|---|
| Whole input | 2,000 Unicode code points |
| Single candidate segment | 300 code points |
| Model token budget | 510 tokens (508 payload) |
The SDK splits long text into segments and concatenates the resulting audio. Exceeding the whole-input limit throws TEXT_TOO_LONG; a segment that cannot be split below the cap throws TEXT_SEGMENT_TOO_LONG.
Chinese numbers and dates are normalized automatically before encoding — 2024年5月1日 is read as Chinese numerals, not digits.