274 lines
9.8 KiB
Bash
Executable File
274 lines
9.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Set Voice
|
|
# Set the default wine voice ba$sed on installed options.
|
|
|
|
#
|
|
# ■The contents of this file are subject to the Common Public Attribution
|
|
# License Version 1.0 (the ■License■); you may not use this file except in
|
|
# compliance with the License. You may obtain a copy of the License at
|
|
# https://opensource.org/licenses/CPAL-1.0. The License is ba$sed on the Mozilla Public License Version
|
|
# 1.1 but Sections 14 and 15 have been added to cover use of software over a
|
|
# computer network and provide for limited attribution for the Original
|
|
# Developer. In addition, Exhibit A has been modified to be consistent with
|
|
# Exhibit B.
|
|
#
|
|
# Software distributed under the License is distributed on an ■AS IS■ basis,
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
# for the specific language governing rights and limitations under the
|
|
# License.
|
|
#
|
|
# The Original Code is audiogame manager.
|
|
#
|
|
# The Original Developer is not the Initial Developer and is . If
|
|
# left blank, the Original Developer is the Initial Developer.
|
|
#
|
|
# The Initial Developer of the Original Code is Billy "Storm Dragon" Wolfe. All portions of
|
|
# the code written by Billy Wolfe are Copyright (c) 2020. All Rights
|
|
# Reserved.
|
|
#
|
|
# Contributor Michael Taboada.
|
|
#
|
|
# Attribution Copyright Notice: Audiogame manager copyright 2020 Storm Dragon. All rights reserved.
|
|
#
|
|
# Attribution Phrase (not exceeding 10 words): A Stormux project
|
|
#
|
|
# Attribution URL: https://stormgames.wolfe.casa
|
|
#
|
|
# Graphic Image as provided in the Covered Code, if any.
|
|
#
|
|
# Display of Attribution Information is required in Larger
|
|
# Works which are defined in the CPAL as a work which combines Covered Code
|
|
# or portions thereof with code not governed by the terms of the CPAL.
|
|
|
|
#--code--
|
|
|
|
help() {
|
|
echo "${0##*/}"
|
|
echo "Released under the terms of the Common Public Attribution License Version 1.0"
|
|
echo -e "This is a Stormux project: https://stormux.org\n"
|
|
echo -e "Usage:\n"
|
|
echo "With no arguments, open the game launcher."
|
|
for i in "${!command[@]}" ; do
|
|
echo "-${i/:/ <parameter>}: ${command[${i}]}"
|
|
done | sort
|
|
exit 0
|
|
}
|
|
|
|
|
|
# Set a variable to make mac compatibility easier...
|
|
sed="sed"
|
|
grep="grep"
|
|
if [[ "$(uname)" == "Darwin" ]]; then
|
|
sed="gsed"
|
|
grep="ggrep"
|
|
fi
|
|
export grep
|
|
export sed
|
|
# Settings to improve accessibility of dialog.
|
|
export DIALOGOPTS='--insecure --no-lines --visit-items'
|
|
# Turn off debug messages
|
|
export WINEDEBUG="-all"
|
|
# Set DISPLAY, as needed
|
|
if [ -z "$DISPLAY" ] ; then
|
|
export DISPLAY=:0
|
|
fi
|
|
# handle arguments
|
|
declare -A command=(
|
|
[b:]="the wine bottle to use."
|
|
[h]="This help screen."
|
|
[r:]="Specify voice rate, default is 7, options are 0-9 or A for fastest."
|
|
[v:]="Voice name, the voice to use, same as in the menu."
|
|
)
|
|
|
|
|
|
|
|
msgbox() {
|
|
# Returns: None
|
|
# Shows the provided message on the screen with an ok button.
|
|
dialog --clear --msgbox "$*" 0 0
|
|
}
|
|
|
|
infobox() {
|
|
# Returns: None
|
|
# Shows the provided message on the screen with no buttons.
|
|
local timeout=3
|
|
dialog --infobox "$*" 0 0
|
|
read -n1 -t $timeout continue
|
|
# Clear any keypresses from the buffer
|
|
read -t 0.01 continue
|
|
}
|
|
|
|
yesno() {
|
|
# Returns: Yes or No
|
|
# Args: Question to user.
|
|
# Called in if $(yesno) == "Yes"
|
|
# Or variable=$(yesno)
|
|
dialog --clear --backtitle "Press 'Enter' for "yes" or 'Escape' for "no"." --yesno "$*" 0 0 --stdout
|
|
if [[ $? -eq 0 ]]; then
|
|
echo "Yes"
|
|
else
|
|
echo "No"
|
|
fi
|
|
}
|
|
|
|
menulist() {
|
|
# Args: List of items for menu.
|
|
# returns: selected tag
|
|
declare -a menuList
|
|
for i in "${@}" ; do
|
|
menuList+=("$i" "$i")
|
|
done
|
|
dialog --backtitle "Use the up and down arrow keys to find the option you want, then press enter to select it." \
|
|
--clear \
|
|
--extra-button \
|
|
--extra-label "Test Voice" \
|
|
--no-tags \
|
|
--menu "Please select one" 0 0 0 "${menuList[@]}" --stdout
|
|
return $?
|
|
}
|
|
|
|
restore_voice() {
|
|
if [[ $doRestore -eq 0 ]]; then
|
|
${wine}server -k # If we don't do this it's likely wine will overwrite our reverted change or even clobber the registry key entirely
|
|
$sed -i -E -e 's/"DefaultTokenId"="HKEY_LOCAL_MACHINE\\\\(SOFTWARE|Software)\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Token(Enum|)s\\\\[^"]+"/"DefaultTokenId"="'"${oldVoice//\\/\\\\}"'"/g' "${WINEPREFIX}/user.reg"
|
|
fi
|
|
}
|
|
|
|
set_voice() {
|
|
doRestore=1
|
|
local tmp="$1"
|
|
local fullVoice
|
|
local counter=0
|
|
for x in "${voiceList[@]}" ; do
|
|
[[ "$x" = "$tmp" ]] && break
|
|
counter=$(( $counter + 1 ))
|
|
done
|
|
local RHVoiceName="$(find "${WINEPREFIX}/drive_c/ProgramData/Olga Yakovleva/RHVoice/data/voices/" -maxdepth 1 -type d)"
|
|
RHVoiceName="${RHVoiceName##*/}"
|
|
fullVoice="${voiceListFullName[$counter]}"
|
|
fullVoice="${fullVoice/RHVoice/RHVoice\\\\${RHVoiceName}}"
|
|
${wine}server -k # If we don't do this it's likely wine will overwrite our reverted change or even clobber the registry key entirely
|
|
# Remove any existing rate change for voices
|
|
$sed -i '/"DefaultTTSRate"=dword:/d' "${WINEPREFIX}/user.reg"
|
|
$sed -i -E -e 's/"DefaultTokenId"="HKEY_LOCAL_MACHINE\\\\(SOFTWARE|Software)\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Token(Enum|)s\\\\[^"]+"/"DefaultTokenId"="HKEY_LOCAL_MACHINE\\\\'"${fullVoice//\\/\\\\}"'"\n"DefaultTTSRate"=dword:0000000'${rate:-7}'/g' "${WINEPREFIX}/user.reg"
|
|
}
|
|
|
|
test_voice() {
|
|
doRestore=0
|
|
local tmp="$1"
|
|
local fullVoice
|
|
local counter=0
|
|
for x in "${voiceList[@]}" ; do
|
|
[ "$x" = "$tmp" ] && break
|
|
counter=$(( $counter + 1 ))
|
|
done
|
|
local RHVoiceName="$(find "${WINEPREFIX}/drive_c/ProgramData/Olga Yakovleva/RHVoice/data/voices/" -maxdepth 1 -type d)"
|
|
RHVoiceName="${RHVoiceName##*/}"
|
|
fullVoice="${voiceListFullName[$counter]}"
|
|
fullVoice="${fullVoice/RHVoice/RHVoice\\\\${RHVoiceName}}"
|
|
${wine}server -k # If we don't do this it's likely wine will overwrite our reverted change or even clobber the registry key entirely
|
|
$sed -i -E -e 's/"DefaultTokenId"="HKEY_LOCAL_MACHINE\\\\(SOFTWARE|Software)\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Token(Enum|)s\\\\[^"]+"/"DefaultTokenId"="HKEY_LOCAL_MACHINE\\\\'"${fullVoice//\\/\\\\}"'"/g' "${WINEPREFIX}/user.reg"
|
|
cat << "EOF" > "${bottle}/drive_c/windows/temp/speak.vbs"
|
|
dim speechobject
|
|
set speechobject=createobject("sapi.spvoice")
|
|
speechobject.speak "This is a test of your chosen voice. It contains multiple sentences and punctuation, and is designed to give a full representation of this voices qualities."
|
|
EOF
|
|
${wine} cscript "c:\windows\temp\speak.vbs"
|
|
}
|
|
|
|
# Handle voice restore, but only if voice changed
|
|
doRestore=1
|
|
trap restore_voice SIGINT
|
|
|
|
# Convert the keys of the command associative array to a format usable by getopts
|
|
args="${!command[*]}"
|
|
args="${args//[[:space:]]/}"
|
|
while getopts "${args}" i ; do
|
|
case "$i" in
|
|
b)
|
|
if ! [[ -d ~/".local/wine/${OPTARG}" ]]; then
|
|
echo "Invalid wine bottle specified."
|
|
exit 1
|
|
fi
|
|
export bottle=~/".local/wine/${OPTARG}"
|
|
export WINEPREFIX=~/".local/wine/${OPTARG}"
|
|
;;
|
|
h) help;;
|
|
r)
|
|
if ! [[ "${OPTARG}" =~ ^[0-9A]$ ]]; then
|
|
echo "Invalid rate specified. Arguments must be 0-9 or A."
|
|
exit 1
|
|
fi
|
|
rate="${OPTARG}"
|
|
;;
|
|
v) voice="${OPTARG}";;
|
|
esac
|
|
done
|
|
|
|
|
|
# Get the desired wine bottle
|
|
|
|
# Offer a list of wine bottles if one isn't specified on the command line.
|
|
if [[ -z "${bottle}" ]]; then
|
|
declare -a bottle
|
|
for i in $(find ~/.local/wine/ -maxdepth 1 -type d -not -name 'wine' | sort) ; do
|
|
bottle+=("$i" "${i##*/}")
|
|
done
|
|
export WINEPREFIX="$(dialog --backtitle "Use the up and down arrow keys to find the option you want, then press enter to select it." \
|
|
--clear \
|
|
--no-tags \
|
|
--menu "Select A Wine Bottle" 0 0 0 "${bottle[@]}" --stdout)"
|
|
fi
|
|
|
|
if [[ -z "${WINEPREFIX}" ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Get wine version if available
|
|
if [[ -r "${WINEPREFIX}/agm.conf" ]]; then
|
|
source "${WINEPREFIX}/agm.conf"
|
|
export WINE
|
|
export WINESERVER
|
|
fi
|
|
wine="${WINE:-$(command -v wine)}"
|
|
|
|
# In case the user hasn't run a game using sapi in this prefix yet, let's try to initialize all the registry keys properly.
|
|
cat << "EOF" > "${bottle}/drive_c/windows/temp/speak.vbs"
|
|
dim speechobject
|
|
set speechobject=createobject("sapi.spvoice")
|
|
speechobject.speak ""
|
|
EOF
|
|
${wine} cscript "c:\windows\temp\speak.vbs"
|
|
|
|
# Create an array of available voices.
|
|
ifs="$IFS"
|
|
IFS=$'\n'
|
|
voiceListFullName=($($grep -P '\[Software\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Token(Enum|)s\\\\[^\\]+\].*' "${WINEPREFIX}/system.reg" | $sed -E -e 's/\[([^]]+)\].*/\1/g'))
|
|
IFS="$ifs"
|
|
voiceList=()
|
|
for x in "${voiceListFullName[@]}" ; do
|
|
voiceList+=("$(echo "$x" | $sed -E -e 's/Software\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Token(Enum|)s\\\\(.+)/\3/g')")
|
|
done
|
|
oldVoice="$($grep -P '"DefaultTokenId"="HKEY_LOCAL_MACHINE\\\\(SOFTWARE|Software)\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Token(Enum|)s\\\\[^"]+"' "${WINEPREFIX}/user.reg" | $sed -E -e 's/"DefaultTokenId"="([^"]+)"/\1/g')"
|
|
exit=1
|
|
if [[ "${#voiceList[@]}" -eq 0 ]]; then
|
|
dialog --msgbox "No voices found." -1 -1
|
|
exit 1
|
|
fi
|
|
while [[ $exit -ne 0 ]] ; do
|
|
if [[ -z "${voice}" ]]; then
|
|
voice="$(menulist "${voiceList[@]}")"
|
|
fi
|
|
|
|
case $? in
|
|
0)
|
|
set_voice "$voice" "${rate:-7}" ; exit=0 ;;
|
|
3)
|
|
test_voice "$voice";;
|
|
*)
|
|
restore_voice ; exit=0 ;;
|
|
esac
|
|
done
|
|
|
|
exit 0
|