Text-to-Speech

The MediaPipe Text-to-Speech task lets you synthesize natural-sounding speech audio from text directly on-device using open-weight neural text-to-speech models (Kokoro-82M, PocketTTS 100M, or Phonon 31M), each packaged in a single .litertlm bundle. The task operates as a headless PCM audio generator, returning normalized 24 kHz mono 32-bit floating-point (float32) audio samples that your application can play through platform audio APIs, save as WAV files, or pass to downstream audio pipelines.

Quickstart

Install the SDK for your platform, initialize the task with a model, and synthesize full clips or streaming audio chunks.

Web

npmnpm install @mediapipe/tasks-audioWeb demo·Edit in StackBlitz·Setup guide

Full clip

Full clipComplete 24 kHz audioSynthesizes the full prompt and returns one concatenated 24 kHz PCM waveform.
import { FilesetResolver, TextToSpeech } from "@mediapipe/tasks-audio";

const audio = await FilesetResolver.forAudioTasks(
  "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-audio@latest/wasm"
);
// Use Kokoro-82M ("kokoro_int8_gpu_fp16.litertlm", delegate: "GPU") or Phonon 31M ("phonon_int8.litertlm", ~87 MB CPU).
const tts = await TextToSpeech.createFromOptions(audio, {
  baseOptions: {
    modelAssetPath: "kokoro_int8_gpu_fp16.litertlm",
    delegate: "GPU",
  },
  defaultVoiceId: "af_heart",
  cacheDirectory: ":nocache",
});

// Synthesize a 24 kHz mono clip
const audioResult = await tts.synthesize("Hello from MediaPipe Text to Speech in the browser!");
enqueuePcmPlayback(audioResult.samples, audioResult.sampleRateHz);

Audio stream

Clause streamLow-latency chunksStreams each synthesized clause chunk as soon as it is vocoded so playback starts immediately.
import { FilesetResolver, TextToSpeech } from "@mediapipe/tasks-audio";

const audio = await FilesetResolver.forAudioTasks(
  "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-audio@latest/wasm"
);
const tts = await TextToSpeech.createFromOptions(audio, {
  baseOptions: {
    modelAssetPath: "kokoro_int8_gpu_fp16.litertlm",
    delegate: "GPU",
  },
  defaultVoiceId: "af_heart",
  cacheDirectory: ":nocache",
});

// Clause-by-clause streaming (or pass finishInput = false and call stream.pushText(delta)
// + stream.finishInput() to pipe live LLM tokens into speech)
const stream = await tts.synthesizeStream(
  "First sentence plays right away. Second sentence vocodes while the first plays."
);
for await (const chunk of stream) {
  enqueuePcmPlayback(chunk.samples, chunk.sampleRateHz);
}

Android (Kotlin)

Gradleimplementation("com.google.mediapipe:tasks-audio:latest.release")Sample code·Setup guide

Full clip

Full clipComplete 24 kHz audioSynthesizes the full prompt and returns one concatenated 24 kHz PCM waveform.
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeech
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeechOptions
import com.google.mediapipe.tasks.core.BaseOptions
import com.google.mediapipe.tasks.core.Delegate

val options = TextToSpeechOptions(
    baseOptions = BaseOptions.builder()
        .setModelAssetPath("${context.filesDir}/kokoro_int8_gpu_fp16.litertlm")
        .setDelegate(Delegate.GPU)
        .build(),
    defaultVoiceId = "af_heart",
    cacheDirectory = context.cacheDir.absolutePath,
)
val tts = TextToSpeech.create(options)

// Suspending unary call: returns one complete 24 kHz AudioResult.
// Call it from a coroutine (for example, lifecycleScope.launch { speak(...) }).
suspend fun speak(text: String) {
    val audioResult = tts.synthesizeAsync(text)
    audioTrackPlayer.write(audioResult.samples, audioResult.sampleRateHz)
}

Audio stream

Clause streamLow-latency chunksStreams each synthesized clause chunk as soon as it is vocoded so playback starts immediately.
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeech
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeechOptions
import com.google.mediapipe.tasks.core.BaseOptions
import com.google.mediapipe.tasks.core.Delegate

