# espeak-ng 1.52.0 (WebAssembly build for 2tool)

**GPL notice.** `espeak-ng.wasm`, `espeak-ng.mjs` and `espeak-ng-data/` are object code of eSpeak NG, licensed under
the GNU General Public License version 3 or later (`COPYING`). The complete Corresponding Source is in `source/` in
this folder: the unmodified upstream source tarball, the glue code (`glue.c`) and the build script (`build.py`) that
produced every built file here. No patches were applied. `phonemize.js` is source code already. You may copy,
change and redistribute all of it under the GPL; see `LICENSE` for the other licences involved.

## Upstream

- Repository: https://github.com/espeak-ng/espeak-ng
- Release: tag `1.52.0` (released 2024-12-12; the newest stable release as of October 2026), commit
  `4870adfa25b1a32b4361592f1be8a40337c58d6c`.
- The release on GitHub has no source tarball asset, so the tarball is a `git archive` of the tag:

  ```
  git clone --branch 1.52.0 https://github.com/espeak-ng/espeak-ng
  git -C espeak-ng archive --format=tar --prefix=espeak-ng-1.52.0/ -o espeak-ng-1.52.0.tar 1.52.0
  xz -9 -k espeak-ng-1.52.0.tar
  ```

| File | Bytes | sha256 |
|---|---|---|
| `source/espeak-ng-1.52.0.tar.xz` | 12,286,672 | 718fce9eb9d2c5c46281daf9084fd1d44da9c181b182ee090f504e46177cf383 |
| (uncompressed `espeak-ng-1.52.0.tar`, git 2.56.0) | 64,286,720 | f9166e82e6753bce499e104db5827fdcc127f237f9f7cf89a83b9573f10b11d8 |

## Build

- Emscripten 6.0.13 (emsdk `install 6.0.13`), its bundled Node 24.19.0 to run the data compiler, CMake 4.4.4 and
  Ninja 1.13.2 (from `pip install --user cmake ninja`), Python 3.12, on Windows 11. No host C compiler.
- Script: `source/build.py` (the same file as `scripts/espeak/build.py` in the 2tool repository), with `source/glue.c`
  next to it (`scripts/espeak/glue.c`). Command used:

  ```
  python scripts/espeak/build.py --emsdk <emsdk folder> --work <temp folder> --jobs 2
  ```

  It checks the tarball's sha256, unpacks it, and then:

  1. `emcmake cmake -G Ninja` on espeak-ng's own CMake build with `-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF
     -DUSE_ASYNC=OFF -DUSE_MBROLA=OFF -DUSE_LIBPCAUDIO=OFF -DUSE_KLATT=OFF -DUSE_SPEECHPLAYER=OFF -DUSE_LIBSONIC=OFF`
     (`SONIC_LIB`/`SONIC_INC` set to a placeholder so CMake does not download sonic), C flags
     `-D_POSIX_C_SOURCE=200809L -DM_PI=3.14159265358979323846` (musl declares `iswalnum()` etc. with `wint_t`, an `int`
     on wasm32, which clashes with espeak-ng's compat `<wctype.h>`; plain POSIX keeps those declarations out, and
     `M_PI` is then supplied by hand), and link flags `-sNODERAWFS=1 -sALLOW_MEMORY_GROWTH=1 -sSTACK_SIZE=5MB
     -sEXIT_RUNTIME=1` for the command-line tool.
  2. `ninja -j2 espeak-ng-bin`: `libespeak-ng.a`, `libucd.a`, and the `espeak-ng` tool as `espeak-ng.js` for Node.
  3. The data, as `cmake/data.cmake` does, with that tool under Node (`node espeak-ng.js --path=<data>`):
     `--compile-intonations` and `--compile-phonemes` in a copy of `phsource/`, then `--compile=<lang>` for each
     dictionary in a folder holding its `_rules`, `_list`, `_listx` and `_emoji` files.
  4. The web module: `emcc glue.c libespeak-ng.a libucd.a -O3 -sMODULARIZE=1 -sEXPORT_ES6=1
     -sEXPORT_NAME=createEspeak -sENVIRONMENT=web,worker,node -sALLOW_MEMORY_GROWTH=1 -sSTACK_SIZE=5MB
     -sFORCE_FILESYSTEM=1 -sEXIT_RUNTIME=0 -sEXPORTED_FUNCTIONS=_tt_init,_tt_set_voice,_tt_ipa,_tt_voices,_malloc,_free
     -sEXPORTED_RUNTIME_METHODS=FS,UTF8ToString,stringToUTF8,lengthBytesUTF8 -o espeak-ng.mjs`. No threads, no
     cross-origin isolation needed.
  5. Copies the data for the chosen languages, `manifest.json` (file list, voices and their dictionaries), `COPYING`
     from the tarball, Emscripten's `LICENSE` and musl's `COPYRIGHT`, and the script and glue into `source/`.

## Languages

Dictionaries `en`, `es`, `fr`, `hi`, `it`, `pt` with these voices (files under `espeak-ng-data/lang/`):

| Dictionary | Bytes | Voices |
|---|---|---|
| `en_dict` | 168,204 | gmw/en (en-gb, en), gmw/en-US (en-us), gmw/en-GB-x-rp, gmw/en-GB-scotland, gmw/en-GB-x-gbclan, gmw/en-GB-x-gbcwmd, gmw/en-029, gmw/en-US-nyc |
| `es_dict` | 49,285 | roa/es (es), roa/es-419 (es-419, es-mx) |
| `fr_dict` | 63,727 | roa/fr (fr-fr, fr), roa/fr-BE, roa/fr-CH |
| `hi_dict` | 92,143 | inc/hi (hi) |
| `it_dict` | 154,408 | roa/it (it) |
| `pt_dict` | 76,389 | roa/pt (pt, pt-pt), roa/pt-BR (pt-br) |

Shared by all: `phondata` 554,740, `phontab` 58,652, `phonindex` 43,316, `intonations` 2,312 bytes.
Module: `espeak-ng.wasm` 351,775 and `espeak-ng.mjs` 60,118 bytes. The whole folder without `source/` is about
1.7 MB; English alone (module, shared data, `en_dict`) is about 1.2 MB. Another espeak-ng language can be added by
putting it in `LANGS` in the build script and rebuilding.

## Use

`phonemize.js` (ES module; in a module Worker, on a page, or in Node 20+):

- `phonemize(text, language = 'en-us')` → `Promise<string[]>`, one IPA string per clause, as
  `espeak-ng --ipa -q -v <language>` prints them, e.g. `phonemize('Hello world.')` → `['həlˈoʊ wˈɜːld']`,
  `phonemize('Hello world.', 'en-gb')` → `['həlˈəʊ wˈɜːld']`. The language is a voice identifier or a language listed
  by a voice (en-us, en-gb, en, es, fr-fr, hi, it, pt-br, ...). It is chosen as the `-v` option does: by voice file
  name first, then by language.
- `languages()` → the included voices as espeak-ng lists them: `{identifier, name, languages: [{name, priority}]}`.
- `list_voices(language?)`: the same, filtered like xenova's `list_voices`.

The first call loads the module, the shared data and English; other dictionaries load the first time their language
is used. Data is fetched next to `phonemize.js` (or read from disk for `file:` URLs in Node).

Differences from xenova's `phonemizer` 1.2.1: its espeak-ng build is of unrecorded source and only has English; there,
`phonemize(text, 'en-gb')` silently keeps the previous voice because 1.52 has no voice file named `en-gb`; here it
selects the British voice (`gmw/en`) as the espeak-ng command line does.
