Voici les liens de téléchargement:
Le runtime
https://www.microsoft.com/en-us/downloa ... x?id=10121
Les voix:
Faire une recherche sur virginie ou sur le fichier RSSolo4French.zip
Vous pouvez aussi le télécharger en passant par le site du créateur du logiciel Balabolka qui permet de tester la synthèse vocale Sapi 4, Sapi 5 et Speech 11, cela vous permettra aussi de vérifier le bon fonctionnement de ce programme.
http://www.cross-plus-a.com/fr/balabolka.htm
Pour Vista et supérieur, il faut installer le runtime et les voix:
- Il faut télécharger le runtime x86 ou x64 (On ne peut pas installer les deux versions, il faut choisir !)
Voici les liens de téléchargement:
Le Runtime :
http://www.microsoft.com/en-us/download ... x?id=27225
Les voix, il y en a 26 disponible au total (Hortense pour le Français):
Les fichiers commençant par MSSpeech_TTS sont pour la synthèse de la parole (ce sont les voix qui nous intéresse)
Les fichiers commençant par MSSpeech_SR sont pour la reconnaissance vocale (pas utile ici)
http://www.microsoft.com/en-us/download ... x?id=27224
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[Mise à jour du 23/12/15 - 13H38]
Ajout de la fonction SkipStream(...) qui permet de se déplacer dans la lecture en cours, avancer ou reculer.
[Mise à jour du 23/12/15 - 17H40]
Correction -> LangId ne s'affichait pas en compilation Ascii
[Mise à jour du 23/12/15 - 20H32]
Ajout de la fonction StopSpeak()
Notification Fin Lecture ->Mise en place de la détection automatique de la fin de lecture du Texte avec un Timer.
[Mise à jour du 23/12/15 - 21H21]
Recodage de la Notification de Fin de Lecture, nettement mieux maintenant.
[Mise à jour du 27/12/15 - 22H26]
Compatibilité Sapi 5 (XP et supérieur) et Speech SDK 11 (Vista et supérieur - 26 langues)
Refonte des arguments des fonctions afin de pouvoir créer plusieurs instances de l'interface, donc pour une deuxième interface, on initialise un nouveau tableau.
Le tableau est donc en argument pour toutes les fonctions.
[Mise à jour du 30/12/15 - 20H37]
Ajout de la fonction SaveTextToWav(...) qui permet donc d'enregistrer du texte écrit en fichier son wav.
[Mise à jour du 30/12/15 - 21H44]
Correction, amélioration du code
[Mise à jour du 31/12/15 - 13H57]
Ajout de deux fonctions, GetAudioOutput et SetAudioOutput, l'exemple affiche un menu pour choisir la sortie audio.
Code : Tout sélectionner
#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
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
;;