--- license: gpl-3.0 language: [en, ne, hi, vi, id, zh] pipeline_tag: text-to-speech tags: [text-to-speech, tiny, microcontroller, esp32, wasm, piper, distillation] library_name: sanotts --- # sanoTTS — a tiny neural voice that runs anywhere ***sano*** (सानो) — Nepali for **"small."** A family of tiny neural text-to-speech voices — **745k to 1.8M parameters** — that run with **no cloud and no NPU**: real-time on a ~$3 ESP32-S3 (out a GPIO into an LM386 and a speaker), or live in the browser via WASM. ![text in → ESP32 → speech out](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/saanotts-mcu-hero.png) | | | | --- | --- | | Smallest neural TTS family known | **745k – 1.8M parameters** | | Runs real-time on a $3 microcontroller | ESP32-S3, out a GPIO into an LM386 | | Runs in the browser | WebAssembly, no server | | Per-voice footprint | under **4 MB**, zero dependencies (espeak-ng phonemizer included) | | Coverage | **9 voices** across **6 languages** — English, Nepali (नेपाली), Hindi (हिन्दी), Vietnamese (Tiếng Việt), Indonesian (Bahasa), Chinese (中文) | | License | open source, **GPL-3.0** | **Live demo:** [ampixa.github.io/sanoTTS](https://ampixa.github.io/sanoTTS/) — every voice synthesizes your text live in the browser, no server, no upload. ## Samples One clip per voice below (a second clip per voice is in this repo's `samples/` folder). "Package here" means this HF repo carries that voice's raw fp16 weights; the three without one currently only ship through the [browser demo](https://ampixa.github.io/sanoTTS/) and the GitHub repo's `web/voices/` — their HF packages haven't been exported yet. | Voice | Language | Params | SCOREQ | Package here | Sample | | --- | --- | ---: | :---: | :---: | --- | | amy | English 🇺🇸 | 1.46 M | **4.13** | [`amy-en-1p46m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/amy-en-1p46m) | | | kristin | English 🇺🇸 | 1.40 M | 4.09 | [`kristin-en-1p4m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/kristin-en-1p4m) | | | hfc | English 🇺🇸 | 1.83 M | 3.94 | [`hfc-en-1p8m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/hfc-en-1p8m) | | | amy-small | English 🇺🇸 | 1.08 M | 3.70 | [`amy-en-1p1m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/amy-en-1p1m) | | | robot (on-device, int8) | English 🇺🇸 | 745 k | — | not packaged here (int8 MCU format, not fp16) | | | Indonesian | Bahasa | 1.46 M | — | [`id-newstts-1p46m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/id-newstts-1p46m) | | | Vietnamese | Tiếng Việt | 1.46 M | — | [`vi-vais1000-1p46m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/vi-vais1000-1p46m) | | | Nepali | नेपाली | 1.47 M | — | not exported yet — see `web/voices/nepali/` in the GitHub repo | | | Hindi | हिन्दी | 1.50 M | — | not exported yet — see `web/voices/hindi/` in the GitHub repo | | | Chinese | 中文 | 1.50 M | — | not exported yet — see `web/voices/chinese/` in the GitHub repo | | The "robot" row is the same 745k-parameter model that runs on the ESP32-S3 — bit-exact with the chip's own output. SCOREQ is only reported for the English voices, which share a common eval set; the other languages haven't been scored against a comparable reference yet. ## Install & use | Platform | Install | Then | | --- | --- | --- | | Python | `pip install sanotts` | `sanotts say "Hello" --voice amy -o hello.wav` | | Web (npm) | `npm install sanotts-web` | `const tts = await SanoTTS.load(); await tts.synthesize('Hello', {voice:'amy'})` | | Web (no build) | copy `dist/` + `voices/` | see [Deploy on your own site](https://github.com/Ampixa/sanoTTS#deploy-on-your-own-site) in the GitHub README | | Arduino / PlatformIO | zip-install or `lib_deps = https://github.com/Ampixa/sanoTTS.git` | [`arduino/README.md`](https://github.com/Ampixa/sanoTTS/blob/master/arduino/README.md) | | Hugging Face | this repo | voice packages above, `manifest.json` + `weights.fp16.bin` per voice | | Browser | nothing | [ampixa.github.io/sanoTTS](https://ampixa.github.io/sanoTTS/) | Pip voices: `amy`, `amy-1p1m`, `amy-1p8m`, `kristin`, `hfc`, `vi`, `id` — fetched from the [voices-v1 release](https://github.com/Ampixa/sanoTTS/releases/tag/voices-v1) into `~/.cache/sanotts/`. Pure numpy inference, no torch, no onnxruntime. ## How it stacks up Open small-scale TTS on an honest gate — a diverse 24-sentence set scored with the **same** no-reference suite (SCOREQ / UTMOS are naturalness predictors, DNSMOS-SIG is signal quality; higher is better). Parameter counts are inference-time and exclude the shared external G2P. ![Size comparison: sanoTTS 0.75M-1.8M params vs TinyTTS 1.62M vs Inflect Nano 4.63M vs Kokoro 82M, linear axis](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/chart-size-comparison.svg) Kokoro is 45x larger than our largest voice, and 110x larger than our smallest. Shipped-file sizes: sanoTTS amy 2.8 MB fp16 and TinyTTS 3.5 MB fp16, both verified from the released files; Kokoro's ~330 MB fp32 is its widely cited public figure. | System | Params | SCOREQ | UTMOS | DNS-SIG | | --- | ---: | :---: | :---: | :---: | | **sanoTTS (amy)** | **1.46 M** | **4.13** | **4.10** | 3.61 | | TinyTTS | 1.62 M | 3.94 | 3.65 | **3.62** | | Inflect Nano | 4.63 M | 3.81 | 3.65 | 3.58 | | Kitten TTS nano | 15 M | 3.02 | 3.58 | 3.43 | | _reference (~15 M)_ | _~15 M_ | _4.71_ | _4.47_ | _3.65_ | | _Kokoro_ | _82 M_ | _4.89_ | _4.52_ | _3.69_ | sanoTTS is the **smallest** model here and the **best on naturalness (SCOREQ and UTMOS) among everything up to 15M params** — beating TinyTTS while being smaller. On DNSMOS-SIG, TinyTTS edges us by 0.01 — no single metric tells the whole story. It's the only one that runs a full neural stack on a $3 MCU. The frontier only pulls ahead at ~15M-class models and Kokoro (82M, 60x larger) — a gap we don't claim to close. Reproduce it with `tools/eval_mos_all.py` + `tools/eval_scorecard.py` in the GitHub repo. ## How it works ![text → duration → acoustic → decoder → audio](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/saanotts-signal-path.png) espeak-ng provides phoneme IDs; a duration model predicts timing; an acoustic model predicts generator latents; a decoder renders 22 kHz audio. The web voices (amy, kristin, hfc, and the other languages) use a compact time-domain decoder running in fp32; the 745k on-device model instead uses a quantized int8 iSTFT decoder, sized to fit and run in real time on the ESP32-S3. All models are distilled from a Piper/VITS teacher — see [`docs/distillation-recipe.md`](https://github.com/Ampixa/sanoTTS/blob/master/docs/distillation-recipe.md) in the GitHub repo for the full recipe. ## Deploy - **ESP32-S3 talking device** — a standalone WiFi dashboard: type text, the board phonemizes (on-chip espeak-ng) and speaks. See [`mcu/ports/esp32s3/`](https://github.com/Ampixa/sanoTTS/tree/master/mcu/ports/esp32s3). - **Browser** — the full stack in WASM, no server. **[▶ Hear and synthesize all 9 voices live](https://ampixa.github.io/sanoTTS/)**; source in [`web/`](https://github.com/Ampixa/sanoTTS/tree/master/web). - **Other MCUs** — which chips can run it and how well: [`docs/mcu-classes-and-porting.md`](https://github.com/Ampixa/sanoTTS/blob/master/docs/mcu-classes-and-porting.md). ## Links - Source, recipes, eval tooling: [github.com/Ampixa/sanoTTS](https://github.com/Ampixa/sanoTTS) - Live browser demo: [ampixa.github.io/sanoTTS](https://ampixa.github.io/sanoTTS/) - npm package: [sanotts-web](https://www.npmjs.com/package/sanotts-web) - PyPI package: [sanotts](https://pypi.org/project/sanotts/) ## License GPLv3 — see [`LICENSE`](https://github.com/Ampixa/sanoTTS/blob/master/LICENSE). The pipeline builds on GPLv3 components (notably [espeak-ng](https://github.com/espeak-ng/espeak-ng) for G2P, and [piper](https://github.com/OHF-Voice/piper1-gpl)), so the project as a whole is GPLv3. Copyright (C) 2026 Ampixa. ## Files here Each voice directory is a self-contained fp16 package (`weights.fp16.bin` + `manifest.json` + `piper-phoneme-config.json` + sibilant-injection calibration where applicable), consumable by the `sanotts` Python package and the portable C runtime. `samples/` holds the audio clips embedded above (mp3, one or two per voice + the on-device `mcu-745k.mp3`).