SAPI Speech Engine build 2020-04-12 beta [Windows only]

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
UEZ
Posts: 523
Joined: May 05, 2017 19:59
Location: Germany

SAPI Speech Engine build 2020-04-12 beta [Windows only]

Postby UEZ » Apr 09, 2020 14:45

Here my version of the SAPI Speech Engine (tested on Windows10 US only).

SAPI.bi

Code: Select all

'Coded by UEZ build 2020-04-12 beta

#Include Once "disphelper\disphelper.bi"
#Include Once "file.bi"
#Include Once "windows.bi"

#Define UNICODE
Dim Shared As IDispatch Ptr __oTTS, __oFileStream
Dim Shared As Ubyte __SAPIver

Enum SpeechStreamFileMode 'https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms720858(v%3Dvs.85)
    SSFMOpenForRead = 0
    SSFMOpenReadWrite = 1
    SSFMCreate = 2
    SSFMCreateForWrite = 3
End Enum

Enum SpeechVoiceEvents 'https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms720886(v%3Dvs.85)
    SVEStartInputStream = 2
    SVEEndInputStream = 4
    SVEVoiceChange = 8
    SVEBookmark = 16
    SVEWordBoundary = 32
    SVEPhoneme = 64
    SVESentenceBoundary = 128
    SVEViseme = 256
    SVEAudioLevel = 512
    SVEPrivate = 32768
    SVEAllEvents = 33790
End Enum

Enum SpeechVoicePriority 'https:'docs.microsoft.com/en-us/previous-versions/windows/desktop/ee125221(v=vs.85)
    SVPNormal = 0
    SVPAlert = 1
    SVPOver = 2
End Enum

Enum SpeechVoiceSpeakFlags 'https:'docs.microsoft.com/en-us/previous-versions/windows/desktop/ee125223(v=vs.85)
    SVSFDefault = 0
    SVSFlagsAsync = 1
    SVSFPurgeBeforeSpeak = 2
    SVSFIsFilename = 4
    SVSFIsXML = 8
    SVSFIsNotXML = 16
    SVSFPersistXML = 32

    'Normalizer Flags
    SVSFNLPSpeakPunc = 64

    'TTS Format
    SVSFParseSapi
    SVSFParseSsml
    SVSFParseAutoDetect

    'Masks
    SVSFNLPMask = SVSFNLPSpeakPunc
    SVSFParseMask = SVSFParseSapi Or SVSFParseSsml
    SVSFVoiceMask = SVSFlagsAsync Or SVSFPurgeBeforeSpeak Or SVSFIsFilename Or SVSFIsXML Or SVSFIsNotXML Or SVSFNLPMask Or SVSFPersistXML Or SVSFParseMask '127
    SVSFUnusedFlags = Not SVSFVoiceMask '-128
   
   'SPEAKFLAGS
   SPF_DEFAULT = SVSFDefault
   SPF_ASYNC = SVSFlagsAsync
   SPF_PURGEBEFORESPEAK = SVSFPurgeBeforeSpeak
   SPF_IS_FILENAME = SVSFIsFilename
   SPF_IS_XML = SVSFIsXML
   SPF_IS_NOT_XML = SVSFIsNotXML
   SPF_PERSIST_XML = SVSFPersistXML
   SPF_NLP_SPEAK_PUNC = SVSFNLPSpeakPunc
   SPF_NLP_MASK = SVSFNLPMask
   SPF_VOICE_MASK = SVSFVoiceMask
   SPF_UNUSED_FLAGS = SVSFUnusedFlags
End Enum

