From f9f1c454d5933241485c31cae723e00b4c4a4812 Mon Sep 17 00:00:00 2001 From: Fisto Date: Wed, 16 Sep 2026 12:57:05 +0200 Subject: [PATCH] latency: cache profile writes; docs: data2 resolved, latency and fade measurements --- README.md | 6 ++++-- docs/NOTES.md | 21 +++++++++++++++++++-- docs/TTS-DESIGN.md | 23 ++++++++++++++++++----- setup/veskslop-tts.sh | 25 +++++++++++++++++++------ 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8936ccc..5f56a4d 100644 --- a/README.md +++ b/README.md @@ -110,8 +110,10 @@ wrapper, so the WebUI does not need to implement them. See `docs/TTS-DESIGN.md`. windows. - Flextalk numeric speaker settings must be `REG_DWORD` (the installer script handles this); `REG_SZ` values cause a monotone buzz. Pitch and speed work on all voices. -- The Flextalk archive lacks `data2.cab`; `unshield -O` extracts `data1.cab` - but one tail file (`WatsonUNInstall.dll`) is incomplete. +- Flextalk extraction needs `unshield -O` (old compression). The installer is + single-volume: the new decompressor reports a phantom `data2.cab`, but `-O` extracts + all 450 entries with exact sizes and valid PE files (the original 1997 upload log lists + `data1.cab` only). ## Reference material diff --git a/docs/NOTES.md b/docs/NOTES.md index 754921a..5c92ff7 100644 --- a/docs/NOTES.md +++ b/docs/NOTES.md @@ -47,8 +47,25 @@ From `msttsl/mstts.inf` (`[TTSReg]`): `.COD` codebook, plus shared `DICT_CI.*`, `phondef`, `AMPRULES`, `ENDINGS`. Extraction: `unshield -O -d extracted x installer/flextalk/data1.cab` -(`-O` = old compression; the archive.org package has no `data2.cab`, so the -final file `WatsonUNInstall.dll` is incomplete). +(`-O` = old compression). The package is single-volume: the original 1997 upload log +(`WS_FTP.LOG`) lists `data1.cab` only, and `-O` extracts all 450 entries with exact +sizes. Without `-O`, unshield's new decompressor reports a phantom "volume 2" and fails +on `MSVCRT.DLL` / `WatsonUNInstall.dll`; with `-O` both are complete, valid PE files. + +The `.ENV` files the engine probes (`ae1m11lc.ENV`) were never shipped; synthesis works +without them. + +## Latency and output shape (measured 2026-09-16) + +- Warm wrapper time: ~410-425 ms per short line (engine call 190-220 ms, ffmpeg measure + ~110 ms, apply ~90 ms, profile write ~57 ms when it runs). First (cold) call ~730 ms. +- The Flextalk profile write is cached per voice in the Wine prefix + (`~/.wine-microslopsam/.microslopsam-profile.reg`): unchanged profiles skip + `wine reg import`. Recreating the prefix invalidates the cache. +- Fades: the 8 ms fade-in/out is applied to the trimmed file whose 25-30 ms padding + silence is retained, so it shapes silence, not speech. Measured head: first sample + >30 at 22.6 ms, speech (>500) at 29.6 ms, natural ~15 ms attack; tail decays over + ~18 ms. No click, no attenuation of the first word. ## SAPI4 runtime engine discovery (`speech.dll`) diff --git a/docs/TTS-DESIGN.md b/docs/TTS-DESIGN.md index 99fe98f..558d358 100644 --- a/docs/TTS-DESIGN.md +++ b/docs/TTS-DESIGN.md @@ -229,6 +229,11 @@ record what the engine needs to interpret, add, or hide._ - Verified: Keith Bell -18.4 LUFS, Kerry Watson -17.9 LUFS, Sam -20.6 LUFS; every file is 48 kHz mono s16le at -3.0 dBFS true peak. The WAV handed to Veskslop is compliant; the "Veskslop does not normalize" rule holds. +- Fades: the 8 ms fade-in/out is applied to the trimmed file, and the retained 25-30 ms + padding silence sits at the edges, so the fade shapes silence, not the first phoneme. + Measured on a Keith Bell line: first sample >30 at 22.6 ms, speech (>500) at 29.6 ms, + attack rising naturally over about 15 ms, tail decaying over about 18 ms. No click and + no attenuation of the first word; Veskslop's 150 ms playback lead-in sits on top. ### Voice IDs @@ -451,11 +456,15 @@ This tree is written to survive a copy into the Veskslop repository next to its text file, transliterates UTF-8 to CP1252, starts or reuses an Xvfb when `DISPLAY` is unset, calls the engine, then post-processes (trim, fades, measured fixed gain, 48 kHz mono s16le). A stale private Xvfb is retried once. -- Measured on the dev host: engine-only synthesis is about 290 ms wall for Sam and about - 40 ms for Flextalk, including process start; the full wrapper adds the ffmpeg - measure/apply passes, about 630-880 ms per short line. That is above the 500 ms target; - the known optimization is a per-voice static gain (skip the measurement pass), expected - to land around 400-500 ms. +- Measured on the dev host (warm): engine call about 190 ms (Flextalk) to 220 ms (Sam) + including Wine start, ffmpeg measure about 110 ms, ffmpeg apply about 90 ms, profile + registry write about 57 ms when it runs. Full wrapper: about 410-425 ms per short line + warm, about 730 ms for the first (cold) call. The 500 ms target is met warm; Veskslop's + "Start engine" warm-up covers the cold case. +- Latency optimization implemented: the Flextalk profile write is cached per voice inside + the Wine prefix (`.microslopsam-profile.reg`); an unchanged profile skips the + `wine reg import` round-trip (about 57 ms warm, 300 ms cold). Recreating the prefix + invalidates the cache automatically. - Manual checks: `setup/run.sh -l`, `setup/run.sh -v "Keith Bell" -t "Hello." -o out.wav` (raw engine WAV), and the wrapper above for normalized output. - HTTP provider (later): a persistent process returning `audio/wav` bytes and `/voices`, @@ -465,6 +474,10 @@ This tree is written to survive a copy into the Veskslop repository next to its - Flextalk numeric speaker settings must be `REG_DWORD`; `REG_SZ` values make the engine synthesize a buzz. `setup/setup-flextalk.sh` writes them correctly. +- Flextalk cabinet is single-volume: `unshield -O` extracts all 450 entries with exact + sizes. Without `-O`, the new decompressor reports a phantom "volume 2" and fails on + `MSVCRT.DLL` / `WatsonUNInstall.dll`; both are complete with `-O` (verified against the + original 1997 upload log, which lists `data1.cab` only). - The mode list includes TruVoice names with no installed voice data; filter those out of `/voices` (or mark them `unavailable`). - Wine needs a working X display; the project helper starts a persistent Xvfb. diff --git a/setup/veskslop-tts.sh b/setup/veskslop-tts.sh index 44fec36..929f690 100755 --- a/setup/veskslop-tts.sh +++ b/setup/veskslop-tts.sh @@ -233,13 +233,26 @@ if [ -n "$SPEAKER_GUID" ]; then exit 1 fi - if ! command -v "$MICROSLOP_WINE" >/dev/null 2>&1; then - echo "wine is required to set the Flextalk profile" >&2 - exit 1 + # Skip the wine round-trip when this voice's profile was already applied. + # The cache lives inside the prefix, so recreating the prefix invalidates + # it automatically. + PROFILE_CACHE="$WINEPREFIX/.microslopsam-profile$SPEAKER_GUID.reg" + if [ -f "$PROFILE_CACHE" ] && cmp -s "$TMP/profile.reg" "$PROFILE_CACHE"; then + PROFILE_APPLIED=1 + else + PROFILE_APPLIED=0 fi - if ! "$MICROSLOP_WINE" reg import "$TMP/profile.reg" >/dev/null 2>&1; then - echo "could not write the Flextalk profile" >&2 - exit 1 + + if [ "$PROFILE_APPLIED" != "1" ]; then + if ! command -v "$MICROSLOP_WINE" >/dev/null 2>&1; then + echo "wine is required to set the Flextalk profile" >&2 + exit 1 + fi + if ! "$MICROSLOP_WINE" reg import "$TMP/profile.reg" >/dev/null 2>&1; then + echo "could not write the Flextalk profile" >&2 + exit 1 + fi + cp -f "$TMP/profile.reg" "$PROFILE_CACHE" 2>/dev/null || true fi fi