Hi everyone,
Since voice output came up in the thread of
AI Mistress/Master, I thought I'd share what I had tried for macOS. Combining it with the command from pixy it would look like this, hopefully usable on Mac and Windows machines:
Code:
def osName = ['windows', 'mac'].find { os -> System.properties['os.name'].toLowerCase(Locale.ENGLISH).contains(os) }
def sayCommand = { Object text ->
def cleantext = text.toString().replaceAll(/<[^>]*>/, "") //filter html tags
switch (osName) {
case 'windows':
cleantext = cleantext.replaceAll("'", "''")
return "powershell -Command \"Add-Type –AssemblyName System.Speech; " +
"(New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('${cleantext}');\""
case 'mac':
if (cleantext.size() == 0) cleantext = "' '"
return "say ${cleantext}"
}
}
def say = { text -> if (text) sayCommand(text).execute() }
def speak = { text ->
show(text)
say(text)
}
// Examples
speak("Hello, this is text to speech.")
showButton("Hello!")
speak("<b>Also in bold!</b>")
showButton("Great!")
speak(null)
Some remarks:
The approach allows you to use it with formatting tags, lists or null input, but I am not able to test it on Windows, I hope the filtering and string modifications work for special cases.
Separating the functions for voice only and with text display enables to de-sync them for cases where text is gradually added.
I prefer not to wait for the voice output completion so timers are not affected.
On Mac voices:
The command uses the currently configured voice in Accessibility, which will sound bad for non-English languages. You probably want to select one that works well.
More advanced:
If a certain (here female) voice shall be used by the script, I recommend the following for UK and US or to add something like this in sayCommand:
Code:
switch (voiceLocale) {
case "en-UK": return "say -v Kate ${cleantext}";
case "en-US": return "say -v Samantha ${cleantext.replaceAll("cum","com").replaceAll("Cum","Com")}";
default: return "say -v Kate ${cleantext}";
}
(Samantha needs a bit of pronounciation help
) In that case you may want to do a test if the voice is installed with
Code:
def sayTest = sayCommand("")
def proc = sayTest.execute()
def voice = sayTest.split(" ")[2]
proc.waitForOrKill(1000)
if (proc.exitValue() != 0) {
show("My voice is not working, check in the system preferences that the voice '$voice' is installed.")
showButton("OK")
}
Feedback is welcome, from Windows users and also recent macOS (my machine is a bit older)!