latency: cache profile writes; docs: data2 resolved, latency and fade measurements

This commit is contained in:
Fisto
2026-09-16 12:57:05 +02:00
parent 928218bd9c
commit f9f1c454d5
4 changed files with 60 additions and 15 deletions
+4 -2
View File
@@ -110,8 +110,10 @@ wrapper, so the WebUI does not need to implement them. See `docs/TTS-DESIGN.md`.
windows. windows.
- Flextalk numeric speaker settings must be `REG_DWORD` (the installer script handles - 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. 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` - Flextalk extraction needs `unshield -O` (old compression). The installer is
but one tail file (`WatsonUNInstall.dll`) is incomplete. 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 ## Reference material
+19 -2
View File
@@ -47,8 +47,25 @@ From `msttsl/mstts.inf` (`[TTSReg]`):
`.COD` codebook, plus shared `DICT_CI.*`, `phondef`, `AMPRULES`, `ENDINGS`. `.COD` codebook, plus shared `DICT_CI.*`, `phondef`, `AMPRULES`, `ENDINGS`.
Extraction: `unshield -O -d extracted x installer/flextalk/data1.cab` Extraction: `unshield -O -d extracted x installer/flextalk/data1.cab`
(`-O` = old compression; the archive.org package has no `data2.cab`, so the (`-O` = old compression). The package is single-volume: the original 1997 upload log
final file `WatsonUNInstall.dll` is incomplete). (`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<GUID>.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`) ## SAPI4 runtime engine discovery (`speech.dll`)
+18 -5
View File
@@ -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 - 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 48 kHz mono s16le at -3.0 dBFS true peak. The WAV handed to Veskslop is compliant; the
"Veskslop does not normalize" rule holds. "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 ### 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 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 unset, calls the engine, then post-processes (trim, fades, measured fixed gain, 48 kHz
mono s16le). A stale private Xvfb is retried once. 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 - Measured on the dev host (warm): engine call about 190 ms (Flextalk) to 220 ms (Sam)
40 ms for Flextalk, including process start; the full wrapper adds the ffmpeg including Wine start, ffmpeg measure about 110 ms, ffmpeg apply about 90 ms, profile
measure/apply passes, about 630-880 ms per short line. That is above the 500 ms target; registry write about 57 ms when it runs. Full wrapper: about 410-425 ms per short line
the known optimization is a per-voice static gain (skip the measurement pass), expected warm, about 730 ms for the first (cold) call. The 500 ms target is met warm; Veskslop's
to land around 400-500 ms. "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<GUID>.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` - 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. (raw engine WAV), and the wrapper above for normalized output.
- HTTP provider (later): a persistent process returning `audio/wav` bytes and `/voices`, - 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 - Flextalk numeric speaker settings must be `REG_DWORD`; `REG_SZ` values make the engine
synthesize a buzz. `setup/setup-flextalk.sh` writes them correctly. 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 - The mode list includes TruVoice names with no installed voice data; filter those out of
`/voices` (or mark them `unavailable`). `/voices` (or mark them `unavailable`).
- Wine needs a working X display; the project helper starts a persistent Xvfb. - Wine needs a working X display; the project helper starts a persistent Xvfb.
+19 -6
View File
@@ -233,13 +233,26 @@ if [ -n "$SPEAKER_GUID" ]; then
exit 1 exit 1
fi fi
if ! command -v "$MICROSLOP_WINE" >/dev/null 2>&1; then # Skip the wine round-trip when this voice's profile was already applied.
echo "wine is required to set the Flextalk profile" >&2 # The cache lives inside the prefix, so recreating the prefix invalidates
exit 1 # 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 fi
if ! "$MICROSLOP_WINE" reg import "$TMP/profile.reg" >/dev/null 2>&1; then
echo "could not write the Flextalk profile" >&2 if [ "$PROFILE_APPLIED" != "1" ]; then
exit 1 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
fi fi