val options = TextToSpeechOptions(
    baseOptions = BaseOptions.builder()
        .setModelAssetPath("${context.filesDir}/kokoro_int8_gpu_fp16.litertlm")
        .setDelegate(Delegate.GPU)
        .build(),
    defaultVoiceId = "af_heart",
    cacheDirectory = context.cacheDir.absolutePath,
)
val tts = TextToSpeech.create(options)

// Clause-by-clause Flow<AudioChunk>: playback starts after the first clause
// (or call tts.openStream() -> stream.pushText(delta) -> stream.finishInput() for live LLM tokens).
suspend fun speakStreaming(text: String) {
    tts.synthesizeStream(text).collect { chunk ->
        audioTrackPlayer.write(chunk.samples, chunk.sampleRateHz)
    }
}

Android (Java)

Gradleimplementation 'com.google.mediapipe:tasks-audio:latest.release'Sample code·Setup guide

Full clip

Full clipComplete 24 kHz audioSynthesizes the full prompt and returns one concatenated 24 kHz PCM waveform.
import com.google.mediapipe.tasks.audio.texttospeech.AudioResult;
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeech;
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeechOptions;
import com.google.mediapipe.tasks.core.BaseOptions;
import com.google.mediapipe.tasks.core.Delegate;

BaseOptions baseOptions = BaseOptions.builder()
    .setModelAssetPath(context.getFilesDir() + "/kokoro_int8_gpu_fp16.litertlm")
    .setDelegate(Delegate.GPU)
    .build();
TextToSpeechOptions options = new TextToSpeechOptions(
    baseOptions, "af_heart", null, 1.0f, 64, context.getCacheDir().getAbsolutePath()
);
TextToSpeech tts = TextToSpeech.create(options);

// Synchronous unary call on a worker thread: returns complete 24 kHz AudioResult
AudioResult audioResult = tts.synthesize("Hello from MediaPipe Text to Speech on Android!");

Audio stream

Clause streamLow-latency chunksStreams each synthesized clause chunk as soon as it is vocoded so playback starts immediately.
import com.google.mediapipe.tasks.audio.texttospeech.AudioChunk;
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeech;
import com.google.mediapipe.tasks.audio.texttospeech.TextToSpeechOptions;
import com.google.mediapipe.tasks.audio.texttospeech.TtsStream;
import com.google.mediapipe.tasks.core.BaseOptions;
import com.google.mediapipe.tasks.core.Delegate;

BaseOptions baseOptions = BaseOptions.builder()
    .setModelAssetPath(context.getFilesDir() + "/kokoro_int8_gpu_fp16.litertlm")
    .setDelegate(Delegate.GPU)
    .build();
TextToSpeechOptions options = new TextToSpeechOptions(
    baseOptions, "af_heart", null, 1.0f, 64, context.getCacheDir().getAbsolutePath()
);
TextToSpeech tts = TextToSpeech.create(options);

// Pull-based streaming using TtsStream: play each clause chunk as soon as ready
try (TtsStream stream = tts.openStream(
    "First sentence plays right away. Second sentence follows seamlessly.",
    null,
    /* finishInput= */ true
)) {
    AudioChunk chunk;
    while ((chunk = stream.readNext()) != null) {
        audioTrackPlayer.write(chunk.getSamples(), chunk.getSampleRateHz());
    }
}

iOS

SwiftPMhttps://github.com/google-ai-edge/mediapipe → MediaPipeTasksAudioPackage.swift·Sample code·Setup guide

Full clip

Full clipComplete 24 kHz audioSynthesizes the full prompt and returns one concatenated 24 kHz PCM waveform.
import Foundation
import MediaPipeTasksAudio

guard let modelPath = Bundle.main.path(forResource: "kokoro_int8_gpu_fp16", ofType: "litertlm") else { return }
let cacheDir = FileManager.default.temporaryDirectory.appendingPathComponent("mediapipe_tts_cache").path

let options = TextToSpeechOptions(
    baseOptions: TTSBaseOptions(modelAssetPath: modelPath, delegate: .gpu),
    defaultVoiceId: "af_heart",
    cacheDirectory: cacheDir
)
let tts = try TextToSpeech(options: options)

