Winelib SAPI4 host: MSTTS (Sam/Mary/Mike) + AT&T Flextalk (Keith Bell/Kerry Watson)
This commit is contained in:
Executable
+112
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert INF AddReg sections into a Windows/Wine .reg file.
|
||||
|
||||
Example:
|
||||
inf2reg.py --section APIReg --define 49000='C:\\windows\\speech' \
|
||||
spchapi/SPCHAPI.INF > spchapi.reg
|
||||
"""
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
ROOTS = {
|
||||
"HKCR": "HKEY_CLASSES_ROOT",
|
||||
"HKLM": "HKEY_LOCAL_MACHINE",
|
||||
"HKCU": "HKEY_CURRENT_USER",
|
||||
"HKU": "HKEY_USERS",
|
||||
}
|
||||
|
||||
|
||||
def expand(text, defines):
|
||||
def repl(m):
|
||||
key = m.group(1)
|
||||
if key == "25":
|
||||
return defines.get("WINDOWS", r"C:\windows")
|
||||
return defines.get(key, m.group(0))
|
||||
|
||||
return re.sub(r"%(\w+)%", repl, text)
|
||||
|
||||
|
||||
def reg_type(flags, data):
|
||||
if not flags:
|
||||
return "REG_SZ"
|
||||
try:
|
||||
f = int(flags, 16) if flags.lower().startswith("0x") else int(flags)
|
||||
except ValueError:
|
||||
return "REG_SZ"
|
||||
if f & 0x00020000:
|
||||
return "REG_EXPAND_SZ"
|
||||
if f & 0x00010000:
|
||||
return "REG_MULTI_SZ"
|
||||
if f & 0x00000001:
|
||||
return "REG_BINARY"
|
||||
return "REG_SZ"
|
||||
|
||||
|
||||
def reg_escape(value):
|
||||
return value.replace("\\", "\\\\").replace('"', '\\"')
|
||||
|
||||
|
||||
def unquote(token):
|
||||
token = token.strip()
|
||||
if len(token) >= 2 and token[0] == '"' and token[-1] == '"':
|
||||
return token[1:-1]
|
||||
return token
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("inf")
|
||||
ap.add_argument("--section", action="append", required=True,
|
||||
help="AddReg section name (repeatable)")
|
||||
ap.add_argument("--define", action="append", default=[],
|
||||
help="ID=value, e.g. 49000=C:\\windows\\speech")
|
||||
args = ap.parse_args()
|
||||
|
||||
defines = {"WINDOWS": r"C:\windows"}
|
||||
for item in args.define:
|
||||
k, v = item.split("=", 1)
|
||||
defines[k] = v
|
||||
|
||||
wanted = set(args.section)
|
||||
section = None
|
||||
out = ["REGEDIT4", ""]
|
||||
|
||||
with open(args.inf, "r", encoding="latin-1") as fh:
|
||||
for raw in fh:
|
||||
line = raw.strip()
|
||||
if not line or line.startswith(";"):
|
||||
continue
|
||||
m = re.match(r"^\[([^\]]+)\]$", line)
|
||||
if m:
|
||||
section = m.group(1)
|
||||
continue
|
||||
if section not in wanted:
|
||||
continue
|
||||
parts = [p.strip() for p in line.split(",")]
|
||||
if len(parts) < 4:
|
||||
continue
|
||||
root, key, name, flags = parts[0], parts[1], parts[2], parts[3]
|
||||
data = ",".join(parts[4:]) if len(parts) > 4 else ""
|
||||
if root.upper() not in ROOTS:
|
||||
continue
|
||||
data = expand(unquote(data), defines)
|
||||
name = expand(unquote(name), defines)
|
||||
if "%InstallPrompt%" in name:
|
||||
continue
|
||||
if not data:
|
||||
continue
|
||||
rtype = reg_type(flags.strip(), data)
|
||||
keypath = "\\".join(
|
||||
p for p in (ROOTS[root.upper()], expand(key, defines)) if p
|
||||
)
|
||||
value = data if rtype == "REG_BINARY" else '"%s"' % reg_escape(data)
|
||||
out.append("[%s]" % keypath)
|
||||
out.append("%s=%s" % ('@' if not name else '"%s"' % name, value))
|
||||
out.append("")
|
||||
|
||||
sys.stdout.write("\n".join(out) + "\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
# Install Wine + 32-bit Winelib toolchain + helpers. Debian/Ubuntu.
|
||||
# Run as root: sudo setup/install-deps.sh
|
||||
set -eu
|
||||
|
||||
[ "$(id -u)" = "0" ] || { echo "run as root: sudo $0" >&2; exit 1; }
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
if ! dpkg --print-foreign-architectures | grep -qx i386; then
|
||||
echo "== enabling i386 architecture"
|
||||
dpkg --add-architecture i386
|
||||
fi
|
||||
|
||||
apt-get update
|
||||
|
||||
for p in \
|
||||
wine wine64 wine32:i386 \
|
||||
wine64-tools \
|
||||
libwine-dev libwine-dev:i386 \
|
||||
gcc-multilib libc6-dev-i386 \
|
||||
mingw-w64 \
|
||||
xvfb unshield
|
||||
do
|
||||
if apt-cache policy "$p" 2>/dev/null | grep -q "Candidate: [0-9]"; then
|
||||
echo "== install $p"
|
||||
apt-get install -y --no-install-recommends "$p" || echo "!! FAILED: $p"
|
||||
else
|
||||
echo "-- unavailable, skipped: $p"
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo "versions:"
|
||||
wine --version 2>/dev/null || echo "wine missing"
|
||||
winegcc --version 2>/dev/null | head -1 || echo "winegcc missing"
|
||||
i686-w64-mingw32-gcc --version 2>/dev/null | head -1 || echo "mingw missing"
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
# Run the SAPI4 host with the project's wine prefix and a working X display.
|
||||
# Usage: setup/run.sh [sapi4host args...]
|
||||
set -eu
|
||||
|
||||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd)
|
||||
export WINEPREFIX=${WINEPREFIX:-$HOME/.wine-microslopsam}
|
||||
export WINEARCH=win32
|
||||
|
||||
if [ -z "${DISPLAY:-}" ]; then
|
||||
if ! [ -S /tmp/.X11-unix/X77 ]; then
|
||||
Xvfb :77 -screen 0 1024x768x24 >/dev/null 2>&1 &
|
||||
sleep 1
|
||||
fi
|
||||
export DISPLAY=:77
|
||||
fi
|
||||
|
||||
HOST="$ROOT/build/sapi4host"
|
||||
if [ ! -x "$HOST" ]; then
|
||||
HOST="$ROOT/build/sapi4host.exe"
|
||||
fi
|
||||
if [ ! -x "$HOST" ]; then
|
||||
echo "no host binary; build first (see README)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$HOST" "$@"
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
# Install AT&T FlexTalk 2.1 (Keith Bell, Kerry Watson) into the wine prefix.
|
||||
#
|
||||
# Source: extracted InstallShield cabinet, e.g.
|
||||
# flextalk/extracted/TTS_Executables
|
||||
# Usage: setup/setup-flextalk.sh [source-dir]
|
||||
set -eu
|
||||
|
||||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd)
|
||||
SRC=${1:-$ROOT/../flextalk/extracted/TTS_Executables}
|
||||
|
||||
[ -d "$SRC/EngineDLLs" ] || { echo "source not found: $SRC" >&2; exit 1; }
|
||||
|
||||
export WINEPREFIX=${WINEPREFIX:-$HOME/.wine-microslopsam}
|
||||
export WINEARCH=win32
|
||||
|
||||
if [ -z "${DISPLAY:-}" ]; then
|
||||
WRUN="xvfb-run -a wine"
|
||||
else
|
||||
WRUN="wine"
|
||||
fi
|
||||
|
||||
DEST="$WINEPREFIX/drive_c/FlexTalk"
|
||||
echo "== files -> $DEST"
|
||||
mkdir -p "$DEST"
|
||||
cp -a "$SRC/." "$DEST/"
|
||||
|
||||
REG="$HERE/out-flextalk.reg"
|
||||
cat > "$REG" <<'EOF'
|
||||
REGEDIT4
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\Voice\TextToSpeech\Engine]
|
||||
"AT&T FlexTalk"="{FFE78E00-C69C-11CE-AEC1-0000C0E9CB87}"
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\Voice\TextToSpeech\Engine\{FFE78E00-C69C-11CE-AEC1-0000C0E9CB87}]
|
||||
"Dirty"=dword:00000001
|
||||
|
||||
[HKEY_CLASSES_ROOT\CLSID\{FFE78E00-C69C-11CE-AEC1-0000C0E9CB87}]
|
||||
@="AT&T FlexTalk"
|
||||
|
||||
[HKEY_CLASSES_ROOT\CLSID\{FFE78E00-C69C-11CE-AEC1-0000C0E9CB87}\InprocServer32]
|
||||
@="C:\\FlexTalk\\EngineDLLs\\FlexTalk.dll"
|
||||
"ThreadingModel"="Apartment"
|
||||
|
||||
[HKEY_CLASSES_ROOT\CLSID\{778EAAE2-499F-11CF-B0BA-444553540000}\InprocServer32]
|
||||
@="C:\\FlexTalk\\EngineDLLs\\FlexTalk.dll"
|
||||
"ThreadingModel"="Apartment"
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Directories]
|
||||
"RootDirectory"="C:\\FlexTalk\\"
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Dictionaries]
|
||||
"StandardDictionary"="2 ft_sdict.dll"
|
||||
"ExceptionDictionary"="0 ft_udict.dll"
|
||||
"HomographDictionary"="1 ft_hgrap.dll"
|
||||
"ProperNameDictionary"="3 ft_namsa.dll"
|
||||
"LetterToSoundDictionary"="4 ft_l2s.dll"
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Options]
|
||||
"Gender"="Male"
|
||||
"SampleRate"="11025"
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Speakers\{11260610-C84A-11ce-AEC4-0000C0E9CB87}]
|
||||
"Age"="30"
|
||||
"Expression"="59"
|
||||
"Gender"=""
|
||||
"Head Size"="46"
|
||||
"Lowering"="40"
|
||||
"Mode Name"="Keith Bell"
|
||||
"Pitch"="27"
|
||||
"Prominences"="17"
|
||||
"Speaker Name"="Keith Bell"
|
||||
"Speaking Rate"="33"
|
||||
"Volume"="100"
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Software\AT&T\Watson\2.0\FlexTalk\2.0\Speakers\{000031CB-3699-551F-AED0-6B4893382D57}]
|
||||
"Age"="30"
|
||||
"Expression"="100"
|
||||
"Gender"=""
|
||||
"Head Size"="45"
|
||||
"Lowering"="40"
|
||||
"Mode Name"="Kerry Watson"
|
||||
"Pitch"="65"
|
||||
"Prominences"="17"
|
||||
"Speaker Name"="Kerry Watson"
|
||||
"Speaking Rate"="32"
|
||||
"Volume"="100"
|
||||
EOF
|
||||
|
||||
echo "== registry"
|
||||
$WRUN regedit /S "$REG" 2>/dev/null || true
|
||||
|
||||
echo "== done; list voices:"
|
||||
echo " $WRUN $ROOT/host/sapi4host.exe -l"
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
# Build a 32-bit Wine prefix, install the SAPI4 runtime, the MSTTS engine and
|
||||
# the MSTTS voices, and register everything.
|
||||
#
|
||||
# Usage: setup/setup-prefix.sh [path-to-asset-repo]
|
||||
# Default asset repo: ../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4
|
||||
set -eu
|
||||
|
||||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd)
|
||||
ASSETS=${1:-$ROOT/../Microsoft-Sam-Mary-Mike-TruVoice-WSAPI4}
|
||||
|
||||
[ -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
|
||||
WRUN="xvfb-run -a wine"
|
||||
else
|
||||
WRUN="wine"
|
||||
fi
|
||||
|
||||
echo "== prefix: $WINEPREFIX"
|
||||
mkdir -p "$WINEPREFIX"
|
||||
$WRUN wineboot -u
|
||||
|
||||
SPEECH_DIR="$WINEPREFIX/drive_c/windows/speech"
|
||||
ENGINE_DIR="$WINEPREFIX/drive_c/Program Files/Common Files/microsoft shared/SpeechEngines/TTS"
|
||||
mkdir -p "$SPEECH_DIR" "$ENGINE_DIR"
|
||||
|
||||
echo "== runtime -> $SPEECH_DIR"
|
||||
cp "$ASSETS"/spchapi/SPEECH.DLL "$SPEECH_DIR/"
|
||||
|
||||
echo "== engine + voices -> $ENGINE_DIR"
|
||||
cp "$ASSETS"/msttsl/msttssyn.dll "$ENGINE_DIR/"
|
||||
cp "$ASSETS"/msttsl/*.vce "$ASSETS"/msttsl/*.cfg "$ENGINE_DIR/"
|
||||
|
||||
echo "== registry"
|
||||
python3 "$HERE/inf2reg.py" --section APIReg \
|
||||
--define "49000=C:\\windows\\speech" \
|
||||
"$ASSETS/spchapi/SPCHAPI.INF" > "$HERE/out-spchapi.reg"
|
||||
python3 "$HERE/inf2reg.py" --section TTSReg \
|
||||
--define "49000=C:\\Program Files\\Common Files\\microsoft shared\\SpeechEngines\\TTS" \
|
||||
"$ASSETS/msttsl/mstts.inf" > "$HERE/out-mstts.reg"
|
||||
|
||||
$WRUN regedit /S "$HERE/out-spchapi.reg"
|
||||
$WRUN regedit /S "$HERE/out-mstts.reg"
|
||||
|
||||
echo "== done"
|
||||
echo "list voices: $WRUN $ROOT/host/sapi4host.exe -l"
|
||||
Reference in New Issue
Block a user