Model reference · open weights

Matcha-TTS

Audio litert-community Text→speech 1 build Open weights 1k dl/mo

Matcha-TTS is an open-weight audio or speech model from litert-community. Matcha-TTS (BF16) weighs 0 MB; the smallest configuration that runs it is RTX 3060 12 GB.

For self-hosting, compare this build's requirements below with the GPU you plan to rent.

  • Matcha-TTS is an on-device English text-to-speech model by litert-community, designed for Android and web via the LiteRT runtime.
  • It uses a conditional flow-matching acoustic model and a HiFi-GAN time-domain vocoder to generate 22.05 kHz audio without FFT operations.
  • The model is released under the MIT license and consists of four fp16 TFLite graphs with fixed shapes for up to 256 phonemes and 512 mel frames.

Summary of the litert-community/Matcha-TTS model card, 2026-10-01

What it is

Released bylitert-community
Released2026-06-26
VRAM0 MB for the weights

What it runs on

Memory and cards for Matcha-TTS (BF16)

0 MBweights, file size
1.6 GBruntime overhead
CardOne streamMemory
RTX 3060 12 GBfits11.6 GB
RTX 4060 Ti 16 GBfits15.4 GB
RTX 3090 24 GBfits23.4 GB
RTX 4090 24 GBfits23.4 GB
RTX 5090 32 GBfits31.0 GB
L40S 48 GBfits44.0 GB
A100 80 GBfits78.2 GB
H100 80 GBfits78.1 GB
RTX PRO 6000 Blackwell 96 GBfits93.8 GB
DGX Spark (GB10) 128 GB unifiedfits107 GB
H200 141 GBfits138 GB
B200 180 GBfits176 GB

From the model card

What litert-community says about Matcha-TTS

Read the model card

LiteRT is Google's on-device runtime, the new name for TensorFlow Lite (Android: com.google.ai.edge.litert:litert), and litert-torch, the renamed ai-edge-torch, is its PyTorch converter: a PyTorch model converted unmodified with litert_torch.convert matched the original to 4e-7 on a Galaxy S26 (measured, LiteRT 2.2.0, Android 16, 2026-09-05).

Measured on device (edge-compat, dp_g2p_matcha_fp16): Raspberry Pi 5 · LiteRT 2.2.0.dev20260804 · CPU/XNNPACK, 4 threads · 22.0 ms p50 (2026-08-31); browser · Chromium 151 on M4 Max · LiteRT.js 2.5.3 · WebGPU · 136 ms p50 (2026-08-11). Record: https://github.com/john-rocky/edge-compat/blob/main/cards/matcha-tts__dp_g2p_matcha_fp16/CARD.md

Measured on device (edge-compat, matcha_decoder_fp16): Raspberry Pi 5 · LiteRT 2.2.0.dev20260804 · CPU/XNNPACK, 4 threads · 69.7 ms p50 (2026-08-31); browser · Chromium 151 on M4 Max · LiteRT.js 2.5.3 · WebGPU · 9.55 ms p50 · output differs from CPU (max rel diff 6e+03) (2026-08-11). Record: https://github.com/john-rocky/edge-compat/blob/main/cards/matcha-tts__matcha_decoder_fp16/CARD.md

Measured on device (edge-compat, matcha_textenc_fp16): Raspberry Pi 5 · LiteRT 2.2.0.dev20260804 · CPU/XNNPACK, 4 threads · 38.7 ms p50 (2026-08-31); browser · Chromium 151 on M4 Max · LiteRT.js 2.5.3 · WebGPU · 5.99 ms p50 · output matches CPU (2026-08-11). Record: https://github.com/john-rocky/edge-compat/blob/main/cards/matcha-tts__matcha_textenc_fp16/CARD.md

Measured on device (edge-compat, matcha_vocoder_fp16): Raspberry Pi 5 · LiteRT 2.2.0.dev20260804 · CPU/XNNPACK, 4 threads · 5825 ms p50 (2026-08-31); browser · Chromium 151 on M4 Max · LiteRT.js 2.5.3 · WebGPU · 104 ms p50 · output differs from CPU (max rel diff 0.22) (2026-08-11). Record: https://github.com/john-rocky/edge-compat/blob/main/cards/matcha-tts__matcha_vocoder_fp16/CARD.md

Matcha-TTS — LiteRT (on-device, FFT-free, GPU)

On-device English text-to-speech for Android via LiteRT CompiledModel. This is the FFT-free TTS lane: Matcha-TTS pairs a conditional flow-matching (CFM) acoustic model with a HiFi-GAN time-domain vocoder, so there is no FFT/iSTFT anywhere in the synthesis path. 22.05 kHz, LJSpeech voice.