// Non-blocking unary call: returns one concatenated 24 kHz AudioResult
let audioResult = try await tts.synthesizeAsync("Hello from MediaPipe Text to Speech on Apple platforms!")

Audio stream

Clause streamLow-latency chunksStreams each synthesized clause chunk as soon as it is vocoded so playback starts immediately.
import Foundation
import MediaPipeTasksAudio

guard let modelPath = Bundle.main.path(forResource: "kokoro_int8_gpu_fp16", ofType: "litertlm") else { return }
let cacheDir = FileManager.default.temporaryDirectory.appendingPathComponent("mediapipe_tts_cache").path

let options = TextToSpeechOptions(
    baseOptions: TTSBaseOptions(modelAssetPath: modelPath, delegate: .gpu),
    defaultVoiceId: "af_heart",
    cacheDirectory: cacheDir
)
let tts = try TextToSpeech(options: options)

// AsyncThrowingStream<AudioChunk, Error>: play each clause as soon as vocoded
for try await chunk in tts.synthesizeStream(
    "First sentence plays right away. Second sentence streams seamlessly."
) {
    audioPlayer.scheduleSamples(chunk.samples, sampleRate: chunk.sampleRateHz)
}

Python

pippip install mediapipe numpySample code·Setup guide

Full clip

Full clipComplete 24 kHz audioSynthesizes the full prompt and returns one concatenated 24 kHz PCM waveform.
import os
import tempfile
import mediapipe as mp

BaseOptions = mp.tasks.BaseOptions
TextToSpeech = mp.tasks.audio.TextToSpeech
TextToSpeechOptions = mp.tasks.audio.TextToSpeechOptions

options = TextToSpeechOptions(
    base_options=BaseOptions(
        model_asset_path="kokoro_int8_gpu_fp16.litertlm",
        delegate=BaseOptions.Delegate.GPU,
    ),
    default_voice_id="af_heart",
    cache_directory=os.path.join(tempfile.gettempdir(), "mediapipe_tts_cache"),
)

with TextToSpeech.create_from_options(options) as tts:
    result = tts.synthesize("Hello from MediaPipe Text to Speech!")

Audio stream

Clause streamLow-latency chunksStreams each synthesized clause chunk as soon as it is vocoded so playback starts immediately.
import os
import tempfile
import mediapipe as mp

BaseOptions = mp.tasks.BaseOptions
TextToSpeech = mp.tasks.audio.TextToSpeech
TextToSpeechOptions = mp.tasks.audio.TextToSpeechOptions

options = TextToSpeechOptions(
    base_options=BaseOptions(
        model_asset_path="kokoro_int8_gpu_fp16.litertlm",
        delegate=BaseOptions.Delegate.GPU,
    ),
    default_voice_id="af_heart",
    cache_directory=os.path.join(tempfile.gettempdir(), "mediapipe_tts_cache"),
)

with TextToSpeech.create_from_options(options) as tts:
    # Or use tts.start_stream() -> stream.push_text(delta) -> stream.finish_input() for LLM tokens
    for chunk in tts.synthesize_stream(
        "First sentence plays right away. Subsequent clauses synthesize in the background."
    ):
        play(chunk.samples, chunk.sample_rate_hz)

Task details

This section describes the capabilities, inputs, outputs, and configuration options of this task.

Features

  • Single-file .litertlm deployment - Packages each model's weights, text-processing data, and voice embeddings into a single .litertlm bundle.
  • Low-latency streaming synthesis - Streams AudioChunk buffers clause by clause (synthesizeStream / synthesize_stream) so playback starts after the first clause, and accepts incremental text input (synthesizeStream on Web with finishInput = false, openStream on Android and iOS, or start_stream in Python with pushText and finishInput) for LLM-to-speech pipelines.
  • Per-utterance voice switching - Switches between bundled voices per utterance using SynthesisOptions without reloading the model (under 1 ms with Kokoro-82M).
  • Automatic sentence chunking - Splits multi-sentence paragraphs at clause and sentence boundaries (., !, ?, ;, :, \n) so long inputs stay within the model's context window.
  • Immediate cancellation - Thread-safe cancel() aborts in-flight unary or streaming synthesis within milliseconds when a user interrupts.
