Apply TTS presets with vendor tags and both hives
This commit is contained in:
@@ -33,7 +33,14 @@ ROOT=$MICROSLOP_ROOT
|
||||
# `expression=NN` marks a Flextalk voice with an Expression profile parameter and
|
||||
# its registry default. Expression is applied at voice load, so the wrapper writes
|
||||
# it into the Wine registry before synthesis.
|
||||
VOICES="sam|Sam|male|en,mary|Mary|female|en,mike|Mike|male|en,keith-bell|Keith Bell|male|en|expression=59+defaults=pitch:27:rate:33:prominences:17:head_size:46:lowering:40:expression:59,kerry-watson|Kerry Watson|female|en|expression=100+defaults=pitch:65:rate:32:prominences:17:head_size:45:lowering:40:expression:100,mike-telephone|Mike (for Telephone)|male|en,mary-telephone|Mary (for Telephone)|female|en,mike-hall|Mike in Hall|male|en,mike-stadium|Mike in Stadium|male|en,mike-space|Mike in Space|male|en,mary-hall|Mary in Hall|female|en,mary-stadium|Mary in Stadium|female|en,mary-space|Mary in Space|female|en"
|
||||
# The Keith Bell defaults follow the active preset so the UI's "default" snap points match
|
||||
# the values the preset actually writes.
|
||||
case "${VESKSLOP_TTS_PRESET:-}" in
|
||||
vox) KB_DEFAULTS="pitch:3:rate:17:prominences:22:head_size:52:lowering:40:expression:59" ;;
|
||||
hev) KB_DEFAULTS="pitch:15:rate:24:prominences:22:head_size:52:lowering:40:expression:59" ;;
|
||||
*) KB_DEFAULTS="pitch:27:rate:33:prominences:17:head_size:46:lowering:40:expression:59" ;;
|
||||
esac
|
||||
VOICES="sam|Sam|male|en,mary|Mary|female|en,mike|Mike|male|en,keith-bell|Keith Bell|male|en|expression=59+defaults=$KB_DEFAULTS,kerry-watson|Kerry Watson|female|en|expression=100+defaults=pitch:65:rate:32:prominences:17:head_size:45:lowering:40:expression:100,mike-telephone|Mike (for Telephone)|male|en,mary-telephone|Mary (for Telephone)|female|en,mike-hall|Mike in Hall|male|en,mike-stadium|Mike in Stadium|male|en,mike-space|Mike in Space|male|en,mary-hall|Mary in Hall|female|en,mary-stadium|Mary in Stadium|female|en,mary-space|Mary in Space|female|en"
|
||||
|
||||
if [ "${1:-}" = "--voices" ]; then
|
||||
echo "$VOICES"
|
||||
@@ -153,18 +160,33 @@ if [ -f "$TEXTFILE" ]; then
|
||||
fi
|
||||
|
||||
# Build the engine arguments from the (possibly command-overridden) speed/pitch.
|
||||
# Flextalk: rate and pitch ride as sticky vendor tags. Setting them through
|
||||
# ITTSAttributes (-s/-p) overrides the speaker profile, which is the bug that made
|
||||
# presets sound "too fast and not deep enough". MSTTS has no tags, so it keeps -s/-p.
|
||||
SET_ARGS=""
|
||||
if [ -n "$SPEED" ]; then
|
||||
S=$(awk -v m="$SPEED" 'BEGIN{printf "%d", 150*m+0.5}')
|
||||
[ "$S" -lt 50 ] && S=50
|
||||
[ "$S" -gt "$SMAX" ] && S=$SMAX
|
||||
SET_ARGS="$SET_ARGS -s $S"
|
||||
fi
|
||||
if [ -n "$PITCH" ]; then
|
||||
P=$(awk -v st="$PITCH" -v nat="$NAT_PITCH" 'BEGIN{printf "%d", nat*exp(log(2)*st/12)+0.5}')
|
||||
[ "$P" -lt 50 ] && P=50
|
||||
[ "$P" -gt "$PMAX" ] && P=$PMAX
|
||||
SET_ARGS="$SET_ARGS -p $P"
|
||||
TAG_PREFIX=""
|
||||
if [ -n "$SPEAKER_GUID" ]; then
|
||||
if [ -n "$SPEED" ]; then
|
||||
R=$(awk -v m="$SPEED" 'BEGIN{ if (m==1) exit; v=1/m; if (v<0.25) v=0.25; if (v>4.0) v=4.0; printf "%.3f", v }')
|
||||
[ -n "$R" ] && TAG_PREFIX="${TAG_PREFIX}\\!R${R} "
|
||||
fi
|
||||
if [ -n "$PITCH" ]; then
|
||||
P=$(awk -v st="$PITCH" 'BEGIN{ if (st==0) exit; v=exp(log(2)*st/12); if (v<0.5) v=0.5; if (v>2.0) v=2.0; printf "%.3f", v }')
|
||||
[ -n "$P" ] && TAG_PREFIX="${TAG_PREFIX}\\!%${P} "
|
||||
fi
|
||||
else
|
||||
if [ -n "$SPEED" ]; then
|
||||
S=$(awk -v m="$SPEED" 'BEGIN{printf "%d", 150*m+0.5}')
|
||||
[ "$S" -lt 50 ] && S=50
|
||||
[ "$S" -gt "$SMAX" ] && S=$SMAX
|
||||
SET_ARGS="$SET_ARGS -s $S"
|
||||
fi
|
||||
if [ -n "$PITCH" ]; then
|
||||
P=$(awk -v st="$PITCH" -v nat="$NAT_PITCH" 'BEGIN{printf "%d", nat*exp(log(2)*st/12)+0.5}')
|
||||
[ "$P" -lt 50 ] && P=50
|
||||
[ "$P" -gt "$PMAX" ] && P=$PMAX
|
||||
SET_ARGS="$SET_ARGS -p $P"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Apply the Flextalk profile before synthesis. Profiles are read at voice load and
|
||||
@@ -227,19 +249,41 @@ if [ -n "$SPEAKER_GUID" ]; then
|
||||
esac
|
||||
done
|
||||
|
||||
REG_KEY="HKLM\\Software\\AT&T\\Watson\\2.0\\FlexTalk\\2.0\\Speakers\\$SPEAKER_GUID"
|
||||
IS_PRESET=0
|
||||
if [ "$ENGVOICE" = "Keith Bell" ]; then
|
||||
case "$PRESET" in
|
||||
vox|hev) IS_PRESET=1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Use printf, not echo: dash's echo interprets \2 in the key path as an
|
||||
# escape (STX), which corrupts the key and makes the import a silent no-op.
|
||||
# NetTTS parity: the audible profile goes to both hives. Presets also write the
|
||||
# informational keys from Valve's setup, and point Default Speaker at Keith Bell.
|
||||
{
|
||||
printf 'Windows Registry Editor Version 5.00\n\n'
|
||||
printf '[%s]\n' "$REG_KEY"
|
||||
printf '"Pitch"=dword:%08x\n' "$P_PITCH"
|
||||
printf '"Speaking Rate"=dword:%08x\n' "$P_RATE"
|
||||
printf '"Volume"=dword:%08x\n' "$P_VOLUME"
|
||||
printf '"Expression"=dword:%08x\n' "$P_EXPR"
|
||||
printf '"Prominences"=dword:%08x\n' "$P_PROM"
|
||||
printf '"Head Size"=dword:%08x\n' "$P_HEAD"
|
||||
printf '"Lowering"=dword:%08x\n' "$P_LOWER"
|
||||
for HIVE in 'HKEY_LOCAL_MACHINE' 'HKEY_CURRENT_USER'; do
|
||||
printf '[%s\\Software\\AT&T\\Watson\\2.0\\FlexTalk\\2.0\\Speakers\\%s]\n' "$HIVE" "$SPEAKER_GUID"
|
||||
printf '"Pitch"=dword:%08x\n' "$P_PITCH"
|
||||
printf '"Speaking Rate"=dword:%08x\n' "$P_RATE"
|
||||
printf '"Volume"=dword:%08x\n' "$P_VOLUME"
|
||||
printf '"Expression"=dword:%08x\n' "$P_EXPR"
|
||||
printf '"Prominences"=dword:%08x\n' "$P_PROM"
|
||||
printf '"Head Size"=dword:%08x\n' "$P_HEAD"
|
||||
printf '"Lowering"=dword:%08x\n' "$P_LOWER"
|
||||
if [ "$IS_PRESET" = "1" ]; then
|
||||
printf '"Gender"=dword:00000002\n'
|
||||
printf '"Line Mode"=dword:00000001\n'
|
||||
fi
|
||||
printf '\n'
|
||||
done
|
||||
|
||||
if [ "$IS_PRESET" = "1" ]; then
|
||||
for HIVE in 'HKEY_LOCAL_MACHINE' 'HKEY_CURRENT_USER'; do
|
||||
printf '[%s\\Software\\AT&T\\Watson\\2.0\\FlexTalk\\2.0\\Speakers]\n' "$HIVE"
|
||||
printf '"Default Speaker"="%s"\n\n' "$SPEAKER_GUID"
|
||||
done
|
||||
fi
|
||||
} > "$TMP/profile.reg"
|
||||
|
||||
# Guard against silent reg-import failures (a malformed key would corrupt
|
||||
@@ -322,7 +366,7 @@ if [ "$WORDS" = "1" ] && [ -n "$SPEAKER_GUID" ] && [ "$VOX" != "1" ]; then
|
||||
INDEX=0
|
||||
for word in $(cat "$TXT"); do
|
||||
INDEX=$((INDEX + 1))
|
||||
try_run_host "$TMP/w$INDEX.wav" "$word"
|
||||
try_run_host "$TMP/w$INDEX.wav" "${TAG_PREFIX}${word}"
|
||||
echo "file '$TMP/w$INDEX.wav'" >> "$TMP/list.txt"
|
||||
|
||||
if [ "$GAP" -gt 0 ]; then
|
||||
@@ -340,7 +384,7 @@ if [ "$WORDS" = "1" ] && [ -n "$SPEAKER_GUID" ] && [ "$VOX" != "1" ]; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
try_run_host "$RAW" "$(cat "$TXT")"
|
||||
try_run_host "$RAW" "${TAG_PREFIX}$(cat "$TXT")"
|
||||
fi
|
||||
[ -s "$RAW" ] || { echo "engine produced no audio" >&2; exit 1; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user