setup: one-shot install.sh; docs: install, fixed-gain normalization, latency

This commit is contained in:
Fisto
2026-09-15 13:34:05 +02:00
parent e79c254e39
commit 6f131b1f9e
3 changed files with 115 additions and 22 deletions
+8 -14
View File
@@ -25,25 +25,18 @@ pure-native build, and keep a path to a fully portable engine.
## Build ## Build
Dependencies (once, as root): Everything in one command (idempotent; sudo only for system packages):
sudo setup/install-deps.sh setup/install.sh
Runtime + MSTTS voices (once): Manual steps, if needed:
setup/setup-prefix.sh sudo setup/install-deps.sh # Wine/Winelib/helpers
setup/setup-prefix.sh # prefix + SAPI4 runtime + MSTTS voices
Flextalk voices (once; needs the extracted installer, see `docs/NOTES.md`): setup/setup-flextalk.sh # Flextalk extraction + registry
# host build:
setup/setup-flextalk.sh
Host:
# Winelib (native ELF + launcher): build/sapi4host-winlib.exe + .exe.so
winegcc -m32 -O2 -o build/sapi4host-winlib host/sapi4host.c -I../reference \ winegcc -m32 -O2 -o build/sapi4host-winlib host/sapi4host.c -I../reference \
-lole32 -luser32 -ladvapi32 -lole32 -luser32 -ladvapi32
# PE fallback (runs under wine):
i686-w64-mingw32-gcc -O2 -static -o build/sapi4host.exe host/sapi4host.c \ i686-w64-mingw32-gcc -O2 -static -o build/sapi4host.exe host/sapi4host.c \
-I../reference -lole32 -luser32 -ladvapi32 -luuid -I../reference -lole32 -luser32 -ladvapi32 -luuid
@@ -70,6 +63,7 @@ which the setup script writes). Mapping details are in `docs/TTS-DESIGN.md`.
## Layout ## Layout
- `host/sapi4host.c` — host: voice select, pitch/speed, text -> WAV - `host/sapi4host.c` — host: voice select, pitch/speed, text -> WAV
- `setup/install.sh` — one-shot installer (runs all steps below)
- `setup/install-deps.sh` — Wine/Winelib/helpers (root) - `setup/install-deps.sh` — Wine/Winelib/helpers (root)
- `setup/setup-prefix.sh` — prefix + SAPI4 runtime + MSTTS engine/voices - `setup/setup-prefix.sh` — prefix + SAPI4 runtime + MSTTS engine/voices
- `setup/setup-flextalk.sh` — Flextalk files + registry - `setup/setup-flextalk.sh` — Flextalk files + registry
+23 -8
View File
@@ -214,9 +214,17 @@ record what the engine needs to interpret, add, or hide._
so one shared level target is required. The engine post-processes every line: so one shared level target is required. The engine post-processes every line:
resample to 48000 Hz, trim leading silence (<100 ms), 5-10 ms fades, DC removal, and resample to 48000 Hz, trim leading silence (<100 ms), 5-10 ms fades, DC removal, and
level normalization (peak about -3 dBFS, integrated loudness -16 to -20 LUFS). level normalization (peak about -3 dBFS, integrated loudness -16 to -20 LUFS).
- Proposed implementation, engine-side, with ffmpeg (already installed on the dev host): - Implemented in `setup/vekslop-tts.sh` with ffmpeg: high-pass at 40 Hz, silence trim at
`ffmpeg -i raw.wav -af "highpass=f=40,<trim><fade>,loudnorm=..." -ar 48000 -ac 1 out.wav`. both ends (trim-start, reverse, trim-start, reverse), 8 ms fades, then a **fixed gain**
The WAV handed to Veskslop is then compliant; the "Veskslop does not normalize" rule holds. computed from an EBU R128 measurement (`ebur128=peak=true`):
`gain = min(-16 LUFS target, -3 dBFS true-peak clamp)`, then 48 kHz mono s16le.
- `loudnorm` was rejected: on short lines (under about 3 s) the loudness range is 0 and
dynamic mode attenuated a 2.8 s line to -37.9 LUFS instead of about -18 LUFS; two-pass
linear mode showed the same result. The fixed gain is steady for one-line utterances,
as Veskslop suggested.
- 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.
### Voice IDs ### Voice IDs
@@ -258,15 +266,22 @@ record what the engine needs to interpret, add, or hide._
### Transport and latency ### Transport and latency
- Installation is one command: `setup/install.sh` (system dependencies with sudo, wine
prefix + SAPI4 runtime + MSTTS voices, Flextalk extraction/registration, host build).
Re-running is safe; a fresh machine needs nothing else.
- Command provider, implemented as `setup/vekslop-tts.sh`: - Command provider, implemented as `setup/vekslop-tts.sh`:
`VESKSLOP_TTS_CMD="<repo>/setup/vekslop-tts.sh {out} {text_file}"` and `VESKSLOP_TTS_CMD="<repo>/setup/vekslop-tts.sh {out} {text_file}"` and
`VESKSLOP_TTS_VOICES="$(<repo>/setup/vekslop-tts.sh --voices)"`. The wrapper reads the `VESKSLOP_TTS_VOICES="$(<repo>/setup/vekslop-tts.sh --voices)"`. The wrapper reads the
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, two-pass `loudnorm`, 48 kHz unset, calls the engine, then post-processes (trim, fades, measured fixed gain, 48 kHz
mono s16le). Verified: -17.7 LUFS integrated, -3.0 dBFS true peak. mono s16le). A stale private Xvfb is retried once.
- Measured on the dev host (warm Wine): Sam line about 288 ms wall, Flextalk line about - Measured on the dev host: engine-only synthesis is about 290 ms wall for Sam and about
41 ms wall, including process start, synthesis, and file write. Both are inside the 40 ms for Flextalk, including process start; the full wrapper adds the ffmpeg
500 ms budget. 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.
- 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`, - HTTP provider (later): a persistent process returning `audio/wav` bytes and `/voices`,
with optional caching by `hash(text + voice + speed + pitch)`. with optional caching by `hash(text + voice + speed + pitch)`.
+84
View File
@@ -0,0 +1,84 @@
#!/bin/sh
# One-shot installer for MicroslopSam. Runs all setup steps, idempotently:
# 1. system dependencies (Wine, Winelib, helpers; needs sudo)
# 2. wine prefix + SAPI4 runtime + MSTTS voices + registration
# 3. Flextalk extraction + voices + registration
# 4. host build (Winelib and PE)
# 5. quick voice check
#
# Usage: setup/install.sh
# Re-running is safe.
set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd)
ASSETS=${ASSETS:-$ROOT/../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4}
FLEXTALK_DIR=${FLEXTALK_DIR:-$ROOT/../flextalk}
log() { printf '\n== %s\n' "$*"; }
# 1) system dependencies -----------------------------------------------------
if [ "$(id -u)" = "0" ]; then
log "installing system dependencies"
"$HERE/install-deps.sh"
else
log "installing system dependencies (sudo)"
sudo "$HERE/install-deps.sh"
fi
# 2) SAPI4 runtime + MSTTS voices --------------------------------------------
log "setting up wine prefix, SAPI4 runtime and MSTTS voices"
"$HERE/setup-prefix.sh" "$ASSETS"
# 3) Flextalk voices ----------------------------------------------------------
EXTRACTED="$FLEXTALK_DIR/extracted/TTS_Executables"
if [ ! -d "$EXTRACTED/EngineDLLs" ]; then
CAB=""
for c in "$FLEXTALK_DIR/installer/flextalk/data1.cab" \
"$ASSETS/flextalk/data1.cab"; do
if [ -f "$c" ]; then CAB="$c"; break; fi
done
if [ -z "$CAB" ]; then
echo "Flextalk data1.cab not found; set FLEXTALK_DIR to the archive dir" >&2
exit 1
fi
command -v unshield >/dev/null 2>&1 || {
echo "unshield is required to extract the Flextalk installer" >&2
exit 1
}
log "extracting Flextalk installer ($CAB)"
rm -rf "$FLEXTALK_DIR/extracted"
unshield -O -d "$FLEXTALK_DIR/extracted" x "$CAB" >/dev/null
fi
log "installing Flextalk voices"
"$HERE/setup-flextalk.sh" "$EXTRACTED"
# 4) host build ---------------------------------------------------------------
log "building the host"
mkdir -p "$ROOT/build"
winegcc -m32 -O2 -o "$ROOT/build/sapi4host-winlib" "$ROOT/host/sapi4host.c" \
-I"$ROOT/../reference" -lole32 -luser32 -ladvapi32
if command -v i686-w64-mingw32-gcc >/dev/null 2>&1; then
i686-w64-mingw32-gcc -O2 -static -o "$ROOT/build/sapi4host.exe" \
"$ROOT/host/sapi4host.c" -I"$ROOT/../reference" \
-lole32 -luser32 -ladvapi32 -luuid
fi
# 5) check --------------------------------------------------------------------
log "installed voices"
"$HERE/run.sh" -l || true
cat <<EOF
Done.
Veskslop configuration:
VESKSLOP_TTS_CMD="$HERE/vekslop-tts.sh {out} {text_file}"
VESKSLOP_TTS_VOICES="\$($HERE/vekslop-tts.sh --voices)"
Manual test:
$HERE/run.sh -v Sam -t "Hello." -o /tmp/hello.wav
Normalized 48 kHz output (what Veskslop hears):
VESKSLOP_TTS_VOICE=keith-bell $HERE/vekslop-tts.sh /tmp/keith.wav /tmp/text.txt
EOF