Inputs
The Text-to-Speech accepts the following inputs:
  • UTF-8 text: a single sentence, a multi-sentence paragraph, or incremental text deltas pushed using TtsStream
  • Optional per-utterance SynthesisOptions (voice_id and locale keyword arguments in Python)
Outputs
The Text-to-Speech outputs the following results:
  • AudioResult (TextToSpeechResult on Web, TtsAudioResult in Python) for unary calls
  • A stream of AudioChunk (TextToSpeechAudioChunk on Web) buffers with chunkIndex and isFinal metadata for streaming calls
  • Normalized 32-bit float mono PCM samples in [-1.0, 1.0] at 24,000 Hz, plus optional wordTimestamps when produced by the model

Configuration options

This task has the following configuration options:

Web

Option Name Description Value Range Default Value
baseOptions.modelAssetPath Path (or URL / modelAssetBuffer as a Uint8Array or ReadableStreamDefaultReader on Web) to a supported .litertlm model bundle (see Models). Keep the original filename, which the task uses to detect the model type. String / Path Required
baseOptions.delegate Hardware acceleration delegate used by the LiteRT runtime. When set to GPU, the Kokoro acoustic stage executes on CPU (XNNPACK) and the neural vocoder executes on GPU (OpenCL/Metal/WebGPU) with CPU fallback. PocketTTS and Phonon run on CPU. {CPU, GPU} CPU
speakingRate Speaking rate multiplier applied to synthesized audio (1.0 represents normal speaking speed). Float (0.0, 4.0] 1.0
targetBucket Target sequence-length bucket for the Kokoro acoustic/vocoder graph (for example, 64, 128, or 256 tokens). Smaller buckets reduce synthesis latency for short sentences; 0 uses the model's default capacity. PocketTTS and Phonon ignore this option. 0, 64, 128, 256 0
defaultVoiceId Default voice ID (for example, "af_heart" for Kokoro-82M, "alba" for PocketTTS, or "freya" for Phonon). Can be overridden per utterance using SynthesisOptions. String (Optional) The model's default voice
defaultLocale Optional default BCP 47 language tag (for example, "en-US", "es", "zh-CN"). When omitted, the task automatically infers the language from the selected voice. BCP 47 String (Optional) Inferred from voice ("en-US" in Python)
cacheDirectory Writable directory path used to persist unpacked phonetic dictionary assets and LiteRT XNNPACK weight caches across runs for faster cold starts (Kokoro-82M). On Web, set this to ":nocache" to turn caching off, as the browser's virtual file system does not persist caches across page loads. Directory Path (Optional) ""

Per-utterance options (SynthesisOptions):

Option Name Description Default Value
voiceId Overrides the voice profile for a single synthesize call (for example, switching from "af_heart" to "ef_dora" in under 1 ms without reloading model weights). null (uses task default)
locale Optional BCP 47 locale override for a single utterance. Leave unset when switching voices so the engine automatically resolves the target language from voiceId. null (inferred from voiceId)

Android

Option Name Description Value Range Default Value
baseOptions.modelAssetPath Path (or URL / modelAssetBuffer as a Uint8Array or ReadableStreamDefaultReader on Web) to a supported .litertlm model bundle (see Models). Keep the original filename, which the task uses to detect the model type. String / Path Required
baseOptions.delegate Hardware acceleration delegate used by the LiteRT runtime. When set to GPU, the Kokoro acoustic stage executes on CPU (XNNPACK) and the neural vocoder executes on GPU (OpenCL/Metal/WebGPU) with CPU fallback. PocketTTS and Phonon run on CPU. {CPU, GPU} CPU
speakingRate Speaking rate multiplier applied to synthesized audio (1.0 represents normal speaking speed). Float (0.0, 4.0] 1.0
targetBucket Target sequence-length bucket for the Kokoro acoustic/vocoder graph (for example, 64, 128, or 256 tokens). Smaller buckets reduce synthesis latency for short sentences; 0 uses the model's default capacity. PocketTTS and Phonon ignore this option. 0, 64, 128, 256 0
defaultVoiceId Default voice ID (for example, "af_heart" for Kokoro-82M, "alba" for PocketTTS, or "freya" for Phonon). Can be overridden per utterance using SynthesisOptions. String (Optional) The model's default voice
defaultLocale Optional default BCP 47 language tag (for example, "en-US", "es", "zh-CN"). When omitted, the task automatically infers the language from the selected voice. BCP 47 String (Optional) Inferred from voice ("en-US" in Python)
cacheDirectory Writable directory path used to persist unpacked phonetic dictionary assets and LiteRT XNNPACK weight caches across runs for faster cold starts (Kokoro-82M). On Web, set this to ":nocache" to turn caching off, as the browser's virtual file system does not persist caches across page loads. Directory Path (Optional) ""

