Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

TTS() Text To Speech using COM


  • Please log in to reply
46 replies to this topic
foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Well its yet another tts script but this one doesn't create a tempfile. It uses the Speech API directly.

Here you can download the TTS.ahk includefile and an example file.

Or you can copy the example in the codebox below.
TTS(sSpeechText, dwFlags=0)
{
    ;For info on the dwFlags bitmask see the SAPI helpfile:
    ;http://download.microsoft.com/download/speechSDK/SDK/5.1/WXP/EN-US/sapi.chm

    static TTSInitialized, ppSpVoice, pSpeak

    wSpeechTextBufLen:=VarSetCapacity(wSpeechText, StrLen(sSpeechText)*2+2,0)
    DllCall("MultiByteToWideChar", "UInt", 0, "UInt", 0, "Str", sSpeechText, "Int", -1, "UInt", &wSpeechText, "Int", wSpeechTextBufLen/2)

    if !TTSInitialized
    {
        ComInit := DllCall("ole32\CoInitialize", "Uint", 0)
        if ComInit not in 0,1
            return "CoInitialize() failed: " ComInit

        sCLSID_SpVoice:="{96749377-3391-11D2-9EE3-00C04F797396}"
        sIID_ISpeechVoice:="{269316D8-57BD-11D2-9EEE-00C04F797396}"
        ;Make space for unicode representations.
    	wCLSID_SpVoiceBufLen:=VarSetCapacity(wCLSID_SpVoice, StrLen(sCLSID_SpVoice)*2+2)
    	wIID_ISpeechVoiceBufLen:=VarSetCapacity(wIID_ISpeechVoice, StrLen(sIID_ISpeechVoice)*2+2)
    	;Convert to unicode
    	DllCall("MultiByteToWideChar", "UInt",0, "UInt",0, "Str",sCLSID_SpVoice, "Int",-1, "UInt",&wCLSID_SpVoice, "Int",wCLSID_SpVoiceBufLen/2)
    	DllCall("MultiByteToWideChar", "UInt",0, "UInt",0, "Str",sIID_ISpeechVoice, "Int",-1, "UInt",&wIID_ISpeechVoice, "Int",wIID_ISpeechVoiceBufLen/2)
        
        ;Convert string representations to originals.
        VarSetCapacity(CLSID_SpVoice, 16)
        VarSetCapacity(IID_ISpeechVoice, 16)
        if ret:=DllCall("ole32\CLSIDFromString", "str", wCLSID_SpVoice, "str", CLSID_SpVoice)
        {
            DllCall("ole32\CoUninitialize")
            return "CLSIDFromString() failed: " ret
        }
        if ret:=DllCall("ole32\IIDFromString", "str", wIID_ISpeechVoice, "str", IID_ISpeechVoice)
        {
            DllCall("ole32\CoUninitialize")
            return "IIDFromString() failed: " ret
        }
    
        ;Obtain ISpeechVoice Interface.
        if ret:=DllCall("ole32\CoCreateInstance", "Uint", &CLSID_SpVoice, "Uint", 0, "Uint", 1, "Uint", &IID_ISpeechVoice, "UintP", ppSpVoice)
        {
            DllCall("ole32\CoUninitialize")
            return "CoCreateInstance() failed: " ret
        }
        ;Get pointer to interface.
        DllCall("ntdll\RtlMoveMemory", "UintP", pSpVoice, "Uint", ppSpVoice, "Uint", 4)
        ;Get pointer to Speak().
        DllCall("ntdll\RtlMoveMemory", "UintP", pSpeak, "Uint", pSpVoice + 4*28, "Uint", 4)

        
        if ret:=DllCall(pSpeak, "Uint", ppSpVoice, "str" , wSpeechText, "Uint", dwFlags, "Uint", 0)
        {
            DllCall("ole32\CoUninitialize")
            return "ISpeechVoice::Speak() failed: " ret
        }

        DllCall("ole32\CoUninitialize")

        TTSInitialized = 1
        return
    }

    if ret:=DllCall(pSpeak, "Uint", ppSpVoice, "str" , wSpeechText, "Uint", dwFlags, "Uint", 0)
        return "ISpeechVoice::Speak() failed: " ret
}


;Some usage examples. #####################################
TTS("You can read simple text.")

