[function] Easy Text to speech
- Learning one
- Posts: 173
- Joined: 04 Oct 2013, 13:59
- Location: Croatia
- Contact:
[function] Easy Text to speech
Continued from old [function] Easy Text to speech thread.
My Website • Join DropBox
Re: [function] Easy Text to speech
Thanks Learning One for this, I needed something for a project of mine and this saved me having to work it all out for myself.
I took your code and re-packaged it as a class - I include it here in case it is useful to anyone else.
Changes:
Implemented as a class - all "commands" that you passed to TTS are now methods (functions) in the new class.
You no longer pass the oVoice object around. When you create a TTS class, it creates a voice object and stores it as a property of the class. All commands change that one voice.
GetVoices now returns an indexed array.
NextVoice added to switch to the next voice.
The code is largely unaltered in essence. Things like the available voices are calculated on startup and stored as class properties, so the code does not need to use COM to determine if a valid voice name is passed to SetVoice for example.
I took your code and re-packaged it as a class - I include it here in case it is useful to anyone else.
Changes:
Implemented as a class - all "commands" that you passed to TTS are now methods (functions) in the new class.
You no longer pass the oVoice object around. When you create a TTS class, it creates a voice object and stores it as a property of the class. All commands change that one voice.
GetVoices now returns an indexed array.
NextVoice added to switch to the next voice.
The code is largely unaltered in essence. Things like the available voices are calculated on startup and stored as class properties, so the code does not need to use COM to determine if a valid voice name is passed to SetVoice for example.
Code: Select all
#SingleInstance force
s := new TTS()
return
F1::s.Speak(gst()) ; select some text and press F1 to test Speak()
F2::s.ToggleSpeak(gst()) ; select some text and press F2 to test ToggleSpeak()
F3::s.NextVoice() ; select some text and press F3 to switch to the next voice
gst() { ; GetSelectedText by Learning one
IsClipEmpty := (Clipboard = "") ? 1 : 0
if !IsClipEmpty {
ClipboardBackup := ClipboardAll
While !(Clipboard = "") {
Clipboard =
Sleep, 10
}
}
Send, ^c
ClipWait, 0.1
ToReturn := Clipboard, Clipboard := ClipboardBackup
if !IsClipEmpty
ClipWait, 0.5, 1
Return ToReturn
}
; Class TTS by evilC
; Based on code by Learning one. For AHK_L. Thanks: jballi, Sean, Frankie.
; AHK forum location: www.autohotkey.com/forum/topic57773.html
; Read more: msdn.microsoft.com/en-us/library/ms723602(v=VS.85).aspx, www.autohotkey.com/forum/topic45471.html, www.autohotkey.com/forum/topic83162.html
Class TTS {
VoiceList := [] ; An indexed array of the available voice names
VoiceAssoc := {} ; An Associative array of voice names, key = voice name, value = voice index (VoiceList lookup)
VoiceCount := 0 ; The number of voices available
VoiceNumber := 0 ; The number of the current voice
VoiceName := "" ; The name of the current voice
__New(){
this.oVoice := ComObjCreate("SAPI.SpVoice")
this._GetVoices()
this.SetVoice(this.VoiceList.1)
}
; speak or stop speaking
ToggleSpeak(text){
Status := this.oVoice.Status.RunningState
if Status = 1 ; finished
this.oVoice.Speak(text,0x1) ; speak asynchronously
Else if Status = 0 ; paused
{
this.oVoice.Resume
this.oVoice.Speak("",0x1|0x2) ; stop
this.oVoice.Speak(text,0x1) ; speak asynchronously
}
Else if Status = 2 ; reading
this.oVoice.Speak("",0x1|0x2) ; stop
}
; speak asynchronously
Speak(text){
Status := this.oVoice.Status.RunningState
if Status = 0 ; paused
this.oVoice.Resume
this.oVoice.Speak("",0x1|0x2) ; stop
this.oVoice.Speak(text,0x1) ; speak asynchronously
}
; speak synchronously
SpeakWait(text){
Status := this.oVoice.Status.RunningState
if Status = 0 ; paused
this.oVoice.Resume
this.oVoice.Speak("",0x1|0x2) ; stop
this.oVoice.Speak(text,0x0) ; speak synchronously
}
; Pause toggle
Pause(){
Status := this.oVoice.Status.RunningState
if Status = 0 ; paused
this.oVoice.Resume
else if Status = 2 ; reading
this.oVoice.Pause
}
Stop(){
Status := this.oVoice.Status.RunningState
if Status = 0 ; paused
this.oVoice.Resume
this.oVoice.Speak("",0x1|0x2) ; stop
}
; rate (reading speed): rate from -10 to 10. 0 is default.
SetRate(rate){
this.oVoice.Rate := rate
}
; volume (reading loudness): vol from 0 to 100. 100 is default
SetVolume(vol){
this.oVoice.Volume := vol
}
; pitch : From -10 to 10. 0 is default.
; http://msdn.microsoft.com/en-us/library/ms717077(v=vs.85).aspx
SetPitch(pitch){
this.oVoice.Speak("<pitch absmiddle = '" pitch "'/>",0x20)
}
; Set voice by name
SetVoice(VoiceName){
if (!ObjHasKey(this.VoiceAssoc, VoiceName))
return 0
While !(this.oVoice.Status.RunningState = 1)
Sleep, 20
this.oVoice.Voice := this.oVoice.GetVoices("Name=" VoiceName).Item(0) ; set voice to param1
this.VoiceName := VoiceName
this.VoiceNumber := this.VoiceAssoc[VoiceName]
return 1
}
; Set voice by index
SetVoiceByIndex(VoiceIndex){
return this.SetVoice(this.VoiceList[VoiceIndex])
}
; Use the next voice. Loops around at end
NextVoice(){
v := this.VoiceNumber + 1
if (v > this.VoiceCount)
v := 1
return this.SetVoiceByIndex(v)
}
; Returns an array of voice names
GetVoices(){
return this.VoiceList
}
GetStatus(){
Status := this.oVoice.Status.RunningState
if Status = 0 ; paused
Return "paused"
Else if Status = 1 ; finished
Return "finished"
Else if Status = 2 ; reading
Return "reading"
}
GetCount(){
return this.VoiceCount
}
SpeakToFile(param1, param2){
oldAOS := this.oVoice.AudioOutputStream
oldAAOFCONS := this.oVoice.AllowAudioOutputFormatChangesOnNextSet
this.oVoice.AllowAudioOutputFormatChangesOnNextSet := 1
SpStream := ComObjCreate("SAPI.SpFileStream")
FileDelete, % param2 ; OutputFilePath
SpStream.Open(param2, 3)
this.oVoice.AudioOutputStream := SpStream
this.SpeakWait(param1)
SpStream.Close()
this.oVoice.AudioOutputStream := oldAOS
this.oVoice.AllowAudioOutputFormatChangesOnNextSet := oldAAOFCONS
}
; ====== Private funcs, not intended to be called by user =======
_GetVoices(){
this.VoiceList := []
this.VoiceAssoc := {}
this.VoiceCount := this.oVoice.GetVoices.Count
Loop, % this.VoiceCount
{
Name := this.oVoice.GetVoices.Item(A_Index-1).GetAttribute("Name") ; 0 based
this.VoiceList.push(Name)
this.VoiceAssoc[Name] := A_Index
}
}
}
Last edited by evilC on 18 Jun 2017, 11:32, edited 1 time in total.
Re: [function] Easy Text to speech
Help.
Can`t write audioOut to file.
Without classes no such problem.
Can`t dig it why. newbie.
Can`t write audioOut to file.
Without classes no such problem.
Can`t dig it why. newbie.
Re: [function] Easy Text to speech
I tried it myself, and yeah there appears to be something wrong. It writes a file, but it does not appear to be valid.
I cannot see what is wrong though, I see no obvious mistakes in my port of that method.
Old code:
New code - should be identical, but the oVoice variable is this.oVoice and the syntax of the TTS method changed.
I cannot see what is wrong though, I see no obvious mistakes in my port of that method.
Old code:
Code: Select all
Else if command = SpeakToFile ; param1 = TextToSpeak, param2 = OutputFilePath
{
oldAOS := oVoice.AudioOutputStream
oldAAOFCONS := oVoice.AllowAudioOutputFormatChangesOnNextSet
oVoice.AllowAudioOutputFormatChangesOnNextSet := 1
SpStream := ComObjCreate("SAPI.SpFileStream")
FileDelete, % param2 ; OutputFilePath
SpStream.Open(param2, 3)
oVoice.AudioOutputStream := SpStream
TTS(oVoice, "SpeakWait", param1)
SpStream.Close()
oVoice.AudioOutputStream := oldAOS
oVoice.AllowAudioOutputFormatChangesOnNextSet := oldAAOFCONS
}
Code: Select all
SpeakToFile(param1, param2){
oldAOS := this.oVoice.AudioOutputStream
oldAAOFCONS := this.oVoice.AllowAudioOutputFormatChangesOnNextSet
this.oVoice.AllowAudioOutputFormatChangesOnNextSet := 1
SpStream := ComObjCreate("SAPI.SpFileStream")
FileDelete, % param2 ; OutputFilePath
SpStream.Open(param2, 3)
this.oVoice.AudioOutputStream := SpStream
this.TTS("SpeakWait", param1)
SpStream.Close()
this.oVoice.AudioOutputStream := oldAOS
this.oVoice.AllowAudioOutputFormatChangesOnNextSet := oldAAOFCONS
}
Re: [function] Easy Text to speech
Hmm, actually, this line is wrong:
this.TTS("SpeakWait", param1) should be this.SpeakWait(param1)
But that does not seem to fix it.
this.TTS("SpeakWait", param1) should be this.SpeakWait(param1)
But that does not seem to fix it.
Re: [function] Easy Text to speech
evilC
wow! Its working now!
Thank you so much, evilC.
wow! Its working now!
Thank you so much, evilC.
Re: [function] Easy Text to speech
Oh really? Didn't seem to work for me, but happy days. I will update the OP.
Re: [function] Easy Text to speech
With this apart works for me:
Spoiler
-
- Posts: 1472
- Joined: 05 May 2018, 12:23
Re: [function] Easy Text to speech
Hi evilCevilC wrote:Oh really? Didn't seem to work for me, but happy days. I will update the OP.
Would you know how I can get a list of available voices and their index number on a machine?
I saw the class above but it is over my head
Re: [function] Easy Text to speech
s.GetVoiceList() returns an indexed array
Code: Select all
s := new TTS()
vl := s.GetVoices()
Loop % vl.Length() {
voices .= A_Index ": " s.VoiceList[A_Index] "`n"
}
msgbox % voices
-
- Posts: 1472
- Joined: 05 May 2018, 12:23
Re: [function] Easy Text to speech
thank youevilC wrote:s.GetVoiceList() returns an indexed array
Code: Select all
s := new TTS() vl := s.GetVoices() Loop % vl.Length() { voices .= A_Index ": " s.VoiceList[A_Index] "`n" } msgbox % voices
Return to “Scripts and Functions (v1)”
Who is online
Users browsing this forum: No registered users and 158 guests