voidash commited on
Commit
dd52a31
·
verified ·
1 Parent(s): 19c75fd

Rebuild model card: samples table with embedded audio players, install table, links

Browse files
Files changed (1) hide show
  1. README.md +97 -101
README.md CHANGED
@@ -8,41 +8,79 @@ library_name: sanotts
8
 
9
  # sanoTTS — a tiny neural voice that runs anywhere
10
 
11
- ***sano*** (सानो) — Nepali for **"small."** A small neural TTS: distill a Piper/VITS
12
- teacher voice into a **~1.4M-parameter** model that runs with **no cloud and no
13
- NPU** real-time on a ~$3 ESP32-S3 (out a GPIO into an LM386 and a speaker), or in
14
- the browser via WASM.
15
 
16
  ![text in → ESP32 → speech out](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/saanotts-mcu-hero.png)
17
 
18
- - smallest neural TTS family known — **745k to 1.8M parameters**
19
- - runs **real-time** on a **$3 microcontroller** (ESP32-S3)
20
- - runs right in your browser **WebAssembly**, no server
21
- - under **4 MB** per voice, zero dependencies (espeak-ng phonemizer included)
22
- - **9 voices** across **6 languages** — English, Nepali (नेपाली), Hindi (हिन्दी),
23
- Vietnamese (Tiếng Việt), Indonesian (Bahasa), Chinese (中文)
24
- - open source, **GPL-3.0**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- ## Live demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- **[ampixa.github.io/sanoTTS](https://ampixa.github.io/sanoTTS/)** every voice
29
- synthesizes your text live in the browser. No server, no upload: text goes
30
- through an espeak-ng-in-WASM phonemizer and that voice's own neural stack, all
31
- client-side.
32
 
33
  ## How it stacks up
34
 
35
- Open small-scale TTS on an honest gate — a diverse 24-sentence set scored with the
36
- **same** no-reference suite (SCOREQ / UTMOS are naturalness predictors, DNSMOS-SIG
37
- is signal quality; higher is better). Parameter counts are inference-time and
38
- exclude the shared external G2P.
39
 
40
  ![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)
41
 
42
- Kokoro is 45x larger than our largest voice, and 110x larger than our smallest.
43
- Shipped-file sizes: sanoTTS amy 2.8 MB fp16 and TinyTTS 3.5 MB fp16, both
44
- verified from the released files; Kokoro's ~330 MB fp32 is its widely cited
45
- public figure.
46
 
47
  | System | Params | SCOREQ | UTMOS | DNS-SIG |
48
  | --- | ---: | :---: | :---: | :---: |
@@ -50,104 +88,62 @@ public figure.
50
  | TinyTTS | 1.62 M | 3.94 | 3.65 | **3.62** |
51
  | Inflect Nano | 4.63 M | 3.81 | 3.65 | 3.58 |
52
  | Kitten TTS nano | 15 M | 3.02 | 3.58 | 3.43 |
53
- | _Piper (teacher)_ | _~15 M_ | _4.71_ | _4.47_ | _3.65_ |
54
  | _Kokoro_ | _82 M_ | _4.89_ | _4.52_ | _3.69_ |
55
 