Enum SpeechAudioFormatType
    SAFTDefault = -1
    SAFTNoAssignedFormat = 0
    SAFTText = 1
    SAFTNonStandardFormat = 2
    SAFTExtendedAudioFormat = 3

    ' Standard PCM wave formats
    SAFT8kHz8BitMono = 4
    SAFT8kHz8BitStereo = 5
    SAFT8kHz16BitMono = 6
    SAFT8kHz16BitStereo = 7
    SAFT11kHz8BitMono = 8
    SAFT11kHz8BitStereo = 9
    SAFT11kHz16BitMono = 10
    SAFT11kHz16BitStereo = 11
    SAFT12kHz8BitMono = 12
    SAFT12kHz8BitStereo = 13
    SAFT12kHz16BitMono = 14
    SAFT12kHz16BitStereo = 15
    SAFT16kHz8BitMono = 16
    SAFT16kHz8BitStereo = 17
    SAFT16kHz16BitMono = 18
    SAFT16kHz16BitStereo = 19
    SAFT22kHz8BitMono = 20
    SAFT22kHz8BitStereo = 21
    SAFT22kHz16BitMono = 22
    SAFT22kHz16BitStereo = 23
    SAFT24kHz8BitMono = 24
    SAFT24kHz8BitStereo = 25
    SAFT24kHz16BitMono = 26
    SAFT24kHz16BitStereo = 27
    SAFT32kHz8BitMono = 28
    SAFT32kHz8BitStereo = 29
    SAFT32kHz16BitMono = 30
    SAFT32kHz16BitStereo = 31
    SAFT44kHz8BitMono = 32
    SAFT44kHz8BitStereo = 33
    SAFT44kHz16BitMono = 34
    SAFT44kHz16BitStereo = 35
    SAFT48kHz8BitMono = 36
    SAFT48kHz8BitStereo = 37
    SAFT48kHz16BitMono = 38
    SAFT48kHz16BitStereo = 39

    ' TrueSpeech format
    SAFTTrueSpeech_8kHz1BitMono = 40

    ' A-Law formats
    SAFTCCITT_ALaw_8kHzMono = 41
    SAFTCCITT_ALaw_8kHzStereo = 42
    SAFTCCITT_ALaw_11kHzMono = 43
    SAFTCCITT_ALaw_11kHzStereo = 4
    SAFTCCITT_ALaw_22kHzMono = 44
    SAFTCCITT_ALaw_22kHzStereo = 45
    SAFTCCITT_ALaw_44kHzMono = 46
    SAFTCCITT_ALaw_44kHzStereo = 47

    ' u-Law formats
    SAFTCCITT_uLaw_8kHzMono = 48
    SAFTCCITT_uLaw_8kHzStereo = 49
    SAFTCCITT_uLaw_11kHzMono = 50
    SAFTCCITT_uLaw_11kHzStereo = 51
    SAFTCCITT_uLaw_22kHzMono = 52
    SAFTCCITT_uLaw_22kHzStereo = 53
    SAFTCCITT_uLaw_44kHzMono = 54
    SAFTCCITT_uLaw_44kHzStereo = 55
    SAFTADPCM_8kHzMono = 56
    SAFTADPCM_8kHzStereo = 57
    SAFTADPCM_11kHzMono = 58
    SAFTADPCM_11kHzStereo = 59
    SAFTADPCM_22kHzMono = 60
    SAFTADPCM_22kHzStereo = 61
    SAFTADPCM_44kHzMono = 62
    SAFTADPCM_44kHzStereo = 63

    ' GSM 6.10 formats
    SAFTGSM610_8kHzMono = 64
    SAFTGSM610_11kHzMono = 65
    SAFTGSM610_22kHzMono = 66
    SAFTGSM610_44kHzMono = 67

    ' Other formats
    SAFTNUM_FORMATS = 68
End Enum

Private Function __Disphelper_ClassInit(sClassname As String, bException As Bool = True) As IDispatch Ptr
   Dim As Wstring * 128 classname = sClassname
   DISPATCH_OBJ(oClass)
   dhInitialize(TRUE)
   dhToggleExceptions(bException)
   Dim As HRESULT result = dhCreateObject(@classname, NULL, @oClass)
   If result <> 0 Then Return 0
   Return oClass
End Function

'https:'docs.microsoft.com/en-us/previous-versions/windows/desktop/ee125640(v=vs.85)
Function SAPI_Init(bException As Bool = True) As BOOL
   __oTTS = __Disphelper_ClassInit("SAPI.SpVoice", bException) 'try SAPI 5
   If __oTTS = 0 Then
      __oTTS = __Disphelper_ClassInit("Speech.VoiceText", bException) 'otherwise try SAPI 4
      If __oTTS = 0 Then Return FALSE
      __SAPIver = 4
   Else
      __SAPIver = 5
   End If
   Return TRUE
End Function

Sub SAPI_FileStreamOpen(sFile As String, iAudioFormat As Ubyte = SAFT44kHz16BitStereo)
   __oFileStream = __Disphelper_ClassInit("SAPI.SpFileStream")
   dhPutValue(__oFileStream, ".Format.Type = %d", iAudioFormat)
   dhCallMethod(__oFileStream, ".Open(%s, %d, %b)", sFile, SSFMCreateForWrite, False)
   dhPutRef(__oTTS, ".AudioOutputStream = %o", __oFileStream)
