#!/bin/bash # Set Voice # Set the default wine voice based on installed options. # Rate can be specified as a numeric argument to this script, 1 through 9. # The default rate is 7 # # Copyright 2020, Storm Dragon, # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free # Software Foundation; either version 3, or (at your option) any later # version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this package; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # #--code-- # Settings to improve accessibility of dialog. export DIALOGOPTS='--insecure --no-lines --visit-items' # 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 echo "wineprefix = $WINEPREFIX" 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 "$(gettext "Use the up and down arrow keys to find the option you want, then press enter to select it.")" \ --clear \ --extra-button \ --extra-label "$(gettext "Test Voice")" \ --no-tags \ --menu "$(gettext "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\\\\Tokens\\\\[^"]+"/"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 fullVoice=${voiceListFullName[$counter]} 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\\\\Tokens\\\\[^"]+"/"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 fullVoice=${voiceListFullName[$counter]} 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\\\\Tokens\\\\[^"]+"/"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 # Create an array of available voices. ifs="$IFS" IFS=$'\n' voiceListFullName=($(grep -P '\[Software\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Tokens\\\\[^\\]+\].*' "${WINEPREFIX}/system.reg" | sed -E -e 's/\[([^]]+)\].*/\1/g')) IFS="$ifs" voiceList=() for x in "${voiceListFullName[@]}" ; do voiceList+=("$(echo "$x" | rev | cut -d\\ -f1 | rev)") done oldVoice="$(grep -P '"DefaultTokenId"="HKEY_LOCAL_MACHINE\\\\(SOFTWARE|Software)\\\\(Wow6432Node\\\\|)Microsoft\\\\Speech\\\\Voices\\\\Tokens\\\\[^"]+"' "${WINEPREFIX}/user.reg" | sed -E -e 's/"DefaultTokenId"="([^"]+)"/\1/g')" echo "oldVoice: ${oldVoice}" echo "voiceList: ${voiceList[@]}" echo "voiceListFullName: ${voiceListFullName[@]}" #exit 1 exit=1 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