#!/usr/bin/env bash # Set Voice # Set the default wine voice ba$sed on installed options. # Rate can be specified as a numeric argument to this script, 1 through 9. # The default rate is 7 # # ■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-- # 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 # Get the desired wine bottle 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)" if [[ -z "${WINEPREFIX}" ]]; then exit 0 fi 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 wineserver -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}}" wineserver -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'${2:-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}}" wineserver -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" > /tmp/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 "z:\tmp\speak.vbs" } # Handle voice restore, but only if voice changed doRestore=1 trap restore_voice SIGINT # 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" > /tmp/speak.vbs dim speechobject set speechobject=createobject("sapi.spvoice") speechobject.speak "" EOF wine cscript "z:\tmp\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 voice="$(menulist "${voiceList[@]}")" case $? in 0) set_voice "$voice" "$1" ; exit=0 ;; 3) test_voice "$voice";; *) restore_voice ; exit=0 ;; esac done exit 0