End Sub

Sub SAPI_FileStreamClose()
   dhCallMethod(__oFileStream, ".Close")
   SAFE_RELEASE(__oFileStream)
End Sub

Sub SAPI_Close()
   SAFE_RELEASE(__oTTS)
   dhUninitialize(TRUE)
End Sub

Sub SAPI_Speak(sText As String, iFlag As Integer = SVSFDefault)
   Dim As Wstring * 8192 txt => sText
   If __SAPIver = 4 Then 'not tested!
      Dim As Bool bIsSpeaking = TRUE
      dhPutValue(__oTTS, ".Enabled = %b", TRUE)
      dhCallMethod(__oTTS, ".Speak(%S, %d)", @txt, iFlag)
      While bIsSpeaking = TRUE And dhGetValue("%b", @bIsSpeaking, __oTTS, ".IsSpeaking") = 0
         Sleep(150)
      Wend
   Else
      dhCallMethod(__oTTS, ".Speak(%S, %d)", @txt, iFlag)
   End If
End Sub

Sub SAPI_SetVoice(iVoiceNumber As Ubyte = 0)
   Dim As Integer count
   DISPATCH_OBJ(oVoices)
   DISPATCH_OBJ(oItem)
   dhGetValue("%o", @oVoices, __oTTS, ".getvoices")    'oVoices = __oTTS.getvoices
   dhGetValue("%d", @count, oVoices, ".count")         'count = oVoices.count
   iVoiceNumber = Iif(iVoiceNumber < 0, 0, Iif(iVoiceNumber > count - 1, count - 1, iVoiceNumber))
   dhGetValue("%o", @oItem, oVoices, ".item(%d)", iVoiceNumber) 'oItem = oVoices.item(iVoiceNumber)
   dhPutRef(__oTTS, ".voice = %o", oItem)            '__oTTS.voice = oItem
End Sub

Sub SAPI_SetVoiceFemale(iVoiceNumber As Ubyte = 0)
   Dim As Integer count
   DISPATCH_OBJ(oVoices)
   DISPATCH_OBJ(oItem)
   dhGetValue("%o", @oVoices, __oTTS, ".getvoices(%s)", "gender=female")
   dhGetValue("%d", @count, oVoices, ".count")
   iVoiceNumber = Iif(iVoiceNumber < 0, 0, Iif(iVoiceNumber > count - 1, count - 1, iVoiceNumber))
   dhGetValue("%o", @oItem, oVoices, ".item(%d)", iVoiceNumber)
   dhPutRef(__oTTS, ".voice = %o", oItem)
   SAFE_RELEASE(oItem)
   SAFE_RELEASE(oVoices)
End Sub

Sub SAPI_SetVoiceMale(iVoiceNumber As Ubyte = 0)
   Dim As Integer count
   DISPATCH_OBJ(oVoices)
   DISPATCH_OBJ(oItem)
   dhGetValue("%o", @oVoices, __oTTS, ".getvoices(%s)", "gender=male")
   dhGetValue("%d", @count, oVoices, ".count")
   iVoiceNumber = Iif(iVoiceNumber < 0, 0, Iif(iVoiceNumber > count - 1, count - 1, iVoiceNumber))
   dhGetValue("%o", @oItem, oVoices, ".item(%d)", iVoiceNumber)
   dhPutRef(__oTTS, ".voice = %o", oItem)
   SAFE_RELEASE(oItem)
   SAFE_RELEASE(oVoices)
End Sub

Sub SAPI_PrintVoices(sFilter As String = "") 'gender=female (Voice attributes include "Gender," "Age," "Name," "Language," and "Vendor")
   Dim As Integer count
   DISPATCH_OBJ(oVoices)
   dhGetValue("%o", @oVoices, __oTTS, ".getvoices(%s)", sFilter)    ' oVoices = __oTTS.getvoices(sFilter)
   dhGetValue("%d", @count, oVoices, ".count")                  ' count = oVoices.count
   Dim As Zstring Ptr text
   For i As Ubyte = 0 To count - 1
      dhGetValue("%s", @text, oVoices, ".item(%d).getdescription", i) 'text = oVoices.item(i).getdescription
      ? i & ". " & text[0]
   Next
   SAFE_RELEASE(oVoices)
