Shared eSpeak-ng phonemizer for model frontends - #502
Conversation
|
Pushed commit 4d44495 with the static eSpeak-ng integration and executable-adjacent espeak-ng-data.bin package. The PR description now documents the architecture, compatibility behavior, extraction cache, validation results. |
|
I think is ready .... now we have a unified platform for using audio models based on eSpeak-ng. |
|
@mirek190 PR merged! Super clean refactor (PI + Qwen 😄 ?), and this is a big step. I’m now more comfortable taking in more phoneme-based models. Glad you made static eSpeak opt-in. GPL-3.0 is viral. |
For that one I used codex-cli ;-) |
Merge of PR #33 (8 upstream commits). Head-on collision resolved: upstream 0xShug0#502 introduced a shared EspeakPhonemizer with a process-global Service singleton (per-instance phonemizer objects hold only config; nothing tears down eSpeak per model), which subsumes the fork's espeak_lifetime.h refcount fix for the multi-voice LRU SIGSEGV observed in sound-rs — the crashing code path (per-instance espeak_Terminate + FreeLibrary) no longer exists. Resolution: take upstream's sanotts/inflect_v2 frontends verbatim, delete the fork's espeak_lifetime.h and its unit test. CMakeLists conflict: keep both the fork-only embed blocks (VAD + audio utilities incl. GTCRN) and upstream's new AUDIOCPP_STATIC_ESPEAK hook. Also brings Sortformer v2.1 streaming diarization (new community model), Colab WebUI notebook + CUDA T4 release build (0xShug0#501), Vulkan fill dispatch fix (0xShug0#508), fish_audio HIP stream perf (0xShug0#500), voxtral warmbench fix. fork_regression 10/10 green, loader catalog in sync, embed intact (~34.8MB .rdata). Generated-by: zcode
Summary
This PR introduces a reusable
engine::audio::EspeakPhonemizer, migrates SanoTTS and Inflect v2 to it, and adds an optional self-contained eSpeak-ng build for the CLI and server.The default build behavior remains unchanged: users can provide an installed shared eSpeak-ng library and matching data. With
AUDIOCPP_STATIC_ESPEAK=ON, audio.cpp downloads the pinned eSpeak-ng 1.52.0 source archive, verifies its SHA-256, builds it statically, and links the phonemizer code into both executables. Noespeak-ng.dllorlibespeak-ng.sois required in that configuration.Shared phonemizer runtime
SanoTTS's E2M and Piper paths and Inflect v2 now share this implementation. Kokoro remains in its separate preview work and is not migrated by this PR.
Optional static eSpeak-ng integration
Configure with:
cmake -S . -B build/static-espeak -DAUDIOCPP_STATIC_ESPEAK=ON cmake --build build/static-espeak --config Release --target audiocpp_cli audiocpp_serverThe integration builds eSpeak in an isolated CMake project and disables components unnecessary for phonemization: Sonic, audio playback, MBROLA, asynchronous synthesis, and speechPlayer. The upstream host tool compiles the phoneme tables and all 114 language dictionaries. Cross-compiling this option is currently rejected because data generation requires a runnable host tool.
The resulting executable directory contains:
The license directory includes upstream COPYING, the verified source archive, the integration scripts, and documentation needed to reproduce the bundled component.
Separate eSpeak data package
espeak-ng-data.bincontains the compiled dictionaries and phoneme tables. It is not a neural model and contains no weights or audio recordings. Internally it uses audio.cpp's embedded-file GGUF metadata layout with zero tensors, but the.binname distinguishes this shared runtime resource from downloadable model GGUFs.The build creates and stages this file automatically; users do not need to run the packer manually. Both CLI and server locate it beside their executable. For backward compatibility, the runtime also accepts
espeak-ng-data.gguf, an unpackedespeak-ng-datadirectory, or an explicit modelespeak_data_pathpointing to any of those forms.The package is about 17.5 MiB and currently uncompressed.
audiocpp_espeak_packis also available for manually repacking compatible eSpeak-ng 1.52.0 data.Safe shared extraction cache
eSpeak itself requires ordinary filesystem data, so the package is materialized into a per-user cache shared by CLI and server:
%LOCALAPPDATA%/audio.cpp/espeak-data/$XDG_CACHE_HOME/audio.cpp/espeak-data/, falling back to$HOME/.cache/audio.cpp/espeak-data/Cache entries are content-keyed and fully compared before reuse. Extraction validates package metadata, file counts, required files, byte ranges, portable paths, duplicate/case-colliding names, traversal attempts, symlinks, and unsupported versions. A complete staging directory is published atomically, so concurrent processes cannot observe partially extracted data. Changed packages or damaged cache entries create a new revision rather than modifying files another process may be using.
Automatic cache eviction is not included; old entries can be removed while no audio.cpp process is using them.
Validation
Tested on Windows x64 with MSVC 19.43 in a Release CPU build using eSpeak-ng 1.52.0:
audiocpp_cliandaudiocpp_serverbuild successfully.espeak-ng-data.binpasses the same 21/21 comparison..ggufcompatibility, and path-traversal rejection.git diff --checkpasses.Not tested on Linux and macOS