Per-utterance options (SynthesisOptions):

Option Name Description Default Value
voiceId Overrides the voice profile for a single synthesize call (for example, switching from "af_heart" to "ef_dora" in under 1 ms without reloading model weights). null (uses task default)
locale Optional BCP 47 locale override for a single utterance. Leave unset when switching voices so the engine automatically resolves the target language from voiceId. null (inferred from voiceId)

iOS

Option Name Description Value Range Default Value
baseOptions.modelAssetPath Path (or URL / modelAssetBuffer as a Uint8Array or ReadableStreamDefaultReader on Web) to a supported .litertlm model bundle (see Models). Keep the original filename, which the task uses to detect the model type. String / Path Required
baseOptions.delegate Hardware acceleration delegate used by the LiteRT runtime. When set to GPU, the Kokoro acoustic stage executes on CPU (XNNPACK) and the neural vocoder executes on GPU (OpenCL/Metal/WebGPU) with CPU fallback. PocketTTS and Phonon run on CPU. {CPU, GPU} CPU
speakingRate Speaking rate multiplier applied to synthesized audio (1.0 represents normal speaking speed). Float (0.0, 4.0] 1.0
targetBucket Target sequence-length bucket for the Kokoro acoustic/vocoder graph (for example, 64, 128, or 256 tokens). Smaller buckets reduce synthesis latency for short sentences; 0 uses the model's default capacity. PocketTTS and Phonon ignore this option. 0, 64, 128, 256 0
defaultVoiceId Default voice ID (for example, "af_heart" for Kokoro-82M, "alba" for PocketTTS, or "freya" for Phonon). Can be overridden per utterance using SynthesisOptions. String (Optional) The model's default voice
defaultLocale Optional default BCP 47 language tag (for example, "en-US", "es", "zh-CN"). When omitted, the task automatically infers the language from the selected voice. BCP 47 String (Optional) Inferred from voice ("en-US" in Python)
cacheDirectory Writable directory path used to persist unpacked phonetic dictionary assets and LiteRT XNNPACK weight caches across runs for faster cold starts (Kokoro-82M). On Web, set this to ":nocache" to turn caching off, as the browser's virtual file system does not persist caches across page loads. Directory Path (Optional) ""

Per-utterance options (SynthesisOptions):

Option Name Description Default Value
voiceId Overrides the voice profile for a single synthesize call (for example, switching from "af_heart" to "ef_dora" in under 1 ms without reloading model weights). null (uses task default)
locale Optional BCP 47 locale override for a single utterance. Leave unset when switching voices so the engine automatically resolves the target language from voiceId. null (inferred from voiceId)

Python