End Sub

Sub SAPI_SetRate(iRate As Byte = 0) '-10 to 10
   iRate = Iif(iRate < -10, -10, Iif(iRate > 10, 10, iRate))
   dhPutValue(__oTTS, ".rate = %d", iRate)
End Sub

Sub SAPI_SetVolume(iVolume As Ubyte) '0 - 100
   iVolume = Iif(iVolume > 100, 100, iVolume)
   dhPutValue(__oTTS, ".volume = %d", iVolume)
End Sub

Sub SAPI_Pause()
   dhCallMethod(__oTTS, ".pause")
End Sub

Sub SAPI_Resume()
   dhCallMethod(__oTTS, ".resume")
End Sub

Sub SAPI_Skip(iNumItems As Integer)
   dhCallMethod(__oTTS, ".Skip(%s, %d)", "sentence", iNumItems)
End Sub

Sub SAPI_WaitUntilDone(msTimeout As Integer = -1)
   dhCallMethod(__oTTS, ".WaitUntilDone(%d)", msTimeout)
End Sub


Example1.bas

Code: Select all

#include once "SAPI.bi"

If SAPI_Init(False) = False Then ? "Unable to initialize SAPI!" : Sleep : End

? "SAPI ver: " & __SAPIver
?

? "Voices found:"
SAPI_PrintVoices()

SAPI_SetVolume(100)

? : ?

Dim As String text = "This is a SAPI voice demo coded by UEZ in April 2020."
? text
SAPI_Speak(text, SVSFlagsAsync)
Sleep (2100) 'some delay during speak
? : ? "pause for 3 seconds..."
SAPI_Pause()
Sleep (3000)
SAPI_Resume()
? "resuming..." : ?
SAPI_WaitUntilDone()

SAPI_SetVoiceFemale(1)

Text = "The voice has been changed to a female voice."
? text
SAPI_Speak(text)
?

SAPI_SetRate(-10)
Text = "Speaking very slowy."
SAPI_SetVoiceFemale(2)
? text
SAPI_Speak(text)
?

SAPI_SetVoiceMale()
text = "1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20."
? text
?
SAPI_SetRate(0)
SAPI_Speak(text, SVSFlagsAsync)
Sleep(7000)
? "Forward some items"
SAPI_Skip(2)
Sleep(5000)
? "Backward some items"
SAPI_Skip(-3)
SAPI_WaitUntilDone()
?

SAPI_SetRate(2)
Dim As Integer l = GetEnvironmentVariable("Temp", 0, 0)
Dim As Zstring Ptr pTempDir = Callocate(l)
Dim As String sTempPath = "C:"
If GetEnvironmentVariable("Temp", pTempDir, l) <> 0 Then sTempPath = pTempDir[0]
Deallocate(pTempDir)

SAPI_SetVoiceMale()
SAPI_SetRate(0)
Text = "Writing speech output to a wave file located in " & sTempPath & "\Test.wav"
? text
?

SAPI_FileStreamOpen(sTempPath & "\Test.wav", SAFT8kHz8BitMono)
SAPI_Speak("Speech output has been created using the SAPI engine. Demo was created by UEZ.", SVSFNLPSpeakPunc)
SAPI_FileStreamClose()

Shell(sTempPath & "\Test.wav")

SAPI_Close()

?
? "You reached the end - you can close the box now. ^^"


Sleep()
End

It might be that you have to modify SAPI_SetVoiceFemale(), SAPI_SetVoiceMale() accordingly to hear some voices.


Example2.bas

Code: Select all

#include once "SAPI.bi"

If SAPI_Init(False) = False Then ? "Unable to initialize SAPI!" : Sleep : End

?

? "Voices found:"
SAPI_PrintVoices()

SAPI_SetVolume(100)

? : ?

Dim As String text

SAPI_SetRate(2)
Dim As String textfile = Curdir & "\Speech.txt"
? "Loading " & textfile & " for speach output"
SAPI_Speak(textfile, SPF_IS_FILENAME Or SVSFIsNotXML Or SVSFNLPSpeakPunc)


SAPI_Close()

?
? "You reached the end - you can close the box now. ^^"


Sleep()
End


Speech.txt

Code: Select all

