Configurable paths (config.sh + generated env), vendored speech.h, merge docs

This commit is contained in:
Fisto
2026-09-16 08:38:19 +02:00
parent 6d010292f2
commit 805c960a4a
11 changed files with 6841 additions and 73 deletions
+1
View File
@@ -6,3 +6,4 @@ build/
*.dll *.dll
setup/out-*.reg setup/out-*.reg
*.wav *.wav
setup/microslopsam.env
+23 -3
View File
@@ -35,10 +35,29 @@ Manual steps, if needed:
setup/setup-prefix.sh # prefix + SAPI4 runtime + MSTTS voices setup/setup-prefix.sh # prefix + SAPI4 runtime + MSTTS voices
setup/setup-flextalk.sh # Flextalk extraction + registry setup/setup-flextalk.sh # Flextalk extraction + registry
# host build: # host build:
winegcc -m32 -O2 -o build/sapi4host-winlib host/sapi4host.c -I../reference \ winegcc -m32 -O2 -o build/sapi4host-winlib host/sapi4host.c -Ithird_party \
-lole32 -luser32 -ladvapi32 -lole32 -luser32 -ladvapi32
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 -Ithird_party -lole32 -luser32 -ladvapi32 -luuid
## Configuration
`setup/install.sh` writes `setup/microslopsam.env` (generated, gitignored) with absolute
paths. Environment variables take precedence over the file, so anything can be relocated
without editing scripts:
| Variable | Default | Meaning |
| --- | --- | --- |
| `MICROSLOP_ROOT` | repo root | project root |
| `MICROSLOP_BUILD` | `$MICROSLOP_ROOT/build` | host binaries, samples |
| `MICROSLOP_PREFIX` | `~/.wine-microslopsam` | wine prefix (exported as `WINEPREFIX`) |
| `MICROSLOP_ASSETS` | `../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4` | SAPI4/MSTTS payloads |
| `MICROSLOP_FLEXTALK_DIR` | `../flextalk` | Flextalk archive/extraction |
| `MICROSLOP_SPEECH_H_DIR` | `$MICROSLOP_ROOT/third_party` | `speech.h` include dir (vendored) |
| `MICROSLOP_DISPLAY` | `:77` | Xvfb display used for Wine |
| `MICROSLOP_WINE`, `MICROSLOP_XVFB`, `MICROSLOP_PYTHON`, `MICROSLOP_FFMPEG` | tool names | tool overrides |
Refresh the file after moving the tree: `MICROSLOP_UPDATE_ENV=1 setup/install.sh`.
## Usage ## Usage
@@ -96,8 +115,9 @@ wrapper, so the WebUI does not need to implement them. See `docs/TTS-DESIGN.md`.
## Reference material (not in this repo) ## Reference material (not in this repo)
- `../reference/speech.h` — SAPI4 SDK header - `third_party/speech.h` — SAPI4 SDK header (vendored, so the build is standalone)
- `../reference/SAPI4-CLI`, `../reference/TETYYS-SAPI4` — host examples - `../reference/SAPI4-CLI`, `../reference/TETYYS-SAPI4` — host examples
- `../reference/NetTTS` — VOX parser reference for `setup/vox_parser.py`
- `../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4` — installers/payloads - `../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4` — installers/payloads
- `../flextalk` — Flextalk installer archive + extraction - `../flextalk` — Flextalk installer archive + extraction
- `/mnt/ghidra/decomp/{msttssyn.dll,speech.dll}/` — decompiled corpora - `/mnt/ghidra/decomp/{msttssyn.dll,speech.dll}/` — decompiled corpora
+37
View File
@@ -391,6 +391,43 @@ not need to parse or implement them:
- Verified on the dev host: `/rate 50` doubles the line duration; `/pitch 150` raises - Verified on the dev host: `/rate 50` doubles the line duration; `/pitch 150` raises
the median F0 from 122 Hz to 177 Hz. the median F0 from 122 Hz to 177 Hz.
### Paths and configuration (standalone)
The engine project is standalone: it has no path dependency on Veskslop and only a
default sibling-directory dependency on the asset checkouts, both overridable.
`setup/install.sh` writes `setup/microslopsam.env` with absolute paths; environment
variables take precedence over that file, so anything can be relocated without editing
scripts:
| Variable | Default | Meaning |
| --- | --- | --- |
| `MICROSLOP_ROOT` | repo root | project root |
| `MICROSLOP_BUILD` | `$MICROSLOP_ROOT/build` | host binaries, samples |
| `MICROSLOP_PREFIX` | `~/.wine-microslopsam` | wine prefix (exported as `WINEPREFIX`) |
| `MICROSLOP_ASSETS` | `../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4` | SAPI4/MSTTS payloads |
| `MICROSLOP_FLEXTALK_DIR` | `../flextalk` | Flextalk archive/extraction |
| `MICROSLOP_SPEECH_H_DIR` | `$MICROSLOP_ROOT/third_party` | `speech.h` include dir (vendored) |
| `MICROSLOP_DISPLAY` | `:77` | Xvfb display used for Wine |
| `MICROSLOP_WINE` / `_XVFB` / `_PYTHON` / `_FFMPEG` | tool names | tool overrides |
The wrapper needs only `VESKSLOP_TTS_CMD` to point at its absolute path; it derives
everything else from its own location plus the env file. `speech.h` is vendored in
`third_party/`, so the build no longer needs the SDK checkout.
### Merging into Veskslop
This tree is written to survive a copy into the Veskslop repository next to its daemon:
1. Copy `microslopsam/` (or replace the existing copy), then refresh the configuration:
`MICROSLOP_UPDATE_ENV=1 microslopsam/setup/install.sh`. Re-running install is
idempotent; it rewrites `setup/microslopsam.env` for the new absolute paths.
2. No daemon changes are required. The env/placeholder contract is unchanged
(`VESKSLOP_TTS_*`, `{out}`, `{text_file}`, voice/speed/pitch/expression/profile/
highpass/echo/words/word_gap_ms). New features are additive and default off.
3. Optional Veskslop-side follow-up: a `tts.vox` preference that exports
`VESKSLOP_TTS_VOX` (like `words`) and a line in the TTS panel help. The inline
`/rate` and `/pitch` controls need no UI work at all.
### Transport and latency ### Transport and latency
- Installation is one command: `setup/install.sh` (system dependencies with sudo, wine - Installation is one command: `setup/install.sh` (system dependencies with sudo, wine
+50
View File
@@ -0,0 +1,50 @@
# shellcheck shell=sh
# Shared configuration for MicroslopSam.
#
# Precedence: environment variables > setup/microslopsam.env (generated by
# setup/install.sh) > built-in defaults.
#
# Source this file near the top of every setup script:
# . "$HERE/config.sh"
#
# All values are absolute paths or tool names. Nothing here depends on the
# project living next to other checkouts, with one exception: the asset repo
# and the Flextalk archive default to sibling directories, which is how the
# development tree is laid out. Set MICROSLOP_ASSETS / MICROSLOP_FLEXTALK_DIR
# to point anywhere else.
: "${HERE:?config.sh: set HERE to the setup directory before sourcing}"
if [ -f "$HERE/microslopsam.env" ]; then
# The generated file uses ': ${VAR:=default}' lines, so values already
# present in the environment win over the file.
. "$HERE/microslopsam.env"
fi
MICROSLOP_ROOT=${MICROSLOP_ROOT:-$(CDPATH= cd -- "$HERE/.." && pwd)}
MICROSLOP_BUILD=${MICROSLOP_BUILD:-$MICROSLOP_ROOT/build}
MICROSLOP_PREFIX=${MICROSLOP_PREFIX:-$HOME/.wine-microslopsam}
MICROSLOP_ASSETS=${MICROSLOP_ASSETS:-$MICROSLOP_ROOT/../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4}
MICROSLOP_FLEXTALK_DIR=${MICROSLOP_FLEXTALK_DIR:-$MICROSLOP_ROOT/../flextalk}
MICROSLOP_SPEECH_H_DIR=${MICROSLOP_SPEECH_H_DIR:-$MICROSLOP_ROOT/third_party}
MICROSLOP_DISPLAY=${MICROSLOP_DISPLAY:-:77}
MICROSLOP_XVFB=${MICROSLOP_XVFB:-Xvfb}
MICROSLOP_WINE=${MICROSLOP_WINE:-wine}
MICROSLOP_PYTHON=${MICROSLOP_PYTHON:-python3}
MICROSLOP_FFMPEG=${MICROSLOP_FFMPEG:-ffmpeg}
export MICROSLOP_ROOT MICROSLOP_BUILD MICROSLOP_PREFIX MICROSLOP_ASSETS
export MICROSLOP_FLEXTALK_DIR MICROSLOP_SPEECH_H_DIR MICROSLOP_DISPLAY
export MICROSLOP_XVFB MICROSLOP_WINE MICROSLOP_PYTHON MICROSLOP_FFMPEG
# The wine prefix and arch are what the scripts actually need; keep the
# standard names so callers can override them directly too.
export WINEPREFIX=${WINEPREFIX:-$MICROSLOP_PREFIX}
export WINEARCH=${WINEARCH:-win32}
# Convenience alias for scripts that use $ROOT for repo-relative files.
ROOT=$MICROSLOP_ROOT
# Derived helpers.
MICROSLOP_XSOCK="/tmp/.X11-unix/X${MICROSLOP_DISPLAY#:}"
export MICROSLOP_XSOCK
+51 -22
View File
@@ -1,22 +1,41 @@
#!/bin/sh #!/bin/sh
# One-shot installer for MicroslopSam. Runs all setup steps, idempotently: # One-shot installer for MicroslopSam. Runs all setup steps, idempotently:
# 1. system dependencies (Wine, Winelib, helpers; needs sudo) # 1. record resolved paths in setup/microslopsam.env
# 2. wine prefix + SAPI4 runtime + MSTTS voices + registration # 2. system dependencies (Wine, Winelib, helpers; needs sudo)
# 3. Flextalk extraction + voices + registration # 3. wine prefix + SAPI4 runtime + MSTTS voices + registration
# 4. host build (Winelib and PE) # 4. Flextalk extraction + voices + registration
# 5. quick voice check # 5. host build (Winelib and PE)
# 6. quick voice check
# #
# Usage: setup/install.sh # Paths and tools come from setup/config.sh. Override anything with environment
# Re-running is safe. # variables (they win over setup/microslopsam.env), for example:
# MICROSLOP_ASSETS=/srv/assets MICROSLOP_PREFIX=~/.wine-sam setup/install.sh
# Set MICROSLOP_UPDATE_ENV=1 to rewrite an existing microslopsam.env.
set -eu set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd) . "$HERE/config.sh"
ASSETS=${ASSETS:-$ROOT/../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4}
FLEXTALK_DIR=${FLEXTALK_DIR:-$ROOT/../flextalk}
log() { printf '\n== %s\n' "$*"; } log() { printf '\n== %s\n' "$*"; }
# 0) record the resolved configuration ----------------------------------------
ENVFILE="$HERE/microslopsam.env"
if [ ! -f "$ENVFILE" ] || [ "${MICROSLOP_UPDATE_ENV:-0}" = "1" ]; then
{
echo "# Generated by setup/install.sh -- safe to edit or delete."
echo "# Values are defaults; environment variables take precedence."
printf ': "${MICROSLOP_ROOT:=%s}"\n' "$MICROSLOP_ROOT"
printf ': "${MICROSLOP_BUILD:=%s}"\n' "$MICROSLOP_BUILD"
printf ': "${MICROSLOP_PREFIX:=%s}"\n' "$MICROSLOP_PREFIX"
printf ': "${MICROSLOP_ASSETS:=%s}"\n' "$MICROSLOP_ASSETS"
printf ': "${MICROSLOP_FLEXTALK_DIR:=%s}"\n' "$MICROSLOP_FLEXTALK_DIR"
printf ': "${MICROSLOP_SPEECH_H_DIR:=%s}"\n' "$MICROSLOP_SPEECH_H_DIR"
printf ': "${MICROSLOP_DISPLAY:=%s}"\n' "$MICROSLOP_DISPLAY"
} > "$ENVFILE"
chmod 644 "$ENVFILE" 2>/dev/null || true
log "configuration written to $ENVFILE"
fi
# 1) system dependencies ----------------------------------------------------- # 1) system dependencies -----------------------------------------------------
if [ "$(id -u)" = "0" ]; then if [ "$(id -u)" = "0" ]; then
log "installing system dependencies" log "installing system dependencies"
@@ -28,18 +47,18 @@ fi
# 2) SAPI4 runtime + MSTTS voices -------------------------------------------- # 2) SAPI4 runtime + MSTTS voices --------------------------------------------
log "setting up wine prefix, SAPI4 runtime and MSTTS voices" log "setting up wine prefix, SAPI4 runtime and MSTTS voices"
"$HERE/setup-prefix.sh" "$ASSETS" "$HERE/setup-prefix.sh" "$MICROSLOP_ASSETS"
# 3) Flextalk voices ---------------------------------------------------------- # 3) Flextalk voices ----------------------------------------------------------
EXTRACTED="$FLEXTALK_DIR/extracted/TTS_Executables" EXTRACTED="$MICROSLOP_FLEXTALK_DIR/extracted/TTS_Executables"
if [ ! -d "$EXTRACTED/EngineDLLs" ]; then if [ ! -d "$EXTRACTED/EngineDLLs" ]; then
CAB="" CAB=""
for c in "$FLEXTALK_DIR/installer/flextalk/data1.cab" \ for c in "$MICROSLOP_FLEXTALK_DIR/installer/flextalk/data1.cab" \
"$ASSETS/flextalk/data1.cab"; do "$MICROSLOP_ASSETS/flextalk/data1.cab"; do
if [ -f "$c" ]; then CAB="$c"; break; fi if [ -f "$c" ]; then CAB="$c"; break; fi
done done
if [ -z "$CAB" ]; then if [ -z "$CAB" ]; then
echo "Flextalk data1.cab not found; set FLEXTALK_DIR to the archive dir" >&2 echo "Flextalk data1.cab not found; set MICROSLOP_FLEXTALK_DIR" >&2
exit 1 exit 1
fi fi
command -v unshield >/dev/null 2>&1 || { command -v unshield >/dev/null 2>&1 || {
@@ -47,20 +66,24 @@ if [ ! -d "$EXTRACTED/EngineDLLs" ]; then
exit 1 exit 1
} }
log "extracting Flextalk installer ($CAB)" log "extracting Flextalk installer ($CAB)"
rm -rf "$FLEXTALK_DIR/extracted" rm -rf "$MICROSLOP_FLEXTALK_DIR/extracted"
unshield -O -d "$FLEXTALK_DIR/extracted" x "$CAB" >/dev/null unshield -O -d "$MICROSLOP_FLEXTALK_DIR/extracted" x "$CAB" >/dev/null
fi fi
log "installing Flextalk voices" log "installing Flextalk voices"
"$HERE/setup-flextalk.sh" "$EXTRACTED" "$HERE/setup-flextalk.sh" "$EXTRACTED"
# 4) host build --------------------------------------------------------------- # 4) host build ---------------------------------------------------------------
log "building the host" log "building the host"
mkdir -p "$ROOT/build" [ -f "$MICROSLOP_SPEECH_H_DIR/speech.h" ] || {
winegcc -m32 -O2 -o "$ROOT/build/sapi4host-winlib" "$ROOT/host/sapi4host.c" \ echo "speech.h not found in $MICROSLOP_SPEECH_H_DIR" >&2
-I"$ROOT/../reference" -lole32 -luser32 -ladvapi32 exit 1
}
mkdir -p "$MICROSLOP_BUILD"
winegcc -m32 -O2 -o "$MICROSLOP_BUILD/sapi4host-winlib" "$MICROSLOP_ROOT/host/sapi4host.c" \
-I"$MICROSLOP_SPEECH_H_DIR" -lole32 -luser32 -ladvapi32
if command -v i686-w64-mingw32-gcc >/dev/null 2>&1; then if command -v i686-w64-mingw32-gcc >/dev/null 2>&1; then
i686-w64-mingw32-gcc -O2 -static -o "$ROOT/build/sapi4host.exe" \ i686-w64-mingw32-gcc -O2 -static -o "$MICROSLOP_BUILD/sapi4host.exe" \
"$ROOT/host/sapi4host.c" -I"$ROOT/../reference" \ "$MICROSLOP_ROOT/host/sapi4host.c" -I"$MICROSLOP_SPEECH_H_DIR" \
-lole32 -luser32 -ladvapi32 -luuid -lole32 -luser32 -ladvapi32 -luuid
fi fi
@@ -72,6 +95,12 @@ cat <<EOF
Done. Done.
Configuration: $ENVFILE
MICROSLOP_ROOT=$MICROSLOP_ROOT
MICROSLOP_PREFIX=$MICROSLOP_PREFIX
MICROSLOP_ASSETS=$MICROSLOP_ASSETS
MICROSLOP_FLEXTALK_DIR=$MICROSLOP_FLEXTALK_DIR
Veskslop configuration: Veskslop configuration:
VESKSLOP_TTS_CMD="$HERE/veskslop-tts.sh {out} {text_file}" VESKSLOP_TTS_CMD="$HERE/veskslop-tts.sh {out} {text_file}"
VESKSLOP_TTS_VOICES="\$($HERE/veskslop-tts.sh --voices)" VESKSLOP_TTS_VOICES="\$($HERE/veskslop-tts.sh --voices)"
+8 -10
View File
@@ -1,27 +1,25 @@
#!/bin/sh #!/bin/sh
# Run the SAPI4 host with the project's wine prefix and a working X display. # Run the SAPI4 host with the configured wine prefix and X display.
# Usage: setup/run.sh [sapi4host args...] # Usage: setup/run.sh [sapi4host args...]
set -eu set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd) . "$HERE/config.sh"
export WINEPREFIX=${WINEPREFIX:-$HOME/.wine-microslopsam}
export WINEARCH=win32
if [ -z "${DISPLAY:-}" ]; then if [ -z "${DISPLAY:-}" ]; then
if ! [ -S /tmp/.X11-unix/X77 ]; then if ! [ -S "$MICROSLOP_XSOCK" ]; then
Xvfb :77 -screen 0 1024x768x24 >/dev/null 2>&1 & "$MICROSLOP_XVFB" "$MICROSLOP_DISPLAY" -screen 0 1024x768x24 >/dev/null 2>&1 &
sleep 1 sleep 1
fi fi
export DISPLAY=:77 export DISPLAY=$MICROSLOP_DISPLAY
fi fi
HOST="$ROOT/build/sapi4host-winlib.exe" HOST="$MICROSLOP_BUILD/sapi4host-winlib.exe"
if [ ! -x "$HOST" ]; then if [ ! -x "$HOST" ]; then
HOST="$ROOT/build/sapi4host.exe" HOST="$MICROSLOP_BUILD/sapi4host.exe"
fi fi
if [ ! -x "$HOST" ]; then if [ ! -x "$HOST" ]; then
echo "no host binary; build first (see README)" >&2 echo "no host binary; run setup/install.sh first" >&2
exit 1 exit 1
fi fi
+5 -8
View File
@@ -7,18 +7,15 @@
set -eu set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd) . "$HERE/config.sh"
SRC=${1:-$ROOT/../flextalk/extracted/TTS_Executables}
SRC=${1:-$MICROSLOP_FLEXTALK_DIR/extracted/TTS_Executables}
[ -d "$SRC/EngineDLLs" ] || { echo "source not found: $SRC" >&2; exit 1; } [ -d "$SRC/EngineDLLs" ] || { echo "source not found: $SRC" >&2; exit 1; }
export WINEPREFIX=${WINEPREFIX:-$HOME/.wine-microslopsam}
export WINEARCH=win32
if [ -z "${DISPLAY:-}" ]; then if [ -z "${DISPLAY:-}" ]; then
WRUN="xvfb-run -a wine" WRUN="xvfb-run -a $MICROSLOP_WINE"
else else
WRUN="wine" WRUN="$MICROSLOP_WINE"
fi fi
DEST="$WINEPREFIX/drive_c/FlexTalk" DEST="$WINEPREFIX/drive_c/FlexTalk"
@@ -92,4 +89,4 @@ echo "== registry"
$WRUN regedit /S "$REG" 2>/dev/null || true $WRUN regedit /S "$REG" 2>/dev/null || true
echo "== done; list voices:" echo "== done; list voices:"
echo " $WRUN $ROOT/host/sapi4host.exe -l" echo " $WRUN $MICROSLOP_BUILD/sapi4host.exe -l"
+5 -8
View File
@@ -7,18 +7,15 @@
set -eu set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd) . "$HERE/config.sh"
ASSETS=${1:-$ROOT/../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4}
ASSETS=${1:-$MICROSLOP_ASSETS}
[ -d "$ASSETS/spchapi" ] || { echo "asset dir not found: $ASSETS" >&2; exit 1; } [ -d "$ASSETS/spchapi" ] || { echo "asset dir not found: $ASSETS" >&2; exit 1; }
export WINEPREFIX=${WINEPREFIX:-$HOME/.wine-microslopsam}
export WINEARCH=win32
if [ -z "${DISPLAY:-}" ]; then if [ -z "${DISPLAY:-}" ]; then
WRUN="xvfb-run -a wine" WRUN="xvfb-run -a $MICROSLOP_WINE"
else else
WRUN="wine" WRUN="$MICROSLOP_WINE"
fi fi
echo "== prefix: $WINEPREFIX" echo "== prefix: $WINEPREFIX"
@@ -48,4 +45,4 @@ $WRUN regedit /S "$HERE/out-spchapi.reg"
$WRUN regedit /S "$HERE/out-mstts.reg" $WRUN regedit /S "$HERE/out-mstts.reg"
echo "== done" echo "== done"
echo "list voices: $WRUN $ROOT/host/sapi4host.exe -l" echo "list voices: $WRUN $MICROSLOP_BUILD/sapi4host.exe -l"
+21 -22
View File
@@ -25,9 +25,8 @@
set -eu set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd) . "$HERE/config.sh"
export WINEPREFIX=${WINEPREFIX:-$HOME/.wine-microslopsam} ROOT=$MICROSLOP_ROOT
export WINEARCH=win32
# VESKSLOP_TTS_VOICES entries: id|Name|gender|language[|flags] # VESKSLOP_TTS_VOICES entries: id|Name|gender|language[|flags]
# `expression=NN` marks a Flextalk voice with an Expression profile parameter and # `expression=NN` marks a Flextalk voice with an Expression profile parameter and
@@ -89,14 +88,14 @@ case "$ENGVOICE" in
esac esac
# The daemon does not export DISPLAY; keep a private Xvfb for the engine. # The daemon does not export DISPLAY; keep a private Xvfb for the engine.
start_xvfb() { start_xvfb() {
if ! [ -S /tmp/.X11-unix/X77 ]; then if ! [ -S "$MICROSLOP_XSOCK" ]; then
Xvfb :77 -screen 0 1024x768x24 >/dev/null 2>&1 & "$MICROSLOP_XVFB" "$MICROSLOP_DISPLAY" -screen 0 1024x768x24 >/dev/null 2>&1 &
sleep 1 sleep 1
fi fi
} }
if [ -z "${DISPLAY:-}" ]; then if [ -z "${DISPLAY:-}" ]; then
start_xvfb start_xvfb
export DISPLAY=:77 export DISPLAY=$MICROSLOP_DISPLAY
fi fi
# NetTTS-style line controls, handled here so no caller/WebUI work is needed: # NetTTS-style line controls, handled here so no caller/WebUI work is needed:
@@ -136,7 +135,7 @@ if [ -f "$TEXTFILE" ]; then
PITCH=$(awk -v v="$CMD_PITCH" 'BEGIN{ if (v<=2.0) v*=100; if (v<0) v=0; if (v>200) v=200; printf "%.4f", 12*log(v/100)/log(2) }') PITCH=$(awk -v v="$CMD_PITCH" 'BEGIN{ if (v<=2.0) v*=100; if (v<0) v=0; if (v>200) v=200; printf "%.4f", 12*log(v/100)/log(2) }')
fi fi
if [ -z "$*" ]; then if [ -z "$*" ]; then
ffmpeg -hide_banner -loglevel error -f lavfi -i anullsrc=r=48000:cl=mono \ "$MICROSLOP_FFMPEG" -hide_banner -loglevel error -f lavfi -i anullsrc=r=48000:cl=mono \
-t 0.1 -c:a pcm_s16le -y "$OUT" >/dev/null 2>&1 \ -t 0.1 -c:a pcm_s16le -y "$OUT" >/dev/null 2>&1 \
|| { echo "could not write silence" >&2; exit 1; } || { echo "could not write silence" >&2; exit 1; }
exit 0 exit 0
@@ -234,11 +233,11 @@ if [ -n "$SPEAKER_GUID" ]; then
exit 1 exit 1
fi fi
if ! command -v wine >/dev/null 2>&1; then if ! command -v "$MICROSLOP_WINE" >/dev/null 2>&1; then
echo "wine is required to set the Flextalk profile" >&2 echo "wine is required to set the Flextalk profile" >&2
exit 1 exit 1
fi fi
if ! wine reg import "$TMP/profile.reg" >/dev/null 2>&1; then if ! "$MICROSLOP_WINE" reg import "$TMP/profile.reg" >/dev/null 2>&1; then
echo "could not write the Flextalk profile" >&2 echo "could not write the Flextalk profile" >&2
exit 1 exit 1
fi fi
@@ -249,11 +248,11 @@ fi
# works on UTF-8, so it runs before the CP1252 transliteration. # works on UTF-8, so it runs before the CP1252 transliteration.
TEXT_SRC="$TEXT_IN" TEXT_SRC="$TEXT_IN"
if [ "$VOX" = "1" ] && [ -n "$SPEAKER_GUID" ]; then if [ "$VOX" = "1" ] && [ -n "$SPEAKER_GUID" ]; then
if command -v python3 >/dev/null 2>&1 && [ -f "$ROOT/setup/vox_parser.py" ]; then if command -v "$MICROSLOP_PYTHON" >/dev/null 2>&1 && [ -f "$MICROSLOP_ROOT/setup/vox_parser.py" ]; then
if [ "$VOX_CLEAN" = "1" ]; then if [ "$VOX_CLEAN" = "1" ]; then
python3 "$ROOT/setup/vox_parser.py" --clean < "$TEXT_IN" > "$TMP/vox.txt" "$MICROSLOP_PYTHON" "$MICROSLOP_ROOT/setup/vox_parser.py" --clean < "$TEXT_IN" > "$TMP/vox.txt"
else else
python3 "$ROOT/setup/vox_parser.py" < "$TEXT_IN" > "$TMP/vox.txt" "$MICROSLOP_PYTHON" "$MICROSLOP_ROOT/setup/vox_parser.py" < "$TEXT_IN" > "$TMP/vox.txt"
fi fi
TEXT_SRC="$TMP/vox.txt" TEXT_SRC="$TMP/vox.txt"
else else
@@ -270,10 +269,10 @@ else
cp "$TEXT_SRC" "$TXT" cp "$TEXT_SRC" "$TXT"
fi fi
HOST="$ROOT/build/sapi4host-winlib.exe" HOST="$MICROSLOP_BUILD/sapi4host-winlib.exe"
if [ ! -x "$HOST" ]; then HOST="$ROOT/build/sapi4host.exe"; fi if [ ! -x "$HOST" ]; then HOST="$MICROSLOP_BUILD/sapi4host.exe"; fi
if [ ! -x "$HOST" ]; then echo "engine host not built" >&2; exit 1; fi if [ ! -x "$HOST" ]; then echo "engine host not built" >&2; exit 1; fi
if ! command -v ffmpeg >/dev/null 2>&1; then echo "ffmpeg not found" >&2; exit 1; fi if ! command -v "$MICROSLOP_FFMPEG" >/dev/null 2>&1; then echo "ffmpeg not found" >&2; exit 1; fi
run_host() { run_host() {
# shellcheck disable=SC2086 # shellcheck disable=SC2086
@@ -284,9 +283,9 @@ run_host() {
try_run_host() { try_run_host() {
if run_host "$1" "$2"; then return 0; fi if run_host "$1" "$2"; then return 0; fi
if [ "${DISPLAY:-}" = ":77" ]; then if [ "${DISPLAY:-}" = "$MICROSLOP_DISPLAY" ]; then
pkill -f "Xvfb :77" 2>/dev/null || true pkill -f "Xvfb $MICROSLOP_DISPLAY" 2>/dev/null || true
rm -f /tmp/.X11-unix/X77 rm -f "$MICROSLOP_XSOCK"
start_xvfb start_xvfb
if run_host "$1" "$2"; then return 0; fi if run_host "$1" "$2"; then return 0; fi
fi fi
@@ -311,7 +310,7 @@ if [ "$WORDS" = "1" ] && [ -n "$SPEAKER_GUID" ] && [ "$VOX" != "1" ]; then
echo "file '$TMP/w$INDEX.wav'" >> "$TMP/list.txt" echo "file '$TMP/w$INDEX.wav'" >> "$TMP/list.txt"
if [ "$GAP" -gt 0 ]; then if [ "$GAP" -gt 0 ]; then
ffmpeg -hide_banner -loglevel error -f lavfi -i "anullsrc=r=11025:cl=mono" \ "$MICROSLOP_FFMPEG" -hide_banner -loglevel error -f lavfi -i "anullsrc=r=11025:cl=mono" \
-t "$(awk -v g="$GAP" 'BEGIN{printf "%.3f", g/1000}')" -c:a pcm_s16le -y "$TMP/sil.wav" \ -t "$(awk -v g="$GAP" 'BEGIN{printf "%.3f", g/1000}')" -c:a pcm_s16le -y "$TMP/sil.wav" \
>/dev/null 2>&1 >/dev/null 2>&1
echo "file '$TMP/sil.wav'" >> "$TMP/list.txt" echo "file '$TMP/sil.wav'" >> "$TMP/list.txt"
@@ -319,7 +318,7 @@ if [ "$WORDS" = "1" ] && [ -n "$SPEAKER_GUID" ] && [ "$VOX" != "1" ]; then
done done
[ "$INDEX" -gt 0 ] || { echo "no words to speak" >&2; exit 1; } [ "$INDEX" -gt 0 ] || { echo "no words to speak" >&2; exit 1; }
if ! ffmpeg -hide_banner -loglevel error -f concat -safe 0 -i "$TMP/list.txt" -c copy -y "$RAW" \ if ! "$MICROSLOP_FFMPEG" -hide_banner -loglevel error -f concat -safe 0 -i "$TMP/list.txt" -c copy -y "$RAW" \
>/dev/null 2>&1; then >/dev/null 2>&1; then
echo "could not merge the words" >&2 echo "could not merge the words" >&2
exit 1 exit 1
@@ -347,7 +346,7 @@ fi
# Fixed-gain normalization: single-pass loudnorm misbehaves on short lines # Fixed-gain normalization: single-pass loudnorm misbehaves on short lines
# (LRA=0 causes heavy attenuation), so measure EBU R128 integrated loudness and # (LRA=0 causes heavy attenuation), so measure EBU R128 integrated loudness and
# true peak, then apply one gain clamped by the -3 dBFS peak target. # true peak, then apply one gain clamped by the -3 dBFS peak target.
M=$(ffmpeg -hide_banner -nostats -i "$RAW" -af "$PRE,ebur128=peak=true" \ M=$("$MICROSLOP_FFMPEG" -hide_banner -nostats -i "$RAW" -af "$PRE,ebur128=peak=true" \
-f null - 2>&1 || true) -f null - 2>&1 || true)
I=$(printf '%s' "$M" | sed -n 's/ *I: *\(-\{0,1\}[0-9.]*\) *LUFS.*/\1/p' | tail -1) I=$(printf '%s' "$M" | sed -n 's/ *I: *\(-\{0,1\}[0-9.]*\) *LUFS.*/\1/p' | tail -1)
TP=$(printf '%s' "$M" | sed -n 's/ *Peak: *\(-\{0,1\}[0-9.]*\) *dBFS.*/\1/p' | tail -1) TP=$(printf '%s' "$M" | sed -n 's/ *Peak: *\(-\{0,1\}[0-9.]*\) *dBFS.*/\1/p' | tail -1)
@@ -365,7 +364,7 @@ else
fi fi
TMPOUT="$TMP/out.wav" TMPOUT="$TMP/out.wav"
if ! ffmpeg -hide_banner -nostats -y -i "$RAW" -af "$PRE,volume=${GAIN}dB" \ if ! "$MICROSLOP_FFMPEG" -hide_banner -nostats -y -i "$RAW" -af "$PRE,volume=${GAIN}dB" \
-ar 48000 -ac 1 -c:a pcm_s16le "$TMPOUT" >/dev/null 2>"$TMP/ff"; then -ar 48000 -ac 1 -c:a pcm_s16le "$TMPOUT" >/dev/null 2>"$TMP/ff"; then
head -c 400 "$TMP/ff" >&2 head -c 400 "$TMP/ff" >&2
exit 1 exit 1
+5
View File
@@ -0,0 +1,5 @@
# third_party
- `speech.h` — Microsoft Speech API 4.0 SDK header (`speech.h`), the same file
referenced from the SAPI4 resources in `docs/NOTES.md`. It is vendored here so the
host builds without any files outside the repository.
+6635
View File
File diff suppressed because it is too large Load Diff