Option Name Description Value Range Default Value
base_options.model_asset_path Path (or URL / modelAssetBuffer as a Uint8Array or ReadableStreamDefaultReader on Web) to a supported .litertlm model bundle (see Models). Keep the original filename, which the task uses to detect the model type. String / Path Required
base_options.delegate Hardware acceleration delegate used by the LiteRT runtime. When set to GPU, the Kokoro acoustic stage executes on CPU (XNNPACK) and the neural vocoder executes on GPU (OpenCL/Metal/WebGPU) with CPU fallback. PocketTTS and Phonon run on CPU. {CPU, GPU} CPU
speaking_rate Speaking rate multiplier applied to synthesized audio (1.0 represents normal speaking speed). Float (0.0, 4.0] 1.0
target_bucket Target sequence-length bucket for the Kokoro acoustic/vocoder graph (for example, 64, 128, or 256 tokens). Smaller buckets reduce synthesis latency for short sentences; 0 uses the model's default capacity. PocketTTS and Phonon ignore this option. 0, 64, 128, 256 0
default_voice_id Default voice ID (for example, "af_heart" for Kokoro-82M, "alba" for PocketTTS, or "freya" for Phonon). Can be overridden per utterance using SynthesisOptions. String (Optional) The model's default voice
default_locale Optional default BCP 47 language tag (for example, "en-US", "es", "zh-CN"). When omitted, the task automatically infers the language from the selected voice. BCP 47 String (Optional) Inferred from voice ("en-US" in Python)
cache_directory Writable directory path used to persist unpacked phonetic dictionary assets and LiteRT XNNPACK weight caches across runs for faster cold starts (Kokoro-82M). On Web, set this to ":nocache" to turn caching off, as the browser's virtual file system does not persist caches across page loads. Directory Path (Optional) ""

Per-utterance keyword arguments on synthesize / synthesize_stream:

Option Name Description Default Value
voice_id Overrides the voice profile for a single synthesize call (for example, switching from "af_heart" to "ef_dora" in under 1 ms without reloading model weights). None (uses task default)
locale Optional BCP 47 locale override for a single utterance. Leave unset when switching voices so the engine automatically resolves the target language from voice_id. None (inferred from voice_id)

Task output

Unary calls (synthesize) return a complete AudioResult (TextToSpeechResult on Web, TtsAudioResult in Python), and streaming calls (synthesizeStream / synthesize_stream) yield AudioChunk buffers as each clause is vocoded:

Field Type / Range Description
samples Float32Array ([-1.0, 1.0]) Synthesized mono PCM audio samples.
sampleRateHz int (Hz) Output audio sample rate, such as 24000 Hz for Kokoro (sample_rate_hz in Python).
wordTimestamps WordTimestamp[] (seconds) Optional word-level alignment intervals (word, startTimeSec, endTimeSec).
chunkIndex int Zero-based clause sequence index yielded on each streaming AudioChunk (chunk_index in Python).
isFinal boolean true on the final streaming AudioChunk of an utterance (is_final in Python).

The following example shows synthesized 24 kHz mono PCM audio with word-level alignment timestamps:

{
  sampleRateHz: 24000,
  samples: Float32Array(57600) [-0.0012, 0.0045, 0.0118 /* ... 2.4s mono PCM */],
  wordTimestamps: [
    { word: "Hello", startTimeSec: 0.04, endTimeSec: 0.38 },
    { word: "world", startTimeSec: 0.40, endTimeSec: 0.82 }
  ]
}

Models

The MediaPipe Text-to-Speech task requires a speech synthesis model in the LiteRT-LM (.litertlm) format. Models aren't included in the MediaPipe Tasks libraries. Download one of the following pre-packaged model bundles from Hugging Face, store it on the device, and pass the local path to BaseOptions.modelAssetPath (model_asset_path in Python).

Model Model Bundle Size Quantization Delegate License Supported Locales Recommended Use Case
Kokoro-82M kokoro_int8_gpu_fp16.litertlm ~295 MB INT8 acoustic + FP16 GPU vocoder GPU Apache 2.0 All nine locales (en-US, en-GB, es, fr-FR, it, pt-BR, hi, cmn, ja) Multilingual on-device speech synthesis across mobile, desktop, and web.
PocketTTS 100M pocket_tts_int8.litertlm ~760 MB INT8 CPU CC BY 4.0 Seven locales (en-US, fr-FR, de-DE, es-ES, it-IT, pt-BR, nl-NL) Multilingual speech synthesis on CPU.
PocketTTS 100M (English) pocket_tts_en_int8.litertlm ~163 MB INT8 CPU CC BY 4.0 en-US English speech synthesis on CPU with a smaller download.
Phonon 31M phonon_int8.litertlm ~87 MB INT8 CPU Apache 2.0 en-US English speech synthesis with the smallest download.

Supported languages and voices