xmltext=
(
<xml version="1.0">
    <SAPI>
        If the first character of the text is a less then character and the dwFlags parameter is 0 the text will be parsed as xml.
        With the use of xml markup
        <VOICE REQUIRED="NAME=Microsoft Sam">you can</VOICE>
        <VOICE REQUIRED="NAME=Microsoft mike">choose</VOICE>
        <VOICE REQUIRED="NAME=Microsoft Mary">which voice</VOICE>
        <VOICE REQUIRED="NAME=Microsoft Sam">you wish to hear. And much more.</VOICE>
    </SAPI>
</xml>
)
TTS(xmltext)


FileAppend ,
(
You can also specify a fully qualified path to a file and set the dwFlags param to 4. This way the files text will be read.
), tmpspeech.txt
TTS(A_ScriptDir "\tmpspeech.txt", 0 | 4)
FileDelete, tmpspeech.txt


TTS("There are even more features. For details read the speech API documentation.")


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
It reports

---------------------------
CLSIDFromString() failed: -2147221005
---------------------------


here...
Posted Image

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Ooops. Thanks for the report. Should be fixed now.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Still doesn't work here.
Strangely enoguh, return is empty string and manualy traversing to code showed me that all dllcalls executed with correct return codes. Still, script exits the same moment as it enters...

Speak is of coursed installed. I use it with Babylon Pro.
Posted Image

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Strange. Which version do you have installed? I have 5.1 SDK on my machine and 5.1 Redist on the machine of my brother and it works on both.

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

I please people that read this to try it out and give feedback if it works for them even if they are not interested in tts.

It worked fine here.
BTW, the error message -2147221005 is "invalid class string", so looks like something got wrong during copy and paste.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
it works, I was using wrong version. Sorry.

I created COM page here for colaborative work:

<!-- m -->http://www.autohotke... ... M_Wrappers<!-- m -->
Posted Image

jps
  • Members
  • 279 posts
  • Last active: Sep 11 2011 07:26 PM
  • Joined: 02 Sep 2006
It worked for me using your example

Keffi
  • Guests
  • Last active:
  • Joined: --
Hello,

just tried it this way:
Code:
#s::
TTS("You can read simple text.")
return

TTS(sSpeechText, dwFlags=0)
{
;For info on the dwFlags bitmask see the SAPI helpfile:
......here follows your script...

it simply does not speak at all, although it is executed. I habve SAPI 4 and SAPI5 installed with a bunch of voices.

Did I call the function wrong?

Cheers,
Keffi

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Thanks for the feedback.
@ Sean
Yeah i know what the code means. I deleted a comma while bringing the dllcalls down to one line and that cause the error.

@ keffi
Which ahk version do u use? I requirres 1.0.46.08.
I edited my first post so u need to copy and paste only once and run it.

@ majkinetor
Thanks for mentioning the wikipage. The artikle on codeprojekt is very educational. A very good read for COM newbies like me.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I added you script to the wiki.

I did this as an example of wiki usage and authors should add their script to relevant places so we can keep things organised.

Thx goes to jonny who polished ahk wiki.


<!-- m -->http://www.autohotke... ... rs#Scripts<!-- m -->


I also created global autohotkey.net account to keep there files for download.

Account name and pass: anonymous
Put the COM realted scripts in COM\Scripts directory.
Posted Image

Keffi
  • Members
  • 2 posts
  • Last active: Jun 05 2008 08:04 AM
  • Joined: 13 Feb 2007
Well, I used sub-version .06 and guess what, after upgrading to .08 it works perfectly. Thanks a lot for this fine done script and your excellent support. As a blind user I'm always intersted in putting speech output to my scripts in the most efficient way. This will bring me a step forward.

Cheers, Keffi
Blindness is the opportunity to see more

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Thanks for adding the script. Althought i am doubtfull about creating libraries because of ahks lack of elementary features to support librarys. However, its nice to see that someone takes the initiative. Hopefully Chris will recognise and honor this and start working on features that aid libraries.

I also created global autohotkey.net account to keep there files for download.

I have the feeling that this is a bad idea. This might sooner or later get abused eighter to change scripts to do harmfull things or to upload illegal content. You might want to inforn Titan as he is in charge for the site.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I don't think so.

ppl can change entire ahk wiki to contain malitious scripts now, yet, they don't do it. Or they do, we will never know. That is the wiki my friend. You will have to beleive or not use it at all.

Well, I beleive, thats why I use it.


You might want to inforn Titan as he is in charge for the site.

This is regular ahk.net usage, nothing is invalid in it. The fact that it is open changes nothing. Feel free foom to update the download links in the wiki to your user space anytime so, you can be sure noone will ever change it.
Posted Image

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Ok the malicious code issue is nonsense on second thought. But still. If someone uses it for illegal activities, Titan is in charge and he should be informed.