diff --git a/README.md b/README.md index 97342cc..aa0b3bd 100644 --- a/README.md +++ b/README.md @@ -25,25 +25,18 @@ pure-native build, and keep a path to a fully portable engine. ## 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 - -Flextalk voices (once; needs the extracted installer, see `docs/NOTES.md`): - - setup/setup-flextalk.sh - -Host: - - # Winelib (native ELF + launcher): build/sapi4host-winlib.exe + .exe.so + sudo setup/install-deps.sh # Wine/Winelib/helpers + setup/setup-prefix.sh # prefix + SAPI4 runtime + MSTTS voices + setup/setup-flextalk.sh # Flextalk extraction + registry + # host build: winegcc -m32 -O2 -o build/sapi4host-winlib host/sapi4host.c -I../reference \ -lole32 -luser32 -ladvapi32 - - # PE fallback (runs under wine): i686-w64-mingw32-gcc -O2 -static -o build/sapi4host.exe host/sapi4host.c \ -I../reference -lole32 -luser32 -ladvapi32 -luuid @@ -70,6 +63,7 @@ which the setup script writes). Mapping details are in `docs/TTS-DESIGN.md`. ## Layout - `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/setup-prefix.sh` — prefix + SAPI4 runtime + MSTTS engine/voices - `setup/setup-flextalk.sh` — Flextalk files + registry diff --git a/docs/TTS-DESIGN.md b/docs/TTS-DESIGN.md index 8bdd289..3092a39 100644 --- a/docs/TTS-DESIGN.md +++ b/docs/TTS-DESIGN.md @@ -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: 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). -- Proposed implementation, engine-side, with ffmpeg (already installed on the dev host): - `ffmpeg -i raw.wav -af "highpass=f=40,,loudnorm=..." -ar 48000 -ac 1 out.wav`. - The WAV handed to Veskslop is then compliant; the "Veskslop does not normalize" rule holds. +- Implemented in `setup/vekslop-tts.sh` with ffmpeg: high-pass at 40 Hz, silence trim at + both ends (trim-start, reverse, trim-start, reverse), 8 ms fades, then a **fixed gain** + 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 @@ -258,15 +266,22 @@ record what the engine needs to interpret, add, or hide._ ### 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`: `VESKSLOP_TTS_CMD="/setup/vekslop-tts.sh {out} {text_file}"` and `VESKSLOP_TTS_VOICES="$(/setup/vekslop-tts.sh --voices)"`. The wrapper reads the 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 - mono s16le). Verified: -17.7 LUFS integrated, -3.0 dBFS true peak. -- Measured on the dev host (warm Wine): Sam line about 288 ms wall, Flextalk line about - 41 ms wall, including process start, synthesis, and file write. Both are inside the - 500 ms budget. + 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. +- 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`, with optional caching by `hash(text + voice + speed + pitch)`. diff --git a/setup/install.sh b/setup/install.sh new file mode 100755 index 0000000..b4f4852 --- /dev/null +++ b/setup/install.sh @@ -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 <