TTS - Sapi 5 (XP et plus) et Speech SDK 11 (Vista et plus)

Partagez votre expérience de PureBasic avec les autres utilisateurs.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

TTS - Sapi 5 (XP et plus) et Speech SDK 11 (Vista et plus)

Message par nico »

Pour XP, installer le runtime si ce n'est pas déjà fait et utiliser des voix Sapi 5

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 

;;
Dernière modification par nico le jeu. 07/janv./2016 20:00, modifié 24 fois.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

Petite correction mineure, code mis à jour.
Avatar de l’utilisateur
Micoute
Messages : 2583
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Sapi 5 mis à jour

Message par Micoute »

Bonjour nico, c'est une superbe réalisation, merci pour le partage.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 6.20 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

Merci à toi. :)

Mise à jour, voir le premier post.
Avatar de l’utilisateur
Ar-S
Messages : 9539
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Sapi 5 mis à jour

Message par Ar-S »

Superbe,ça me servira sans aucun doute !
Merci !
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

Merci.

Il y a plein de choses a rajouter notamment toutes les fonctions de IspeechVoiceStatus, je n'en ai mis que quelques unes, c'est très simple à ajouter, il suffit de regarder ce qui existe déjà; c'est juste qu'il faut créer les exemples qui vont avec pour bien montrer a quoi ça sert.

Je voudrais aussi ajouter la possibilité de choisir la sortie audio, c'est très simple à faire puisque ça revient au même que pour spécifier une voix sauf que c'est de l'audio.

Et aussi récupérer les events et les traiter dans une procédure (Ce sera plus compliqué à faire sans utiliser ComatePlus, mais je pense pas que ça va me poser un problème, vu que je m'était amuser à le faire avec IE) mais bon là, j'ai plus trop le temps.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

Correction d'une petite erreur, voir premier post.

J'en profite pour indiquer que si vous souhaitez connaître dans quel langage sont les voix au delà de l'indication french dans la description, il faut checker le LangID, par exemple pour le "Français France" c'est '40C', pour le "Français Canadien" c'est 'C0C' pour l' "English Américain" c'est '409' et ainsi de suite.

Pour connaître toutes les références des Identifiants des Langues, c'est ici:
https://msdn.microsoft.com/en-us/librar ... e.14).aspx
Marc56
Messages : 2196
Inscription : sam. 08/févr./2014 15:19

Re: Sapi 5 mis à jour

Message par Marc56 »

Beau boulot nico. :)
Pas testé car en déplacement et avec juste un portable c'est pénible pour faire du developp.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

Mise à jour, voir premier post.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

Mise à jour, voir premier post.

Bon je crois que ce sera la dernière pour aujourd'hui.
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Sapi 5 mis à jour

Message par Kwai chang caine »

Marche niquel sur ma charette XP PRO SP3
Merci de ton partage 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

Salut Kwai chang caine, content que ça te plaise. :D
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Sapi 5 mis à jour

Message par Kwai chang caine »

Tu m’étonnes....que pourrait demander de mieux un geek boutonneux à douche hebdomadaire que d'entendre ce qu'il a de plus cher au monde pouvoir lui parler 8O
Un peu comme si le vagabond entendait une nuit sous un pont, son fidèle compagnon à quatre pattes, lui dire : "Rooobert !!! tu prends tout le journal qui nous sert de couverture !!!" :?

Maintenant c'est devenu banal, comme beaucoup trop de chose d’ailleurs, de parler avec un objet
Mais je me rappelle des premiers balbutiements des machines (Rien à voir avec TERMINATOR... hein !! :wink:)
J’étais émerveillé...et cette admiration je l'ai toujours lorsque sortent les syllabes, une à une de mes haut parleurs 8)

Le seul truc que je trouve dommage, c'est que depuis le temps CROCRO ai pas simplifié la mise en oeuvre, installation des voix et tout le toutim.
Moi j'aurais bien vu une petite DLL à la sauce SQlite, quelques API et hop à nous molière et Shakespeare :mrgreen:

En tout cas, je parle même pas de la complexité de ton code..... 8O
Encore merci à toi, de te casser la tète pour nous faire découvrir, les fabuleux pouvoirs des machines à nous remplacer un jour :lol:
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Sapi 5 mis à jour

Message par nico »

C'est vrai que les Object Com sont compliqués à utiliser, heureusement qu'il y a des exemples.

Concernant une fonction, je ne trouvais pas celle pour Stop, je n’avais pas pris assez de temps pour examiner la fonction Speak et en teléchargeant le SDK 5.1, j'ai regardé l'exemple de l’appli TTS et c'est là que j'ai vu qu'il fallait le faire avec la fonction Speak.

Tu as remarqué que je n'ai pas gardé la compatibilité Sapi 4 car je la trouve trop ancienne, mais chacun peut la rajouter; cependant je vais mettre la compatibilité Speech 10 et 11 qui est apparu avec vista, parce que Microsoft met à disposition 26 langues. Je ferais des essais dans quelques jours.
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Re: Sapi 5 mis à jour

Message par erix14 »

Merci nico pour le partage, ça marche très bien sous windows 8.1 et 10. Personnellement, j'attends avec impatience les premières démos en PureBasic de l'API Cortana. Je pense que faire des applications compatibles avec Cortana deviendra incontournable dans les prochaines années.
https://msdn.microsoft.com/fr-fr/librar ... 85598.aspx
Répondre