56
- sanoTTS is the **smallest** model here and the **best on naturalness (SCOREQ and
57
- UTMOS) among everything up to 15M params** — beating TinyTTS while being smaller.
58
- On DNSMOS-SIG, TinyTTS edges us by 0.01 — no single metric tells the whole story.
59
- It's the only one that runs a full neural stack on a $3 MCU. Parameter count
60
- isn't destiny at this scale: Kitten TTS at 10x the size scores a full SCOREQ
61
- point lower. The frontier only pulls ahead at the teacher (~15M) and Kokoro (82M,
62
- 60x larger) a gap we don't claim to close. Reproduce it with
63
- `tools/eval_mos_all.py` + `tools/eval_scorecard.py`.
64
-
65
- ![The size-quality frontier: SCOREQ rising from 3.70 to 4.16 as decoder size grows from 1.09M to 1.84M params, same voice](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/chart-frontier.svg)
66
-
67
- Same voice (amy), same duration/acoustic recipe — only decoder size changes.
68
- Quality lives in the decoder: doubling it from 1.09M to 1.84M params moves
69
- SCOREQ from 3.70 to 4.16.
70
-
71
- ## The voices
72
-
73
- | Language | Voice | Params | SCOREQ |
74
- | --- | --- | ---: | :---: |
75
- | English 🇺🇸 | amy | 1.46 M | 4.13 |
76
- | | kristin | 1.40 M | 4.09 |
77
- | | hfc | 1.83 M | 3.94 |
78
- | | amy-small | 1.08 M | 3.70 |
79
- | | robot (on-device, int8) | 745 k | — |
80
- | Nepali नेपाली | Nepali | 1.47 M | — |
81
- | Hindi हिन्दी | Hindi | 1.50 M | — |
82
- | Vietnamese Tiếng Việt | Vietnamese | 1.46 M | — |
83
- | Indonesian Bahasa | Indonesian | 1.46 M | — |
84
- | Chinese 中文 | Chinese | 1.50 M | — |
85
-
86
- The "robot" row is the same 745k-parameter model that runs on the ESP32-S3 —
87
- bit-exact with the chip's own output. SCOREQ is only reported for the English
88
- voices, which share a common eval set; the other languages haven't been scored
89
- against a comparable reference yet.
90
 
91
  ## How it works
92
 
93
  ![text → duration → acoustic → decoder → audio](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/saanotts-signal-path.png)
94
 
95
- Piper provides phoneme IDs; a duration student predicts timing; an acoustic
96
- student predicts the generator latents; a decoder student renders 22 kHz audio.
97
  The web voices (amy, kristin, hfc, and the other languages) use a compact
98
- "piperlite" decoder running in fp32 WASM; the 745k on-device model instead uses
99
  a quantized int8 iSTFT decoder, sized to fit and run in real time on the
100
- ESP32-S3. All students are distilled from the teacher.
101
-
102
- ## Distill your own voice
103
-
104
- The end-to-end recipe is [`docs/distillation-recipe.md`](docs/distillation-recipe.md):
105
- build a probe pack from a Piper teacher → train the duration, acoustic-latent, and
106
- decoder students → joint finetune → export int8. New-language porting is
107
- [`docs/roota-language-porting-recipe.md`](docs/roota-language-porting-recipe.md).
108
-
109
- ```bash
110
- pip install -e .
111
- # then follow docs/distillation-recipe.md against any en_US Piper voice
112
- ```
113
 
114
  ## Deploy
115
 