FreeBASIC is a free, BASIC compiler for Windows (32-bit and 64-bit), 32 bit protected-mode DOS (COFF executables, like DJGPP), and Linux (x86, x86_64, and ARM).
It is open source and licensed under the GPL.
It is designed to be syntax compatible with QuickBASIC, while expanding on the language and capabilities.
It can create programs for MS-Windows, DOS and Linux, and is being ported to other platforms.
See About FreeBASIC and Main Features.


Example3:

Code: Select all

#include once "SAPI.bi"

If SAPI_Init(False) = False Then ? "Unable to initialize SAPI!" : Sleep : End

?

? "Voices found:"
SAPI_PrintVoices()

SAPI_SetVolume(100)

? : ?

Dim As String text

SAPI_SetRate(1)
Dim As String textfile = Curdir & "\TTSXmlDemo.xml"
? "Loading " & textfile & " for speach output"
SAPI_Speak(textfile, SPF_IS_FILENAME Or SVSFIsXML Or SVSFNLPSpeakPunc)


SAPI_Close()

?
? "You reached the end - you can close the box now. ^^"


Sleep()
End



TTSXmlDemo.xml

Code: Select all

<xml version="1.0">

This is a basic functionality test for SAPI5 XML markup within the TTS Engine.  If you haven't done so already, please choose Microsoft Zira Desktop for your voice and check the box labeled "IsXML" before clicking on "Speak" in order to begin the tutorial.

<SAPI>

<VOICE REQUIRED="NAME=Microsoft David Desktop">Hello, my name is Microsoft David Desktop. </VOICE><VOICE REQUIRED="NAME=Microsoft Zira Desktop">Hello, my name is Microsoft Zira Desktop. </VOICE><VOICE REQUIRED="NAME=Microsoft Hazel Desktop">Hello, my name is Microsoft Hazel Desktop. </VOICE>Together we make up Microsoft's SAPI5 Text-to-Speech engine.  With the use of XML tags, we can avoid the normal, default way that we read words and speak in general. 

First of all, <VOICE REQUIRED="NAME=Microsoft Hazel Desktop">you can</VOICE><VOICE REQUIRED="NAME=Microsoft David Desktop">choose</VOICE><VOICE REQUIRED="NAME=Microsoft Zira Desktop">which voice</VOICE><VOICE REQUIRED="NAME=Microsoft Hazel Desktop">you wish to hear</VOICE> through the use of a voice tag.<VOICE REQUIRED="NAME=Microsoft David Desktop">Either Sam, Mary or myself can spell out words for you too.</VOICE>For example, the company "Microsoft" is spelled<SPELL>Microsoft</SPELL><VOICE REQUIRED="NAME=Microsoft Hazel Desktop">and the word "Windows" is spelled <SPELL>windows</SPELL></VOICE>.

<VOICE REQUIRED="NAME=Microsoft David Desktop">We can also change the rate at which we speak.</VOICE><RATE SPEED="10">I am currently speaking at three times my normal rate.</RATE><VOICE REQUIRED="NAME=Microsoft Hazel Desktop"><RATE SPEED="-10">and I am currently speaking at one third my normal rate.</RATE></VOICE>Our pitch can be easily manipulated as well.<VOICE REQUIRED="NAME=Microsoft David Desktop"><PITCH MIDDLE="10">This is an example of a high pitch</PITCH></VOICE><PITCH middle="-10">and this is an example of a low pitch</PITCH>

<VOICE REQUIRED="NAME=Microsoft Hazel Desktop">Another way to adjust the prosody of our speech is through the use of a silence tag.</VOICE><VOICE REQUIRED="NAME=Microsoft David Desktop">With a silence tag, an end user can make one of us pause for up to 65,536 milliseconds.</VOICE>For example, I<SILENCE MSEC="500"/>am<SILENCE MSEC="500"/>pausing<SILENCE MSEC="500"/>500<SILENCE MSEC="500"/>milliseconds<SILENCE MSEC ="500"/>between<SILENCE MSEC ="500"/>each<SILENCE MSEC ="500"/>word<SILENCE MSEC ="500"/>of<SILENCE MSEC ="500"/>this<SILENCE MSEC ="500"/>sentence.

<VOICE REQUIRED="NAME=Microsoft Hazel Desktop">The volume of our individual voices can also be raised and lowered through the use of XML tags.  <VOLUME LEVEL="101">This is the loudest I can speak</VOLUME><VOLUME LEVEL="-101">and this is the softest I can speak.</VOLUME></VOICE>