Each model bundle includes its own set of voices. You can enumerate the voices in the loaded .litertlm bundle at runtime using listVoices() / list_voices().

Kokoro-82M includes 54 pre-packaged voice embeddings across nine locales (eight languages). Each voice ID uses a two-letter prefix <lang_char><gender_char>_<name> (for example, af_heart = American English Female "Heart", ef_dora = Spanish Female "Dora").

Language BCP 47 Language Tag Prefix Bundled Voice IDs (54 Total)
English (American) en-US af_, am_ Female (11): af_alloy, af_aoede, af_bella, af_heart (default), af_jessica, af_kore, af_nicole, af_nova, af_river, af_sarah, af_sky
Male (9): am_adam, am_echo, am_eric, am_fenrir, am_liam, am_michael, am_onyx, am_puck, am_santa
English (British) en-GB bf_, bm_ Female (4): bf_alice, bf_emma, bf_isabella, bf_lily
Male (4): bm_daniel, bm_fable, bm_george, bm_lewis
Spanish es ef_, em_ Female (1): ef_dora
Male (2): em_alex, em_santa
French fr-FR ff_ Female (1): ff_siwis
Hindi hi hf_, hm_ Female (2): hf_alpha, hf_beta
Male (2): hm_omega, hm_psi
Italian it if_, im_ Female (1): if_sara
Male (1): im_nicola
Portuguese (Brazilian) pt-BR pf_, pm_ Female (1): pf_dora
Male (2): pm_alex, pm_santa
Mandarin Chinese zh-CN / cmn zf_, zm_ Female (4): zf_xiaobei, zf_xiaoni, zf_xiaoxiao, zf_xiaoyi
Male (4): zm_yunjian, zm_yunxi, zm_yunxia, zm_yunyang
Japanese ja jf_, jm_ Female (4): jf_alpha, jf_gongitsune, jf_nezumi, jf_tebukuro
Male (1): jm_kumo

Each PocketTTS voice speaks one language. The multilingual bundle (pocket_tts_int8.litertlm) includes all of the following voices, and the English bundle (pocket_tts_en_int8.litertlm) includes only English voices.

Language BCP 47 Language Tag Voice IDs
English en-US alba (default), azelma, cosette, eponine, fantine, javert, jean, marius
French fr-FR estelle
German de-DE juergen
Spanish es-ES lola
Italian it-IT giovanni
Portuguese (Brazilian) pt-BR rafael
Dutch nl-NL daan

As with Kokoro-82M, set only voiceId (voice_id in Python) when you switch voices. If you also set a locale that doesn't match the voice's language, the task uses the default voice for that locale instead.

Phonon 31M speaks English (en-US) only. It includes five voices: freya (default), claire, lucas, lukas, and sofia.

Model license and attribution

Kyutai publishes PocketTTS under the Creative Commons Attribution 4.0 (CC-BY-4.0) license. If you distribute an app that uses a PocketTTS model, give appropriate credit to Kyutai, for example in your app's open source notices.

How it works

Text-to-Speech pipeline overview

For Kokoro-82M, the MediaPipe Text-to-Speech task runs a multi-stage pipeline:

  1. Sentence segmentation: Multi-sentence input text (or incremental text pushed using TtsStream) is split at punctuation boundaries to fit the acoustic model's token capacity.
  2. Grapheme-to-phoneme (G2P) frontend: Converts normalized text into phoneme token IDs using the phonetic dictionaries bundled in the model for each supported language.
  3. Acoustic stage: Runs the LiteRT acoustic model, conditioned on the selected voice's style embedding, to predict duration, pitch, and energy contours together with the acoustic features.
  4. Neural vocoder stage: Runs the ISTFTNet-based LiteRT vocoder model (on CPU using XNNPACK, or hybrid CPU+GPU) to convert the acoustic features into a 24 kHz mono float32 PCM waveform. During streaming synthesis, each clause's AudioChunk is emitted as soon as it is vocoded; unary synthesis concatenates all chunks into a single AudioResult.

PocketTTS 100M and Phonon 31M use a different architecture: a Flow-LM transformer generates audio latents, and a Mimi neural audio decoder converts them into 24 kHz audio. Both models run on CPU.