116
- - **ESP32-S3 talking device** — a standalone WiFi dashboard: type text, the board
117
- phonemizes (on-chip espeak-ng) and speaks. See
118
- [`mcu/ports/esp32s3/`](mcu/ports/esp32s3/).
119
- - **Browser** — the full stack in WASM, no server. **[▶ Hear and synthesize all 9
120
- voices live](https://ampixa.github.io/sanoTTS/)** (GitHub Pages); source in
121
- [`web/`](web/).
122
  - **Other MCUs** — which chips can run it and how well:
123
- [`docs/mcu-classes-and-porting.md`](docs/mcu-classes-and-porting.md).
124
-
125
- ## Verify your result
126
 
127
- The eval loop measures what actually matters — intelligibility (Whisper WER),
128
- phoneme-class fidelity, and G2P parity — not just a gameable MOS score:
129
- `tools/eval_scorecard.py`, `tools/eval_phoneme_class_fidelity.py`,
130
- `tools/eval_g2p_parity.py`.
131
 
132
- ## Layout
133
-
134
- [`docs/repository-layout.md`](docs/repository-layout.md). In short: `src/saanotts/`
135
- (package), `tools/` (pipeline + eval commands), `mcu/` (portable C runtime + device
136
- ports), `web/` (browser demo), `configs/` + `data/textsets/` (contracts).
137
 
138
  ## License
139
 
140
- GPLv3 — see [`LICENSE`](https://github.com/Ampixa/sanoTTS/blob/master/LICENSE). The distillation + G2P path builds on
141
- [piper](https://github.com/OHF-Voice/piper1-gpl) and
142
- [espeak-ng](https://github.com/espeak-ng/espeak-ng), both GPLv3, so the project as a
 
143
  whole is GPLv3.
144
 
145
  Copyright (C) 2026 Ampixa.
146
 
147
-
148
  ## Files here
149
 
150
- Each directory is a self-contained fp16 voice package (`weights.fp16.bin` +
151
- `manifest.json` + phoneme config + sibilant-injection calibration), consumable
152
- by the `sanotts` Python package and the portable C runtime. Source, recipes,
153
- and the live demo: https://github.com/Ampixa/sanoTTS · https://ampixa.github.io/sanoTTS/
 
 
8
 
9
  # sanoTTS — a tiny neural voice that runs anywhere
10
 
11
+ ***sano*** (सानो) — Nepali for **"small."** A family of tiny neural
12
+ text-to-speech voices **745k to 1.8M parameters** that run with
13
+ **no cloud and no NPU**: real-time on a ~$3 ESP32-S3 (out a GPIO into an
14
+ LM386 and a speaker), or live in the browser via WASM.
15
 
16
  ![text in → ESP32 → speech out](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/saanotts-mcu-hero.png)
17
 
18
+ | | |
19
+ | --- | --- |
20
+ | Smallest neural TTS family known | **745k – 1.8M parameters** |
21
+ | Runs real-time on a $3 microcontroller | ESP32-S3, out a GPIO into an LM386 |
22
+ | Runs in the browser | WebAssembly, no server |
23
+ | Per-voice footprint | under **4 MB**, zero dependencies (espeak-ng phonemizer included) |
24
+ | Coverage | **9 voices** across **6 languages** — English, Nepali (नेपाली), Hindi (हिन्दी), Vietnamese (Tiếng Việt), Indonesian (Bahasa), Chinese (中文) |
25
+ | License | open source, **GPL-3.0** |
26
+
27
+ **Live demo:** [ampixa.github.io/sanoTTS](https://ampixa.github.io/sanoTTS/) —
28
+ every voice synthesizes your text live in the browser, no server, no upload.
29
+
30
+ ## Samples
31
+
32
+ One clip per voice below (a second clip per voice is in this repo's
33
+ `samples/` folder). "Package here" means this HF repo carries that voice's
34
+ raw fp16 weights; the three without one currently only ship through the
35
+ [browser demo](https://ampixa.github.io/sanoTTS/) and the GitHub repo's
36
+ `web/voices/` — their HF packages haven't been exported yet.
37
+
38
+ | Voice | Language | Params | SCOREQ | Package here | Sample |
39
+ | --- | --- | ---: | :---: | :---: | --- |
40
+ | amy | English 🇺🇸 | 1.46 M | **4.13** | [`amy-en-1p46m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/amy-en-1p46m) | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/english-amy-1.mp3"></audio> |
41
+ | kristin | English 🇺🇸 | 1.40 M | 4.09 | [`kristin-en-1p4m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/kristin-en-1p4m) | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/english-kristin-1.mp3"></audio> |
42
+ | hfc | English 🇺🇸 | 1.83 M | 3.94 | [`hfc-en-1p8m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/hfc-en-1p8m) | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/english-hfc-1.mp3"></audio> |
43
+ | amy-small | English 🇺🇸 | 1.08 M | 3.70 | [`amy-en-1p1m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/amy-en-1p1m) | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/english-amy-small-1.mp3"></audio> |
44
+ | robot (on-device, int8) | English 🇺🇸 | 745 k | — | not packaged here (int8 MCU format, not fp16) | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/mcu-745k.mp3"></audio> |
45
+ | Indonesian | Bahasa | 1.46 M | — | [`id-newstts-1p46m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/id-newstts-1p46m) | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/indonesian-1.mp3"></audio> |
46
+ | Vietnamese | Tiếng Việt | 1.46 M | — | [`vi-vais1000-1p46m/`](https://huggingface.co/ampixa/sanoTTS/tree/main/vi-vais1000-1p46m) | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/vietnamese-1.mp3"></audio> |
47
+ | Nepali | नेपाली | 1.47 M | — | not exported yet — see `web/voices/nepali/` in the GitHub repo | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/nepali-1.mp3"></audio> |
48
+ | Hindi | हिन्दी | 1.50 M | — | not exported yet — see `web/voices/hindi/` in the GitHub repo | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/hindi-1.mp3"></audio> |
49
+ | Chinese | 中文 | 1.50 M | — | not exported yet — see `web/voices/chinese/` in the GitHub repo | <audio controls src="https://huggingface.co/ampixa/sanoTTS/resolve/main/samples/chinese-1.mp3"></audio> |
50
 
51
+ The "robot" row is the same 745k-parameter model that runs on the ESP32-S3 —
52
+ bit-exact with the chip's own output. SCOREQ is only reported for the
53
+ English voices, which share a common eval set; the other languages haven't
54
+ been scored against a comparable reference yet.
55
+
56
+ ## Install & use
57
+
58
+ | Platform | Install | Then |
59
+ | --- | --- | --- |
60
+ | Python | `pip install sanotts` | `sanotts say "Hello" --voice amy -o hello.wav` |
61
+ | Web (npm) | `npm install sanotts-web` | `const tts = await SanoTTS.load(); await tts.synthesize('Hello', {voice:'amy'})` |
62
+ | 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 |
63
+ | 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) |
64
+ | Hugging Face | this repo | voice packages above, `manifest.json` + `weights.fp16.bin` per voice |
65
+ | Browser | nothing | [ampixa.github.io/sanoTTS](https://ampixa.github.io/sanoTTS/) |
66
 
67
+ Pip voices: `amy`, `amy-1p1m`, `amy-1p8m`, `kristin`, `hfc`, `vi`, `id` —
68
+ fetched from the [voices-v1 release](https://github.com/Ampixa/sanoTTS/releases/tag/voices-v1)
69
+ into `~/.cache/sanotts/`. Pure numpy inference, no torch, no onnxruntime.
 
70
 
71
  ## How it stacks up
72
 
73
+ Open small-scale TTS on an honest gate — a diverse 24-sentence set scored
74
+ with the **same** no-reference suite (SCOREQ / UTMOS are naturalness
75
+ predictors, DNSMOS-SIG is signal quality; higher is better). Parameter
76
+ counts are inference-time and exclude the shared external G2P.
77
 
78
  ![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)
79
 
80
+ Kokoro is 45x larger than our largest voice, and 110x larger than our
81
+ smallest. Shipped-file sizes: sanoTTS amy 2.8 MB fp16 and TinyTTS 3.5 MB
82
+ fp16, both verified from the released files; Kokoro's ~330 MB fp32 is its
83
+ widely cited public figure.
84
 
85
  | System | Params | SCOREQ | UTMOS | DNS-SIG |
86
  | --- | ---: | :---: | :---: | :---: |
 
88
  | TinyTTS | 1.62 M | 3.94 | 3.65 | **3.62** |
89
  | Inflect Nano | 4.63 M | 3.81 | 3.65 | 3.58 |
90
  | Kitten TTS nano | 15 M | 3.02 | 3.58 | 3.43 |
91
+ | _reference (~15 M)_ | _~15 M_ | _4.71_ | _4.47_ | _3.65_ |
92
  | _Kokoro_ | _82 M_ | _4.89_ | _4.52_ | _3.69_ |
93
 
94
+ sanoTTS is the **smallest** model here and the **best on naturalness
95
+ (SCOREQ and UTMOS) among everything up to 15M params** — beating TinyTTS
96
+ while being smaller. On DNSMOS-SIG, TinyTTS edges us by 0.01 — no single
97
+ metric tells the whole story. It's the only one that runs a full neural
98
+ stack on a $3 MCU. The frontier only pulls ahead at ~15M-class models and
99
+ Kokoro (82M, 60x larger) a gap we don't claim to close. Reproduce it with
100
+ `tools/eval_mos_all.py` + `tools/eval_scorecard.py` in the GitHub repo.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  ## How it works
103
 
104
  ![text → duration → acoustic → decoder → audio](https://raw.githubusercontent.com/Ampixa/sanoTTS/master/docs/assets/saanotts-signal-path.png)
105
 
106
+ espeak-ng provides phoneme IDs; a duration model predicts timing; an
107
+ acoustic model predicts generator latents; a decoder renders 22 kHz audio.
108
  The web voices (amy, kristin, hfc, and the other languages) use a compact
109
+ time-domain decoder running in fp32; the 745k on-device model instead uses
110
  a quantized int8 iSTFT decoder, sized to fit and run in real time on the
111
+ ESP32-S3. All models are distilled from a Piper/VITS teacher — see
112
+ [`docs/distillation-recipe.md`](https://github.com/Ampixa/sanoTTS/blob/master/docs/distillation-recipe.md)
113
+ in the GitHub repo for the full recipe.
 
 
 
 
 
 
 
 
 
 
114
 
115
  ## Deploy
116
 
117
+ - **ESP32-S3 talking device** — a standalone WiFi dashboard: type text, the
118
+ board phonemizes (on-chip espeak-ng) and speaks. See
119
+ [`mcu/ports/esp32s3/`](https://github.com/Ampixa/sanoTTS/tree/master/mcu/ports/esp32s3).
120
+ - **Browser** — the full stack in WASM, no server. **[▶ Hear and synthesize
121
+ all 9 voices live](https://ampixa.github.io/sanoTTS/)**; source in
122
+ [`web/`](https://github.com/Ampixa/sanoTTS/tree/master/web).
123
  - **Other MCUs** — which chips can run it and how well:
124
+ [`docs/mcu-classes-and-porting.md`](https://github.com/Ampixa/sanoTTS/blob/master/docs/mcu-classes-and-porting.md).
 
 
125
 
126
+ ## Links
 
 
 
127
 
128
+ - Source, recipes, eval tooling: [github.com/Ampixa/sanoTTS](https://github.com/Ampixa/sanoTTS)
129
+ - Live browser demo: [ampixa.github.io/sanoTTS](https://ampixa.github.io/sanoTTS/)
130
+ - npm package: [sanotts-web](https://www.npmjs.com/package/sanotts-web)
131
+ - PyPI package: [sanotts](https://pypi.org/project/sanotts/)
 
132
 
133
  ## License
134
 
135
+ GPLv3 — see [`LICENSE`](https://github.com/Ampixa/sanoTTS/blob/master/LICENSE).
136
+ The pipeline builds on GPLv3 components (notably
137
+ [espeak-ng](https://github.com/espeak-ng/espeak-ng) for G2P, and
138
+ [piper](https://github.com/OHF-Voice/piper1-gpl)), so the project as a
139
  whole is GPLv3.
140
 
141
  Copyright (C) 2026 Ampixa.
142
 
 
143
  ## Files here
144
 
145
+ Each voice directory is a self-contained fp16 package (`weights.fp16.bin` +
146
+ `manifest.json` + `piper-phoneme-config.json` + sibilant-injection
147
+ calibration where applicable), consumable by the `sanotts` Python package
148
+ and the portable C runtime. `samples/` holds the audio clips embedded
149
+ above (mp3, one or two per voice + the on-device `mcu-745k.mp3`).