In order to make our voices sound more natural, an emphasis tag can be used to allow us to place emphasis on certain words in a sentence.  <VOICE REQUIRED="NAME=Microsoft David Desktop">Compare the following two phrases:  The movie will be this friday. <SILENCE MSEC="750"/>  The <EMPH>movie</EMPH> will be <EMPH>this friday.</EMPH>  Pretty neat, don't you think?</VOICE>

Don't worry, that isn't all that we can do through the proper use of XML tags.  <VOICE REQUIRED="NAME=Microsoft Hazel Desktop">An end user can also decide which part of speech to use for each word in a sentence.  Using the part of speech tag, we can force a certain pronunciation of a word without relying on the context around it</VOICE>.   <VOICE REQUIRED="NAME=Microsoft David Desktop">For example, the nominal pronunciation of the word "compact" is <SILENCE MSEC="250"/><PARTOFSP PART="noun">compact</PARTOFSP> and the verbal pronunciation of the word "compact" is <SILENCE MSEC="250"/> <PARTOFSP PART="verb">compact.</PARTOFSP>  We can also force certain pronunciations for modifiers, functions , interjections and abbreviations.

Another great use of XML tags within the TTS Engine is the creation of your own words.</VOICE>  Perhaps you want the computer to say a word that is not in the lexicon, such as "extracalifragilisticexpiallidocious."  As you just heard, we do not recognize this word and have to use letter to sound rules in order to try and guess at a proper pronunciation.  The pronunciation tag may be used to force the correct pronunciation of the word, <PRON SYM="eh 1 k s - t r ax 2 - k ae 1 l - ih 2 - f r ae 1 - jh ax 2 - l ih 1 - s t ih 2 k - eh 1 k s - p iy 2 - ae 1 l - ih 2 - d ow 1 - sh ax 2 s"/>.  Wow, now tell me, doesn't that sound better?

Now let's insert a bookmark here<BOOKMARK MARK="8"/>. Your application should have received a bookmark event with a bookmark id of 8 when speech synthesis has passed this element in the input stream. Bookmark event is an easy way for an application to take action at a given point in the stream.

</SAPI>


Thanks for participating in this tutorial.  I hope you have a better understanding of the basic functionality of XML tag usage within the TTS Engine.  Enjoy!

</xml>


If the defined voices ("NAME=...) in TTSXmlDemo.xml is not set properly the demo will not work.


The example uses englisch words. If you have another language installed you have to change the text accordingly!

If you want to compile it as x64 you need the 64-bit version of libdisphelper.a which can be download here: <Click Me>

I assume that the x86 version of libdisphelper.a is available by default. If not let me know it.

Have fun...

Edit1: changed function name from Speak to SAPI_Speak to follow the SAPI_* name convention and added SAPI_Skip methode.
Edit2: updated the example to get the temp folder for the system environment variable to avoid error messages when dumping to wave
Edit3: some code modification in the bi file and added two example to read file for speaking
Last edited by UEZ on Apr 12, 2020 17:38, edited 10 times in total.
dodicat
Posts: 6390
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: SAPI Voice Engine [Windows only]

Postby dodicat » Apr 10, 2020 0:46

Hi UEZ.
I found this method (invoke vbscript directly).

Code: Select all


sub speak(text as string)
      dim as string x="mshta vbscript:Execute(""CreateObject(""""SAPI.SpVoice"""").Speak("""""+text+""""")(window.close)"")"
      print text
      shell x
  end sub
 
  speak("Goodnight everybody,  stay safe")
  sleep
BasicCoder2
Posts: 3525
Joined: Jan 01, 2009 7:03

Re: SAPI Voice Engine [Windows only]

Postby BasicCoder2 » Apr 10, 2020 2:58

@UEZ

Four error boxes while running code.

Member: .Open(%s,%d,%b)
Function: CallMethod
Error In: InvokeArray
Error: The parameter is incorrect.
Code: 80070057
Source: IDispatch-interface

Member: .Close
Function: CallMethod
Error In: InvokeArray
Error: Unknown runtime error
Code: 80045001
Source: IDispatch-interface

Member: .AudioOutputStream = %o
Function: PutRef
Error In: InvokeArray
Error: Unknown runtime error
Code: 80045001
Source: IDispatch-interface
BasicCoder2
Posts: 3525
Joined: Jan 01, 2009 7:03

Re: SAPI Voice Engine [Windows only]

Postby BasicCoder2 » Apr 10, 2020 3:05

