how can i use text-to-speech in windows ?
- skinkairewalker
- Addict

- Posts: 824
- Joined: Fri Dec 04, 2015 9:26 pm
how can i use text-to-speech in windows ?
hi everyone , have a way to i use windows voices native in my Pb application ? like text-to-speech ?
Re: how can i use text-to-speech in windows ?
From Nico : Pb 5.44 LTS x86 : http://www.purebasic.fr/french/viewtopi ... ese+vocale
You may need the windows 'runtime : https://www.microsoft.com/en-us/downloa ... x?id=10121
You may need the windows 'runtime : https://www.microsoft.com/en-us/downloa ... x?id=10121
Code: Select all
#CLSCTX_INPROC_SERVER=1
;// Valeur pour SpeechVoiceSpeakFlags
#SVSFDefault = 0
#SVSFlagsAsync = 1
#SVSFPurgeBeforeSpeak = 2
#SVSFIsFilename = 4
#SVSFIsXML = 8
#SVSFIsNotXML = 16
#SVSFPersistXML = 32
#SVSFNLPSpeakPunc = 64
#SVSFNLPMask = 64
#SVSFVoiceMask = 127
#SVSFUnusedFlags = -128
Enumeration ; SPSTREAMFORMAT
#SPSF_Default
#SPSF_NoAssignedFormat
#SPSF_Text
#SPSF_NonStandardFormat
#SPSF_ExtendedAudioFormat
;// Standard PCM wave formats
#SPSF_8kHz8BitMono
#SPSF_8kHz8BitStereo
#SPSF_8kHz16BitMono
#SPSF_8kHz16BitStereo
#SPSF_11kHz8BitMono
#SPSF_11kHz8BitStereo
#SPSF_11kHz16BitMono
#SPSF_11kHz16BitStereo
#SPSF_12kHz8BitMono
#SPSF_12kHz8BitStereo
#SPSF_12kHz16BitMono
#SPSF_12kHz16BitStereo
#SPSF_16kHz8BitMono
#SPSF_16kHz8BitStereo
#SPSF_16kHz16BitMono
#SPSF_16kHz16BitStereo
#SPSF_22kHz8BitMono
#SPSF_22kHz8BitStereo
#SPSF_22kHz16BitMono
#SPSF_22kHz16BitStereo
#SPSF_24kHz8BitMono
#SPSF_24kHz8BitStereo
#SPSF_24kHz16BitMono
#SPSF_24kHz16BitStereo
#SPSF_32kHz8BitMono
#SPSF_32kHz8BitStereo
#SPSF_32kHz16BitMono
#SPSF_32kHz16BitStereo
#SPSF_44kHz8BitMono
#SPSF_44kHz8BitStereo
#SPSF_44kHz16BitMono
#SPSF_44kHz16BitStereo
#SPSF_48kHz8BitMono
#SPSF_48kHz8BitStereo
#SPSF_48kHz16BitMono
#SPSF_48kHz16BitStereo
;// TrueSpeech format
#SPSF_TrueSpeech_8kHz1BitMono
;// A-Law formats
#SPSF_CCITT_ALaw_8kHzMono
#SPSF_CCITT_ALaw_8kHzStereo
#SPSF_CCITT_ALaw_11kHzMono
#SPSF_CCITT_ALaw_11kHzStereo
#SPSF_CCITT_ALaw_22kHzMono
#SPSF_CCITT_ALaw_22kHzStereo
#SPSF_CCITT_ALaw_44kHzMono
#SPSF_CCITT_ALaw_44kHzStereo
;// u-Law formats
#SPSF_CCITT_uLaw_8kHzMono
#SPSF_CCITT_uLaw_8kHzStereo
#SPSF_CCITT_uLaw_11kHzMono
#SPSF_CCITT_uLaw_11kHzStereo
#SPSF_CCITT_uLaw_22kHzMono
#SPSF_CCITT_uLaw_22kHzStereo
#SPSF_CCITT_uLaw_44kHzMono
#SPSF_CCITT_uLaw_44kHzStereo
;// ADPCM formats
#SPSF_ADPCM_8kHzMono
#SPSF_ADPCM_8kHzStereo
#SPSF_ADPCM_11kHzMono
#SPSF_ADPCM_11kHzStereo
#SPSF_ADPCM_22kHzMono
#SPSF_ADPCM_22kHzStereo
#SPSF_ADPCM_44kHzMono
#SPSF_ADPCM_44kHzStereo
;// GSM 6.10 formats
#SPSF_GSM610_8kHzMono
#SPSF_GSM610_11kHzMono
#SPSF_GSM610_22kHzMono
#SPSF_GSM610_44kHzMono
#SPSF_NUM_FORMATS
EndEnumeration
Interface ISpeechObjectTokenCategory Extends IDispatch
get_Id(Id.i)
set_Default(TokenId.i)
get_Default(TokenId.i)
SetId(Id.p-bstr, CreateIfNotExist.i)
GetDataKey(SpeechDataKeyLocation.i, ISpeechDataKey.i)
EnumerateTokens(RequiredAttributes.i, OptionalAttributes.i, ISpeechObjectTokens.i)
EndInterface
Interface ISpeechObjectToken Extends IDispatch
get_Id(ObjectId.i)
get_DataKey(ISpeechDataKey.i)
get_Category(ISpeechObjectTokenCategory.i)
GetDescription(Locale.i, Description.i)
SetId(Id.i, CategoryID.i, CreateIfNotExist.l)
GetAttribute(AttributeName.p-bstr, AttributeValue.i)
CreateInstance(pUnkOuter.i, SpeechTokenContext.l, Object.i)
Remove(ObjectStorageCLSID.i)
GetStorageFileName(ObjectStorageCLSID.i, KeyName,FileName.i, SpeechTokenShellFolder.l, FilePath.i)
RemoveStorageFileName(ObjectStorageCLSID.i, KeyName.i, DeleteFile.l)
IsUISupported(TypeOfUI.i, ExtraData.variant, Object.i, Supported.i)
DisplayUI(hWnd.i, Title.i, TypeOfUI.i, ExtraData.variant, Object.i)
MatchesAttributes(Attributes.i, Matches.i)
EndInterface
Interface ISpeechObjectTokens Extends IDispatch
get_Count(a.l)
Item(Index.l, Token.ISpeechObjectToken)
get__NewEnum(ppEnumVARIANT.IUnknown)
EndInterface
Interface ISpeechAudioFormat Extends IDispatch
get_Type(SpeechAudioFormatType.i)
set_Type(SpeechAudioFormatType.i)
get_Guid(Guid.i)
set_Guid(Guid.i)
GetWaveFormatEx(ISpeechWaveFormatEx.i)
SetWaveFormatEx(ISpeechWaveFormatEx.i)
EndInterface
Interface ISpeechFileStream Extends IDispatch
get_Format(ISpeechAudioFormat.i)
set_putref_Format(ISpeechAudioFormat.i)
Read(Buffer.i, NumberOfBytes.i, BytesRead.i, BytesWritten.i)
Write(Buffer.i, BytesWritten.i)
Seek(Position.i, SpeechStreamSeekPositionType.i, NewPosition.i)
Open(FileName.p-bstr, SpeechStreamFileMode.i, DoEvents.i)
Close()
EndInterface
Interface ISpeechVoiceStatus Extends IDispatch
get_CurrentStreamNumber(StreamNumber.i)
get_LastStreamNumberQueued(StreamNumber.i)
get_LastHResult(Hresult.i)
get_RunningState(State.i)
get_InputWordPosition(Position.i)
get_InputWordLength(Length.i)
get_InputSentencePosition(Position.i)
get_InputSentenceLength(Length.i)
get_LastBookmark(Bookmark.i)
get_LastBookmarkId(BookmarkId.i)
get_PhonemeId(PhoneId.i)
get_VisemeId(VisemeId.i)
EndInterface
Interface ISpeechVoice Extends IDispatch
get_Status(ISpeechVoiceStatus.i)
get_Voice(ISpeechObjectToken.i)
put_Voice(ISpeechObjectToken.i)
get_AudioOutput(ISpeechObjectToken.i)
put_AudioOutput(ISpeechObjectToken.i)
get_AudioOutputStream(ISpeechBaseStream.i)
put_AudioOutputStream(ISpeechBaseStream.i)
get_Rate(long.i)
put_Rate(long.i)
get_Volume(long.i)
put_Volume(long.i)
put_AllowAudioOutputFormatChangesOnNextSet(VARIANT_BOOL.i)
get_AllowAudioOutputFormatChangesOnNextSet(VARIANT_BOOL.i)
get_EventInterests(SpeechVoiceEvents.i)
put_EventInterests(SpeechVoiceEvents.i)
put_Priority(SpeechVoicePriority.i)
get_Priority(SpeechVoicePriority.i)
put_AlertBoundary(SpeechVoiceEvents.i)
get_AlertBoundary(SpeechVoiceEvents.i)
put_SynchronousSpeakTimeout(long.i)
get_SynchronousSpeakTimeout(long.i)
Speak(Text.p-bstr, SpeechVoiceSpeakFlags.l, IDVoice.i)
SpeakStream(ISpeechBaseStream.i, SpeechVoiceSpeakFlags.l, StreamNumber.i)
Pause()
Resume()
Skip(Type.i, NumItems.l, NumSkipped.i)
GetVoices(RequiredAttributes.i, OptionalAttributes.i, ISpeechObjectTokens.i)
GetAudioOutputs(RequiredAttributes.i, OptionalAttributes.i, ISpeechObjectTokens.i)
WaitUntilDone(msTimeout.l, VARIANT_BOOL.i)
SpeakCompleteEvent(Handle.i)
IsUISupported(TypeOfUI.i, ExtraData.VARIANT, VARIANT_BOOL.i)
DisplayUI(hWndParent.i, Title.i, TypeOfUI.i, ExtraData.VARIANT)
EndInterface
Structure AttributeVoice
Description.s
LangID.s
Item.l
Rate.l
Volume.l
SpeechVoice.i
EndStructure
Structure AttributeAudio
Description.s
Item.l
DeviceId.s
EndStructure
Procedure.i ConvertToUnicode(AsciiOrUnicode.s)
Static *MemoryUnicode
Protected LenMemoryUnicode.l
If *MemoryUnicode <> 0
FreeMemory(*MemoryUnicode)
EndIf
LenMemoryUnicode = StringByteLength(AsciiOrUnicode , #PB_Unicode)
*MemoryUnicode = AllocateMemory(LenMemoryUnicode + 2)
If *MemoryUnicode <> 0
PokeS(*MemoryUnicode, AsciiOrUnicode, Len(AsciiOrUnicode), #PB_Unicode)
ProcedureReturn *MemoryUnicode
EndIf
ProcedureReturn 0
EndProcedure
Procedure.i InterfaceData(Option.l, Donnees.i)
Static NameInterface.l
If Option = 1
NameInterface = Donnees
ProcedureReturn 1
ElseIf Option = -1
ProcedureReturn NameInterface
EndIf
ProcedureReturn 0
EndProcedure
Procedure SetInterfaceData(Option.l, Donnees.i)
ProcedureReturn InterfaceData(Option.l, Donnees.i)
EndProcedure
Procedure.i GetInterfaceData(Option.l)
ProcedureReturn InterfaceData(-1, 0)
EndProcedure
Procedure.l SaveTextToWav(Array VoicesSapi.AttributeVoice(1), VoixID.l, Texte.s, File.s, Format.l)
Protected SpeechFileStream.ISpeechFileStream, SpeechAudioFormat.ISpeechAudioFormat
Protected SpeechFileStreamDefault.i, IDVoice.l, NameInterface$, NameInterface.l, Ret.l=-10
Protected SSFMCreateForWrite = 3
If VoixID > -1 And VoixID <= ArraySize(VoicesSapi())
NameInterface = GetInterfaceData(-1)
If NameInterface = 2 ; Speech 11
NameInterface$ = "SAPI.SpFileStream"
ElseIf NameInterface = 1 ; Sapi 5
NameInterface$ = "Speech.SpFileStream"
Else
Ret = -9
Goto Error2
EndIf
If CLSIDFromProgID_(ConvertToUnicode(NameInterface$), @CLSID.CLSID) < #S_OK
Ret = -8
Goto Error2
EndIf
If CLSIDFromString_(ConvertToUnicode("{AF67F125-AB39-4E93-B4A2-CC2E66E182A7}"), @Refiid.CLSID) < #S_OK
Ret = -7
Goto Error2
EndIf
If CoCreateInstance_(Clsid, #Null, #CLSCTX_INPROC_SERVER, Refiid, @SpeechFileStream.ISpeechFileStream) < #S_OK
Ret = -6
Goto Error2
EndIf
If SpeechFileStream\get_Format(@SpeechAudioFormat.ISpeechAudioFormat) < #S_OK
Ret = -5
Goto Error2
EndIf
If SpeechAudioFormat\set_Type(Format) < #S_OK
Ret = -4
Goto Error2
EndIf
If SpeechFileStream\Open(File, SSFMCreateForWrite, 0) < #S_OK
Ret = -3
Goto Error2
EndIf
SpeechVoice.ISpeechVoice = VoicesSapi(VoixID)\SpeechVoice
If SpeechVoice = 0
Ret = -2
Goto Error2
EndIf
If SpeechVoice\get_AudioOutputStream(@SpeechFileStreamDefault) < #S_OK
Ret = -1
Goto Error2
EndIf
If SpeechVoice\put_AudioOutputStream(SpeechFileStream) < #S_OK
Ret = 0
Goto Error2
EndIf
If SpeechVoice\Speak(Texte, 0, @IDVoice) < #S_OK
Ret = 1
Goto Error2
EndIf
error2:
If SpeechFileStream <> 0
SpeechFileStream\Close()
SpeechFileStream\Release()
EndIf
If SpeechAudioFormat <> 0
SpeechAudioFormat\Release()
EndIf
If SpeechFileStreamDefault <> 0
SpeechVoice\put_AudioOutputStream(SpeechFileStreamDefault)
EndIf
EndIf
; Renvoie 1 si la fonction réussie
ProcedureReturn Ret
EndProcedure
Procedure GetAudioOutput(Array VoicesAudio.AttributeAudio(1), *DefaultAudio.long)
Protected SpeechObjectTokenCategory.ISpeechObjectTokenCategory
Protected SpeechObjectTokens.ISpeechObjectTokens
Protected SpeechObjectToken.ISpeechObjectToken
Protected Clsid.CLSID, Refiid.CLSID, NameInterface$
Protected Description.i, DescriptionAudio.s, ID.s, DefaultID.s
Protected a.l, Ret.l=0
#SpeechCategoryAudioOut = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\AudioOutput"
NameInterface = GetInterfaceData(-1)
If NameInterface = 2 ; Speech 11
NameInterface$ = "Speech.SpObjectTokenCategory"
ElseIf NameInterface = 1 ; Sapi 5
NameInterface$ = "Sapi.SpObjectTokenCategory"
Else
Goto Error3
EndIf
If CLSIDFromProgID_(ConvertToUnicode(NameInterface$), @Clsid.CLSID) < #S_OK
Goto Error3
EndIf
If CLSIDFromString_(ConvertToUnicode("{CA7EAC50-2D01-4145-86D4-5AE7D70F4469}"), @Refiid.CLSID) < #S_OK
Goto Error3
EndIf
If CoCreateInstance_(Clsid, #Null, #CLSCTX_INPROC_SERVER, Refiid, @SpeechObjectTokenCategory.ISpeechObjectTokenCategory) >= #S_OK
If SpeechObjectTokenCategory\SetId(#SpeechCategoryAudioOut, 0) >= #S_OK
If SpeechObjectTokenCategory\get_Default(@Description) >= #S_OK
If Description <> 0
DefaultID.s = PeekS(Description, -1, #PB_Unicode)
Debug DefaultID
SysFreeString_(Description)
EndIf
EndIf
If SpeechObjectTokenCategory\EnumerateTokens(0, 0, @SpeechObjectTokens.ISpeechObjectTokens) >= #S_OK
If SpeechObjectTokens\get_Count(@Count.l) >= #S_OK
For a = 0 To count -1
If SpeechObjectTokens\Item(a, @SpeechObjectToken.ISpeechObjectToken) >= #S_OK
If SpeechObjectToken\GetDescription(0, @Description) >= #S_OK
If Description <> 0
DescriptionAudio.s = PeekS(Description, -1, #PB_Unicode)
Debug DescriptionAudio
SysFreeString_(Description)
VoicesAudio(a)\Description = DescriptionAudio
Ret = Ret + 1
EndIf
If SpeechObjectToken\get_Id(@Description) >= #S_OK
If Description <> 0
ID.s = PeekS(Description, -1, #PB_Unicode)
Debug ID
VoicesAudio(a)\DeviceId = ID
If DefaultID = ID
*DefaultAudio\l = a
EndIf
EndIf
SysFreeString_(Description)
EndIf
VoicesAudio(a)\Item = a
EndIf
SpeechObjectToken\Release()
EndIf
Next a
EndIf
SpeechObjectTokens\Release()
EndIf
EndIf
SpeechObjectTokenCategory\Release()
EndIf
Error3:
ProcedureReturn Ret
EndProcedure
Procedure SetAudioOutput(Array VoicesSapi.AttributeVoice(1), Item.l)
Protected SpeechObjectTokenCategory.ISpeechObjectTokenCategory
Protected SpeechObjectTokens.ISpeechObjectTokens
Protected SpeechObjectToken.ISpeechObjectToken
Protected Clsid.CLSID, Refiid.CLSID, NameInterface$, NameInterface.l
Protected Description.i, DescriptionAudio.s, a.l, Ret.l=0
Protected SpeechVoice.ISpeechVoice
#SpeechCategoryAudioOut = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\AudioOutput"
If Item > -1 And Item <= ArraySize(VoicesSapi())
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
Debug "SpeechVoice " + SpeechVoice
NameInterface = GetInterfaceData(-1)
If NameInterface = 2 ; Speech 11
NameInterface$ = "Speech.SpObjectTokenCategory"
ElseIf NameInterface = 1 ; Sapi 5
NameInterface$ = "Sapi.SpObjectTokenCategory"
Else
Goto Error5
EndIf
If CLSIDFromProgID_(ConvertToUnicode(NameInterface$), @Clsid.CLSID) < #S_OK
Goto Error5
EndIf
If CLSIDFromString_(ConvertToUnicode("{CA7EAC50-2D01-4145-86D4-5AE7D70F4469}"), @Refiid.CLSID) < #S_OK
Goto Error5
EndIf
If CoCreateInstance_(Clsid, #Null, #CLSCTX_INPROC_SERVER, Refiid, @SpeechObjectTokenCategory.ISpeechObjectTokenCategory) >= #S_OK
If SpeechObjectTokenCategory\SetId(#SpeechCategoryAudioOut, 0) >= #S_OK
If SpeechObjectTokenCategory\EnumerateTokens(0, 0, @SpeechObjectTokens.ISpeechObjectTokens) >= #S_OK
If SpeechObjectTokens\Item(Item, @SpeechObjectToken.ISpeechObjectToken)>= #S_OK
If SpeechObjectToken <> 0
If SpeechVoice\put_AudioOutput(SpeechObjectToken)>= #S_OK
Ret = 1
EndIf
SpeechObjectToken\Release()
EndIf
EndIf
SpeechObjectTokens\Release()
EndIf
EndIf
SpeechObjectTokenCategory\Release()
EndIf
EndIf
EndIf
Error5:
ProcedureReturn Ret
EndProcedure
Procedure.l FreeSpeakVoice(Array VoicesSapi.AttributeVoice(1))
Protected SpeechVoice.ISpeechVoice, a.l
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
SpeechVoice\Pause()
SpeechVoice\Release()
For a = 0 To ArraySize(VoicesSapi())
VoicesSapi(a)\SpeechVoice = 0
Next a
Debug "Free InterfaceVoice -> OK"
ProcedureReturn #True
EndIf
ProcedureReturn #False
; Renvoi vrai ou faux
EndProcedure
Procedure.l InitSpeakVoice(Array VoicesSapi.AttributeVoice(1), NameInterface.l)
Protected ClsidSpVoice.i, RefiidISpeechVoice.i, Clsid.CLSID, Refiid.CLSID, Language.i
Protected SpeechVoice.ISpeechVoice, SpeechObjectTokens.ISpeechObjectTokens
Protected SpeechObjectToken.ISpeechObjectToken, SpeechObjectTokenCategory.ISpeechObjectTokenCategory
Protected LangIDVoice.s, DescriptionVoice.s, Ret.l = -2, Longueur.l, a.l
Protected NameInterface$, Count.l, Lang.i, Description.i
; Sécurité, afin de libérer l'interface Sapi.SpVoice si déjà créé
FreeSpeakVoice(VoicesSapi())
Longueur = ArraySize(VoicesSapi())
;
; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices
If NameInterface = 2 ; Speech 11
NameInterface$ = "Speech.SpVoice" ; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech Server\v11.0\Voices
SetInterfaceData(1, 2)
ElseIf NameInterface = 1 ; Sapi 5
NameInterface$ = "SAPI.SpVoice" ; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices
SetInterfaceData(1, 1)
Else
SetInterfaceData(1, 0)
Ret = -1
Goto Error
EndIf
If CLSIDFromProgID_(ConvertToUnicode(NameInterface$), @Clsid.CLSID) < #S_OK
Goto Error
EndIf
If CLSIDFromString_(ConvertToUnicode("{269316D8-57BD-11D2-9EEE-00C04F797396}"), @Refiid.CLSID) < #S_OK
Goto Error
EndIf
If CoCreateInstance_(Clsid, #Null, #CLSCTX_INPROC_SERVER, Refiid, @SpeechVoice) >= #S_OK
Ret = 0
If SpeechVoice\GetVoices(0, 0, @SpeechObjectTokens) >= #S_OK
If SpeechObjectTokens\get_Count(@Count) >= #S_OK
;Listing des voix installés
For a= 0 To Count-1
If SpeechObjectTokens\Item(a, @SpeechObjectToken) >= #S_OK
If SpeechObjectToken\GetDescription(0, @Description) >= #S_OK
If Description <> 0
DescriptionVoice = PeekS(Description, -1, #PB_Unicode)
SysFreeString_(Description)
EndIf
EndIf
If SpeechObjectToken\GetAttribute("Language", @Lang) >= #S_OK
If Lang <> 0
LangIDVoice = PeekS(Lang, -1, #PB_Unicode)
SysFreeString_(Lang)
EndIf
EndIf
If a < (Longueur + 1)
VoicesSapi(a)\Description = DescriptionVoice
VoicesSapi(a)\LangID = LangIDVoice
VoicesSapi(a)\Item = a
VoicesSapi(a)\Rate = 0
VoicesSapi(a)\Volume = 100
VoicesSapi(a)\SpeechVoice = SpeechVoice
Ret = a + 1
EndIf
SpeechObjectToken\Release()
EndIf
Next
EndIf
SpeechObjectTokens\Release()
EndIf
EndIf
Error:
If ClsidSpVoice <> 0
FreeMemory(ClsidSpVoice)
EndIf
If RefiidSpVoice <> 0
FreeMemory(RefiidSpVoice)
EndIf
ProcedureReturn Ret
; Renvoi une valeur > 0 indiquant le nombre de voix
; Renvoi 0 si pas de voix installées (possible si le Runtime est installé mais pas les voix!)
; Renvoi -1 si Sapi 5 ou Speech Plateform 11 non installés
; Renvoi -2 si InterfaceName n'as pas la valeur recquise
EndProcedure
Procedure.l PauseSpeak(Array VoicesSapi.AttributeVoice(1))
Protected SpeechVoice.ISpeechVoice
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
If SpeechVoice\Pause() >= #S_OK
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
; Renvoi vrai ou faux
EndProcedure
Procedure.l ResumeSpeak(Array VoicesSapi.AttributeVoice(1))
Protected SpeechVoice.ISpeechVoice
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
If SpeechVoice\Resume() >= #S_OK
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
; Renvoi vrai ou faux
EndProcedure
Procedure.l StatusSpeak(Array VoicesSapi.AttributeVoice(1))
Protected SpeechVoice.ISpeechVoice, State.l=-1
Protected SpeechVoiceStatus.ISpeechVoiceStatus
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
If SpeechVoice\get_Status(@SpeechVoiceStatus) >= #S_OK
SpeechVoiceStatus\get_RunningState(@State)
Debug "RunningState = " + Str(State)
SpeechVoiceStatus\Release()
EndIf
EndIf
ProcedureReturn State
; Renvoi 2 si Sapi en cours d'utilisation
; Renvoi 1 si Sapi ok
; Renvoi 0 si Speak non lancé une première fois
; Renvoi -1 si échec de la fonction
EndProcedure
Procedure.l CurrentStream(Array VoicesSapi.AttributeVoice(1))
Protected SpeechVoice.ISpeechVoice, Number.l = -1
Protected SpeechVoiceStatus.ISpeechVoiceStatus
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
If SpeechVoice\get_Status(@SpeechVoiceStatus) >= #S_OK
SpeechVoiceStatus\get_CurrentStreamNumber(@Number)
SpeechVoiceStatus\Release()
EndIf
EndIf
ProcedureReturn Number
; Renvoi l'ID du Stream en cours, si 0 pas de Stream en cours
; Renvoi -1 si échec de la fonction
EndProcedure
Procedure.l SkipStream(Array VoicesSapi.AttributeVoice(1), Item.l)
Protected SpeechVoice.ISpeechVoice, Sentence.i, ItemSkipped.l
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
If SpeechVoice\Skip(ConvertToUnicode("SENTENCE"), Item, @ItemSkipped) >= #S_OK
ProcedureReturn ItemSkipped
EndIf
EndIf
ProcedureReturn #False
; Renvoi le nombre de phrase sautée, peut être positif ou négatif
; Renvoi 0 si échec de la fonction
EndProcedure
Procedure.l InputSentenceLength(Array VoicesSapi.AttributeVoice(1))
Protected SpeechVoice.ISpeechVoice, Lenght.l = -1
Protected SpeechVoiceStatus.ISpeechVoiceStatus
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
If SpeechVoice\get_Status(@SpeechVoiceStatus) >= #S_OK
SpeechVoiceStatus\get_InputSentenceLength(@Lenght)
SpeechVoiceStatus\Release()
EndIf
EndIf
ProcedureReturn Lenght
; Renvoi la longueur de texte de la phrase en cours
; Renvoi -1 si échec de la fonction
EndProcedure
Procedure.l PlaySpeakAsync(Array VoicesSapi.AttributeVoice(1), VoixID.l, Texte.s, *Stream.long = 0, Rate.l = -20, Volume.l = -1)
Protected SpeechVoice.ISpeechVoice, StreamNumber.l, Ret.l = 0, Ret2.l
Protected SpeechObjectTokens.ISpeechObjectTokens, SpeechObjectToken.ISpeechObjectToken
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
If VoixID > -1 And VoixID <= ArraySize(VoicesSapi())
If SpeechVoice\GetVoices(0, 0, @SpeechObjectTokens) >= #S_OK
If SpeechObjectTokens\Item(VoixID, @SpeechObjectToken) >= #S_OK
If SpeechVoice\put_Voice(SpeechObjectToken) >= #S_OK
Ret2 = 1
EndIf
SpeechObjectToken\Release()
EndIf
SpeechObjectTokens\Release()
EndIf
If Volume = -1
SpeechVoice\put_Volume(VoicesSapi(VoixID)\Volume)
Else
If SpeechVoice\put_Volume(Volume) >= #S_OK
VoicesSapi(VoixID)\Volume = Volume
EndIf
EndIf
If Rate = -20
SpeechVoice\put_Rate(VoicesSapi(VoixID)\Rate)
Else
If SpeechVoice\put_Rate(Rate) >= #S_OK
VoicesSapi(VoixID)\Rate = Rate
EndIf
EndIf
EndIf
If SpeechVoice\Speak(Texte, #SVSFlagsAsync, @StreamNumber) >= #S_OK
If *Stream <> 0
*Stream\l = StreamNumber
EndIf
Ret = Ret2 + 1
EndIf
EndIf
ProcedureReturn Ret
; Renvoi 2 si la fonction réussie avec l'indice de Voix spécifié
; Renvoi 1 si la fonction réussie alors que l'indice de Voix n'est pas spécifié ou 1 si l'indice de Voix est spécifié mais non trouvé (voix par défaut dans ce cas)
; Renvoi 0 si la fonction SpeechVoice\Speak échoue
EndProcedure
Procedure.l StopSpeak(Array VoicesSapi.AttributeVoice(1))
Protected SpeechVoice.ISpeechVoice, IDVoice.l
SpeechVoice = VoicesSapi(0)\SpeechVoice
If SpeechVoice <> 0
; Le ResumeSpeak est nécessaire au cas où l'état précédent est en Pause
; car sinon il faudrait faire un ResumeSpeak après un nouveau Speak
ResumeSpeak(VoicesSapi())
If SpeechVoice\Speak("", #SVSFPurgeBeforeSpeak, 0) >= #S_OK
Debug "Stop -> OK"
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
; Renvoi vrai ou faux
EndProcedure
; Début de création du programme
Enumeration
#Menu
EndEnumeration
Enumeration
#Window
EndEnumeration
Enumeration
#TimerDetectSpeakfinish
EndEnumeration
Enumeration
#Indication
#Voix
#LangID
#Edit
#TextRate
#Rate
#Precision
#TextVolume
#Volume
#Speak
#Pause
#Resume
#Stop
#SaveToWav
EndEnumeration
; invoquer Coinitialize_() qu'une seule fois dans le programme
CoInitialize_(0)
#SAPI_5 = 1
#SPEECH_11 = 2
; // Initialisation du tableau
; Il sera redimensionné par la suite
#LmiteNbVoices = 30
Dim VoicesSapi1.AttributeVoice(#LmiteNbVoices)
; ----------------------------------------------
; // Déclaration du premier index pour le menu qui servira à l'affichage des voix
#DebutIndiceVoix = 10
#DebutIndiceAudio = 100
; ----------------------------------------------
If OpenWindow(#Window, 200, 200, 400, 500, "PureBasic - SAPI 5 / SPEECH 11 - Asynchrone")
TextGadget(#Indication, 10, 10, 380, 40, "Le choix de la voix ne modifie pas celle par défaut dans le panneau de configuration!")
TextGadget(#Voix, 10, 50, 380, 40, "Voix sélectionnée :")
TextGadget(#LangID, 10, 80, 380, 20, "LandID :")
SetGadgetColor(#Voix, #PB_Gadget_FrontColor, RGB(255,0,0))
SetGadgetColor(#LangID, #PB_Gadget_FrontColor, RGB(255,0,0))
; // InitSpeakVoice initialise l'interface Sapi.SpVoice et met à jour dans le tableau en argument la liste des voix installées
; La valeur de retour de la fonction permet de savoir si on a pu obtenir un pointeur Sapi.SpVoice ainsi que le nombre de voix installées
If CreateMenu(#Menu, WindowID(0))
MenuTitle("Sélection de la Voix")
; Au choix, choisir #SPEECH_11 ou #SAPI_5, vous pouvez tester l'un ou l'autre
; comme dans cet exemple
NbVoice = InitSpeakVoice(VoicesSapi1(), #SPEECH_11)
If NbVoice < 0
NbVoice = InitSpeakVoice(VoicesSapi1(), #SAPI_5)
EndIf
If NbVoice > 0
; On redimensionne le tableau avec le nombre exacte de voix, -1 car commence à 0
ReDim VoicesSapi1(NbVoice-1)
Debug "------------------------------"
Debug "Nombre de Voix = " + Str(NbVoice)
For a = 0 To NbVoice -1
MenuItem( #DebutIndiceVoix + a, VoicesSapi1(a)\Description)
Debug "------------------------------"
Debug "Description = " + VoicesSapi1(a)\Description
Debug "LangID = " + VoicesSapi1(a)\LangID
Debug "------------------------------"
Next
; la voix par défaut est 0 d'après mes essais.
SetMenuItemState(#Menu, #DebutIndiceVoix, #True)
VoiceSapi1 = 0
SetGadgetText(#Voix, "Voix sélectionnée : " + VoicesSapi1(VoiceSapi1)\Description)
SetGadgetText(#LangID, "LandID : " + VoicesSapi1(VoiceSapi1)\LangID)
ElseIf NbVoice = 0
SetGadgetText(#Voix, "Voix sélectionnée : Pas de voix installée")
MenuItem( #DebutIndiceVoix, "Pas de voix installée")
Else
SetGadgetText(#Voix, "Voix sélectionnée : Aucune, Veuillez installer SAPI 5")
MenuItem( #DebutIndiceVoix, "Veuillez installer SAPI 5")
EndIf
MenuTitle("Sortie Audio")
Dim SortieAudio.AttributeAudio(10)
CountAudioOutput.l = GetAudioOutput(SortieAudio(), @DefautAudio)
If CountAudioOutput > 0
For a = 0 To CountAudioOutput - 1
MenuItem(#DebutIndiceAudio + a, SortieAudio(a)\Description)
Next a
SetMenuItemState(#Menu, #DebutIndiceAudio + DefautAudio, #True)
Else
MenuItem(#DebutIndiceAudio, "Erreur Sortie Audio")
EndIf
EndIf
EditorGadget(#Edit, 10, 100, 380, 40)
SetGadgetText(#Edit, "Purebasic is very nice! Purebasic est génial! ")
TextGadget(#Precision, 10, 220, 380, 40, "Précision : le % du volume est en rapport avec le volume réglé actuellement, permet seulement de le baisser par rapport au niveau actuel!")
TextGadget(#TextVolume, 10, 260, 380, 20, "Volume")
TrackBarGadget(#Volume, 10, 280, 380, 20, 0, 100)
TextGadget(#TextRate, 10, 160, 380, 20, "Vitesse")
TrackBarGadget(#Rate, 10, 180, 380, 20, 0, 20)
ButtonGadget(#Speak, 20, 320, 80, 30, "Speak")
ButtonGadget(#Pause, 110, 320, 80, 30, "Pause")
ButtonGadget(#Resume, 200, 320, 80, 30, "Resume")
ButtonGadget(#Stop, 290, 320, 80, 30, "Stop")
ButtonGadget(#SaveToWav, 20, 370, 80, 30, "Save to Wav")
DisableGadget(#Resume, 1)
DisableGadget(#Pause, 1)
DisableGadget(#Stop, 1)
If NbVoice < 1
DisableGadget(#Speak, 1)
EndIf
Volume = 100
Rate = 0
SetGadgetState(#Volume, Volume)
SetGadgetState(#Rate, Rate + 10)
SetGadgetText(#TextVolume, "Volume = " + Str(Volume) + "%")
SetGadgetText(#TextRate, "Vitesse = " + Str(Rate) + " ( -10 à + 10 ), Vitesse normale = 0")
Repeat
Select WaitWindowEvent()
Case #PB_Event_Menu
EventMenu = EventMenu()
Select EventMenu
Case #DebutIndiceVoix To (#DebutIndiceVoix + NbVoice-1)
For a = #DebutIndiceVoix To (#DebutIndiceVoix + NbVoice-1)
SetMenuItemState(#Menu, a, #False)
Next
SetMenuItemState(#Menu, EventMenu, #True)
VoiceSapi1 = EventMenu - #DebutIndiceVoix
SetGadgetText(#Voix, "Voix sélectionnée : " + VoicesSapi1(VoiceSapi1)\Description)
SetGadgetText(#LangID, "LandID : " + VoicesSapi1(VoiceSapi1)\LangID)
Case #DebutIndiceAudio To (#DebutIndiceAudio + CountAudioOutput-1)
For a = #DebutIndiceAudio To (#DebutIndiceAudio + CountAudioOutput-1)
SetMenuItemState(#Menu, a, #False)
Next
SetMenuItemState(#Menu, EventMenu, #True)
Debug "/////////////////////////"
Debug EventMenu - #DebutIndiceAudio
SetAudioOutput(VoicesSapi1(), EventMenu - #DebutIndiceAudio)
EndSelect
Case #PB_Event_Timer
Select EventTimer()
Case #TimerDetectSpeakfinish
; En pause, le StatusSpeak est 0, en fait il n'y a pas d'état
; En cours il est de 2
; Prêt il est de 1
Debug InputSentenceLength(VoicesSapi1())
If StatusSpeak(VoicesSapi1()) = 1
RemoveWindowTimer(#Window, #TimerDetectSpeakfinish)
DisableGadget(#Speak, 0)
DisableGadget(#Resume, 1)
DisableGadget(#Pause, 1)
DisableGadget(#Stop, 1)
EndIf
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #SaveToWav
Texte.s = GetGadgetText(#Edit)
File$ = SaveFileRequester("Enregistrer le fichier sous...", "c:\", "*.wav", 0)
If File$ <> ""
If LCase(Right(File$, 3)) <> "wav"
File$ = File$ + ".wav"
EndIf
Debug File$
If SaveTextToWav(VoicesSapi1(), VoiceSapi1, Texte, File$, #SPSF_22kHz16BitMono)
MessageRequester("Info", "Texte To Wav Réussie!")
EndIf
EndIf
Case #Volume
Volume = GetGadgetState(#Volume)
SetGadgetText(#TextVolume, "Volume = " + Str(Volume) + "%")
Case #Rate
Rate = GetGadgetState(#Rate) - 10
SetGadgetText(#TextRate, "Vitesse = " + Str(Rate) + " ( -10 à + 10 ), Vitesse normale = 0")
Case #Speak
Texte.s = GetGadgetText(#Edit)
If PlaySpeakAsync( VoicesSapi1(), VoiceSapi1, Texte, @Stream, Rate, Volume) > 0
; Timer de détection de Fin de Lecture du Texte
AddWindowTimer(#Window, #TimerDetectSpeakfinish, 500)
DisableGadget(#Speak, 1)
DisableGadget(#Pause, 0)
DisableGadget(#Stop, 0)
Else
MessageRequester("Info", "La fonction Speak a échoué sur la voix sélectionnée!")
EndIf
Case #Pause
DisableGadget(#Resume, 0)
DisableGadget(#Pause, 1)
DisableGadget(#Speak, 1)
PauseSpeak(VoicesSapi1())
Case #Resume
DisableGadget(#Resume, 1)
DisableGadget(#Pause, 0)
ResumeSpeak(VoicesSapi1())
Case #Stop
DisableGadget(#Speak, 0)
DisableGadget(#Resume, 1)
DisableGadget(#Pause, 1)
DisableGadget(#Stop, 1)
StopSpeak(VoicesSapi1())
EndSelect
Case #PB_Event_CloseWindow
Quit = 1
EndSelect
Until Quit = 1
EndIf
; Libérer les ressources avant de quitter
; N'as pas d'effet si déjà libéré
FreeSpeakVoice(VoicesSapi1())
; invoquer CoUninitialize_() qu'une seule fois dans le programme
CoUninitialize_()
End
~Ar-S~
My Image Hoster for PB users
My webSite (french) with PB apps : LDVMULTIMEDIA
PB - 3.x / 5.7x / 6 - W11 x64 - Ryzen 7 3700x / #Rpi4
My Image Hoster for PB users
My webSite (french) with PB apps : LDVMULTIMEDIA
PB - 3.x / 5.7x / 6 - W11 x64 - Ryzen 7 3700x / #Rpi4
Code: Select all
r3p347 : 7ry : un71l d0n3 = 1Re: how can i use text-to-speech in windows ?
You can also try Dobro Lib :
http://forums.purebasic.com/english/vie ... 55518be52c
http://forums.purebasic.com/english/vie ... 55518be52c
~Ar-S~
My Image Hoster for PB users
My webSite (french) with PB apps : LDVMULTIMEDIA
PB - 3.x / 5.7x / 6 - W11 x64 - Ryzen 7 3700x / #Rpi4
My Image Hoster for PB users
My webSite (french) with PB apps : LDVMULTIMEDIA
PB - 3.x / 5.7x / 6 - W11 x64 - Ryzen 7 3700x / #Rpi4
Code: Select all
r3p347 : 7ry : un71l d0n3 = 1- skinkairewalker
- Addict

- Posts: 824
- Joined: Fri Dec 04, 2015 9:26 pm
Re: how can i use text-to-speech in windows ?
thanks you very muchar-s wrote:You can also try Dobro Lib :
http://forums.purebasic.com/english/vie ... 55518be52c
- skinkairewalker
- Addict

- Posts: 824
- Joined: Fri Dec 04, 2015 9:26 pm
Re: how can i use text-to-speech in windows ?
i am using : http://espeak.sourceforge.net/ to try create Text-To-Speech
here my espeak code :
how can i fix it code to works ?
here my espeak code :
Code: Select all
Define.i espeakCHARS_AUTO = 0
Define.i espeakCHARS_UTF8 = 1
Define.i espeakCHARS_8BIT = 2
Define.i espeakCHARS_WCHAR = 3
Define.i espeakCHARS_16BIT = 4
Define.i EE_OK = 0
Define.i EE_INTERNAL_ERROR = -1
Define.i EE_BUFFER_FULL = 1
Define.i EE_NOT_FOUND = 2
Prototype.i Proto_espeak_Initialize(audio_output.i,buflength.i,path.p-utf8,options.i)
Prototype.i Proto_espeak_Synth(text.p-utf8,textLen.i,position.i,position_type.i,end_position.i,flags.i,unique_identifier.i,user_data.i)
If ( OpenLibrary(0,"espeak_sapi.dll") <> 0)
espeak_Initialize.Proto_espeak_Initialize = GetFunction(0,"espeak_Initialize")
espeak_Synth.Proto_espeak_Synth = GetFunction(0,"espeak_Synth")
Debug espeak_Initialize(4,0,GetCurrentDirectory(),0)
; Debug espeak_Synth("Hello World",StringByteLength("Hello World",#PB_UTF8),0,0,0,espeakCHARS_AUTO,#Null,#Null)
; espeak_Synth have "error : invalid memory acess ( error adress 0 ) ... how can i fix it ?
EndIf
- Michael Vogel
- Addict

- Posts: 2835
- Joined: Thu Feb 09, 2006 11:27 pm
- Contact:
Re: how can i use text-to-speech in windows ?
I like that one, but when compiling for 64 bit, the code crashes at 'If SpeechVoice\GetVoices(0, 0, @SpeechObjectTokens) >= #S_OK'ar-s wrote:From Nico : Pb 5.44 LTS x86 : http://www.purebasic.fr/french/viewtopi ... ese+vocale
You may need the windows 'runtime : https://www.microsoft.com/en-us/downloa ... x?id=10121
Code: Select all
[...] Procedure.l InitSpeakVoice(Array VoicesSapi.AttributeVoice(1), NameInterface.l) [...] If NameInterface = 2 ; Speech 11 NameInterface$ = "Speech.SpVoice" ; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech Server\v11.0\Voices SetInterfaceData(1, 2) ElseIf NameInterface = 1 ; Sapi 5 NameInterface$ = "SAPI.SpVoice" ; HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices SetInterfaceData(1, 1) Else SetInterfaceData(1, 0) Ret = -1 Goto Error EndIf If CLSIDFromProgID_(ConvertToUnicode(NameInterface$), @Clsid.CLSID) < #S_OK Goto Error EndIf If CLSIDFromString_(ConvertToUnicode("{269316D8-57BD-11D2-9EEE-00C04F797396}"), @Refiid.CLSID) < #S_OK Goto Error EndIf If CoCreateInstance_(Clsid, #Null, #CLSCTX_INPROC_SERVER, Refiid, @SpeechVoice) >= #S_OK Ret = 0 If SpeechVoice\GetVoices(0, 0, @SpeechObjectTokens) >= #S_OK If SpeechObjectTokens\get_Count(@Count) >= #S_OK ; invoquer CoUninitialize_() qu'une seule fois dans le programme [...]
When forcing the NameInterface=1, everything works fine.
Re: how can i use text-to-speech in windows ?
I use this by RSBasic -> viewtopic.php?f=27&t=70342
Re: how can i use text-to-speech in windows ?
Hi, I just tried the first example posted here.
I do get speech output. but I can't seem to set the output audio device. which ever audio device i select in the example. it still sends the speech output to the default windows output device.
any help please.
Martin
I do get speech output. but I can't seem to set the output audio device. which ever audio device i select in the example. it still sends the speech output to the default windows output device.
any help please.
Martin