Try it in your browser: john-rocky.github.io/page-demos/matcha-tts — the same four .tflite files below running on LiteRT.js (text encoder + vocoder on WebGPU, decoder on WASM). Nothing to install; inference runs on your machine.

Converted from the official matcha_ljspeech + hifigan_T2_v1 checkpoints with litert-torch, re-authored to be ML-Drift-GPU-clean (per-graph tflite-vs-torch corr 1.000000; end-to-end waveform corr ≥0.99). fp16 weights.

Files

FileSizeIn → OutDelegate (Pixel 8a)
matcha_textenc_fp16.tflite15 MBemb[1,256,192] + mask[1,1,256] → mu[1,80,256], logw[1,1,256]GPU
matcha_decoder_fp16.tflite23 MBx,mu[1,80,512] + t_sin[1,160] + mask[1,1,512] → v[1,80,512]CPU¹
matcha_vocoder_fp16.tflite29 MBmel[1,80,512] → wav[1,1,131072]GPU
dp_g2p_matcha_fp16.tflite26 MBtext[1,96] (char ids) → logits[1,96,64] (IPA)CPU
emb.bin0.1 MBphoneme embedding table (178×192 f32, host lookup)host
g2p_dict.txt.gz1.8 MB275k-entry espeak-IPA dictionary (primary G2P)host
config.json, g2p_meta.json—symbols, shapes, mel stats, G2P tokenizer tableshost

¹ The CFM decoder runs on the CompiledModel CPU delegate. It converts GPU-clean and is correct on CPU, but the Mali ML Drift GPU delegate mis-fuses the decoder's transformer blocks at large activation magnitude (the same block is correct as a standalone GPU graph, corr 0.984, but collapses to corr 0.006 fused — a graph-fusion bug, not a bad op). text encoder + vocoder run on the GPU; the GPU vocoder dominates wall time so the pipeline stays realtime (RTF ~0.8).

Pipeline (host orchestration)

text --G2P(CPU dict+neural)--> phoneme ids
     --host: embed + intersperse + pad-->     text_encoder(GPU) -> mu, logw
     --host: durations + length-regulator-->  mu_y[1,80,T]
     --host: Euler ODE loop (N steps)-->        decoder(CPU) x N -> v
     --host: denormalize-->                     vocoder(GPU)     -> waveform

Fixed shapes (256 phonemes, 512 mel frames ≈ 5.9 s); a runtime float mask makes padded positions a no-op so one compiled graph handles any length.

How to use

Android (Kotlin, LiteRT CompiledModel)

fun load(name: String, acc: Accelerator) =                    // models staged in filesDir
    CompiledModel.create(File(filesDir, name).absolutePath, CompiledModel.Options(acc), null)

val textenc = load("matcha_textenc_fp16.tflite", Accelerator.GPU)
val decoder = load("matcha_decoder_fp16.tflite", Accelerator.CPU)  // Mali mis-fuses this graph on GPU
val vocoder = load("matcha_vocoder_fp16.tflite", Accelerator.GPU)

val teIn = textenc.createInputBuffers(); val teOut = textenc.createOutputBuffers()
teIn[0].writeFloat(emb)     // [1,256,192] host phoneme-embedding lookup (emb.bin), blanks interspersed
teIn[1].writeFloat(tmask)   // [1,1,256]   1 = real phoneme position
textenc.run(teIn, teOut)    // -> mu[1,80,256], logw[1,1,256]
// host: durations ceil(exp(logw))·0.95 -> length-regulate mu -> mu_y[1,80,512]; 10 Euler steps of
// decoder(x, mu_y, t_sin[1,160], ymask[1,1,512]); mel = x·2.116101 − 5.536622 -> vocoder -> wav.
// Full pipeline: the text_to_speech (Matcha-TTS) sample in google-ai-edge/litert-samples.

Python (desktop verification)

import gzip, json, math, numpy as np, soundfile as sf
from ai_edge_litert.interpreter import Interpreter

MAXT, MAXM, LS = 256, 512, 0.95
cfg = json.

Quoted from the model card on Hugging Face. The full card is behind the Hugging Face link above.

How it works

How audio & music work

Audio or textinputAudio modelrecognise / synthesiseText or audiooutputSpeech-to-text turns audio into text; text-to-speech and music models turn text into audio.
© 2026 AxForge · EU-hosted AI infrastructure Pricing Docs Trust Privacy Terms