I noticed that windows 10 also has speech to text, can that be used to input text to a FreeBASIC program?
UEZ
Posts: 523
Joined: May 05, 2017 19:59
Location: Germany

Re: SAPI Voice Engine [Windows only]

Postby UEZ » Apr 10, 2020 11:27

BasicCoder2 wrote:@UEZ

Four error boxes while running code.

Member: .Open(%s,%d,%b)
Function: CallMethod
Error In: InvokeArray
Error: The parameter is incorrect.
Code: 80070057
Source: IDispatch-interface

Member: .Close
Function: CallMethod
Error In: InvokeArray
Error: Unknown runtime error
Code: 80045001
Source: IDispatch-interface

Member: .AudioOutputStream = %o
Function: PutRef
Error In: InvokeArray
Error: Unknown runtime error
Code: 80045001
Source: IDispatch-interface


This occurs because C:\Temp doesn't exist. I've updated the example to get the temp path from the system environment variable.

BasicCoder2 wrote:I noticed that windows 10 also has speech to text, can that be used to input text to a FreeBASIC program?

I don't know about this API but I can try to find some documentation.

dodicat wrote:Hi UEZ.
I found this method (invoke vbscript directly).

Good catch. I don't know if this is also a practical way to use the SAPI engine. Anyhow, thanks for sharing.
dodicat
Posts: 6390
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: SAPI Speech Engine build 2020-04-09 beta [Windows only]

Postby dodicat » Apr 12, 2020 15:44

Another method.
I only have two voices here 0 and 1

Code: Select all



Sub savefile(filename As String,p As String)
  Dim As Integer n
  n=Freefile
  If Open (filename For Binary Access Write As #n)=0 Then
    Put #n,,p
    Close
  Else
    Print "Unable to save " + filename
  End If
End Sub

Sub runscript(filename As String)
  Shell "cscript.exe /Nologo "+ filename
End Sub

Function SAR(s0 As String,s1 As String,s2 As String) As String'SearchAndReplace
  Dim s As String=s0
  Var position=Instr(s,s1)
  While position>0
    s=Mid(s,1,position-1) & s2 & Mid(s,position+Len(s1))
    position=Instr(position+Len(s2),s,s1)
  Wend
  SAR=s
End Function

Sub speak(text As String,voice As Long,rate As Long,volume As Long)
  print text 'optional
  Dim As String g 'fixed
  g="set sapi=CreateObject(""SAPI.SpVoice"")"+Chr(13,10)
  g+="Set sapi.Voice = sapi.GetVoices.Item(0)"+Chr(13,10)
  g+="sapi.Rate = 2"+Chr(13,10)
  g+="sapi.volume = 100"+Chr(13,10)
  g+="sapi.Speak ""Hello world"""
 
  Dim As String w=g 'working string
  w=sar(w,"Item(0)","Item("+Str(voice)+")")
  w=sar(w,"Rate = 2","Rate = "+Str(rate))
  w=sar(w,"Hello world",text)
  savefile("voice.vbs",w)
  runscript ("voice.vbs")
  Kill "voice.vbs"
End Sub

speak("Hello there from voice 1",1,2,50)
speak("This should be a different voice, Goodbye",0,2,90)
speak("Press any key to finish",1,5,40)

Sleep
 
BasicCoder2
Posts: 3525
Joined: Jan 01, 2009 7:03

Re: SAPI Speech Engine build 2020-04-12 beta [Windows only]

Postby BasicCoder2 » Apr 13, 2020 10:09

@dodicat
Thanks for the latest contribution on this subject.
It has come up before of course,

viewtopic.php?f=3&t=25306&
Imortis SAPI.bi is different to the SAPI.bi in this thread.

Other posts:
viewtopic.php?f=3&t=25284&
viewtopic.php?f=3&t=25278&

And a thread started by a visually impaired person:
viewtopic.php?f=3&t=25276&
UEZ
Posts: 523
Joined: May 05, 2017 19:59
Location: Germany

Re: SAPI Speech Engine build 2020-04-12 beta [Windows only]

Postby UEZ » Apr 13, 2020 11:13

@dodicat: thank you for your contribution - always appreciated. :-)

@BasicCoder2: many roads lead to Rome. ;-) Maybe I gonna convert my SAPI.bi to the Dot notation syntax...

Return to “Tips and Tricks”

Who is online

Users browsing this forum: Bing [Bot] and 6 guests