PureBasic

Forums PureBasic
Nous sommes le Lun 17/Déc/2018 10:43

Heures au format UTC + 1 heure




Poster un nouveau sujet Répondre au sujet  [ 5 messages ] 
Auteur Message
 Sujet du message: PureSapi, jouer un texte sélectionné
MessagePosté: Mer 21/Nov/2018 8:24 
Hors ligne
Avatar de l’utilisateur

Inscription: Mar 02/Nov/2010 13:53
Messages: 115
Localisation: Corte
Bonjour à tous,

J'avais besoin d'un lecteur de textes, que l'on puisse sélectionner dans un lecteur externe de fichiers pdf.
Je me suis donc basé sur du code présent sur ce forum, et j'ai fais celui qui suit, nommé PureSapi.

Si vous voyez des choses à améliorer selon vos intérêts... :)

Pour rappel, ce code est x86 exclusivement. (En tout cas chez moi)

Image

Fonctionnement :
1) Lancer le logiciel, et votre lecteur de fichiers pdf.
2) Sélectionnez-y un texte à lire.
3) Appuyez sur le bouton Speak.


Code:
#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)
          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)
                  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)
                    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
    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)
      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
      ProcedureReturn #True
    EndIf
  EndIf
 
  ProcedureReturn #False
  ; Renvoi vrai ou faux
EndProcedure



; Envoyer un "Control-C" pour copier le texte de la fenêtre ayant le focus vers le clipboard
Procedure SendControlC(hWnd.i, win.i)
  #KeyDown = 0
  #KeyUp = 2
 
  ; Réactiver le handle sur la fenêtre perdue
  SetForegroundWindow_(hWnd)
 
  Delay(50)

  ; Effectuer un "Control + C"
  keybd_event_(#VK_CONTROL,0,0,0)
  keybd_event_(#VK_C,0,0,0)
 
  Delay(50)
 
  keybd_event_(#VK_C,0,2,0)
  keybd_event_(#VK_CONTROL,0,2,0)
 
  Delay(50)
   
  ; Réactiver le player
  SetForegroundWindow_(WindowID(win))
 
EndProcedure

Procedure.i GetSelLen(hWnd.i)
  Protected Start.i = 0
  Protected Stop.i = 0
 
  SendMessage_(hWnd, #EM_GETSEL, @Start.i, @Stop.i)
 
  ProcedureReturn Stop.i - Start.i
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, 200, "PureSapi (Player)")
 
  TextGadget(#Voix, 10, 10, 380, 40, "Voix sélectionnée :")
  TextGadget(#LangID, 10, 30, 380, 20, "LangID :")
 
  SetGadgetColor(#Voix, #PB_Gadget_FrontColor, RGB(255,0,0))
  SetGadgetColor(#LangID, #PB_Gadget_FrontColor, RGB(255,0,0))
 
  StickyWindow(#Window, #True)
 
  ; // 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)
           
      For a = 0 To NbVoice -1
        MenuItem( #DebutIndiceVoix + a, VoicesSapi1(a)\Description)
      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, "LangID : " + 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
 
  TextGadget(#TextVolume, 10, 50, 380, 20, "Volume")
  TrackBarGadget(#Volume, 10,  70, 380, 20, 0, 100)
 
  TextGadget(#TextRate, 10, 90, 380, 20, "Vitesse")
  TrackBarGadget(#Rate, 10,  110, 380, 20, 0, 20)
 
  ButtonGadget(#Speak, 20, 140, 80, 30, "Speak")
  ButtonGadget(#Pause, 110, 140, 80, 30, "Pause")
  ButtonGadget(#Resume, 200, 140, 80, 30, "Resume")
  ButtonGadget(#Stop, 290, 140, 80, 30, "Stop")
 
  DisableGadget(#Resume, 1)
  DisableGadget(#Pause, 1)
  DisableGadget(#Stop, 1)
 
  If NbVoice < 1
    DisableGadget(#Speak, 1)
  EndIf
 
  Volume = 100
 
  If OpenPreferences("settings.ini")
    Rate = ReadPreferenceInteger("Rate", 0)
    ClosePreferences()
  Else
    Rate = 0
    CreatePreferences("settings.ini")
    WritePreferenceInteger("Rate", Rate)
    ClosePreferences()
  EndIf
 
 
  SetGadgetState(#Volume, Volume)
  SetGadgetState(#Rate, Rate + 10)
 
  SetGadgetText(#TextVolume, "Volume = " + Str(Volume) + "%")
  SetGadgetText(#TextRate, "Vitesse = " + Str(Rate) + "    ( -10 à + 10 ), Vitesse normale = 0")
 
 
  ClearClipboard()
 
  SetActiveWindow(#Window)
  LastHandle = WindowID(#Window)

  Repeat
   
    ; Obtenir Handle de la fenêtre externe ayant le focus
    Handle = GetForegroundWindow_()
    If Handle <> WindowID(#Window) ; Et si ce n'est pas celle du player,
      If Handle > 0 ; Si une fenêtre est sélectionnée,
        LastHandle = Handle ; On mémorise son Handle
      EndIf
    EndIf

    ; Saisie des événements
    Event = WaitWindowEvent(20)
               
    Select Event
       
        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, "LangID : " + 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)
              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
              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 #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
             
              selectedText$ = " "
             
              ; Récupérer le texte éventuel dans la dernère fenêtre ayant eu le focus
              If LastHandle <> WindowID(#Window)
                SendControlC(LastHandle, #Window) ; on en fait un Control-C
                selectedText$ = GetClipboardText()
                ClearClipboard()
                selectedText$ = ReplaceString(selectedText$, Chr(13)+Chr(10), " ")
                selectedText$ = ReplaceString(selectedText$, Chr(13), " ")
                selectedText$ = ReplaceString(selectedText$, Chr(10), " ")
                If Trim(selectedText$) = "" : selectedText$ = " " : EndIf
              EndIf   
                           
              If PlaySpeakAsync(VoicesSapi1(), VoiceSapi1, selectedText$, @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
     
      Delay(1)
     
    Until Quit = 1
   
    RemoveWindowTimer(#Window, #TimerDetectSpeakfinish)
   
EndIf



; Sauvegarde les préférences
CreatePreferences("settings.ini")
WritePreferenceInteger("Rate", Rate)
ClosePreferences()
 
; 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

;;

_________________
Mes travaux informatiques gratuits, en vrac :
http://retro-bruno.pagesperso-orange.fr/


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: PureSapi, jouer un texte sélectionné
MessagePosté: Sam 01/Déc/2018 13:55 
Hors ligne
Avatar de l’utilisateur

Inscription: Ven 13/Fév/2004 0:57
Messages: 3699
Bonjour, cela fonctionne bien en compilation x86. :)

Mais le cœur du code, que j'ai conçu à partir d'autres échantillons que j'ai pu trouver ici et là, nécessiterais une petite refonte, notamment sur les appels COM qui récupèrent un pointeur sur une autre interface. Car même si l'appel réussit, cela ne signifie pas pour autant que le pointeur reçu est valide, c'est pourquoi le programme plante en x64.

Par exemple au lieu de faire ceci:
Code:
  If  CoCreateInstance_(Clsid, #Null, #CLSCTX_INPROC_SERVER, Refiid, @SpeechVoice) >= #S_OK   
   
    If SpeechVoice\GetVoices(0, 0, @SpeechObjectTokens) >= #S_OK   ; peut planter si  SpeechVoice=0


Il faudrait faire cela:
Code:
  If  CoCreateInstance_(Clsid, #Null, #CLSCTX_INPROC_SERVER, Refiid, @SpeechVoice) >= #S_OK   
   
    If SpeechVoice And SpeechVoice\GetVoices(0, 0, @SpeechObjectTokens) >= #S_OK  ; ainsi on évite le plantage



Il faudrait aussi compléter en rajoutant des boites de messages d'erreurs pour informer de l'erreur et plutôt que de laisser le programme décider du choix entre Sapi 5 et Speech 11, on pourrait laisser à l'utilisateur le choix de sélection au niveau de l'interface. A l'époque, je l'avais fais ainsi car suivant l'OS que l'on avait, on avait forcément l'un ou l'autre, soit le dernier en date.

Voilà pour la petite explication.


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: PureSapi, jouer un texte sélectionné
MessagePosté: Sam 01/Déc/2018 18:46 
Hors ligne
Avatar de l’utilisateur

Inscription: Sam 23/Sep/2006 18:32
Messages: 6567
Localisation: Isere
Marche nickel W10 x64 / v5.62 x86 :wink:
Ce genre de programme m'épate tout le temps 8O
Et la voix française parle presque aussi bien qu'une vraie personne "bien française", c'est ébouriffant 8O
On est loin des anciennes voix, ou on était mort de rire en entendant l'accent "Métalamericain", mais qui déjà à l'époque nous bluffait....
Merci de ce partage 8)

_________________
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: PureSapi, jouer un texte sélectionné
MessagePosté: Dim 02/Déc/2018 8:22 
Hors ligne
Avatar de l’utilisateur

Inscription: Ven 13/Fév/2004 0:57
Messages: 3699
Salut KCC,

Oui, les voix sont excellentes et la lecture fonctionne vraiment bien, la reconnaissance vocale est encore plus impressionnante et plus compliquée encore. :)


Haut
 Profil  
Répondre en citant le message  
 Sujet du message: Re: PureSapi, jouer un texte sélectionné
MessagePosté: Mer 05/Déc/2018 18:03 
Hors ligne
Avatar de l’utilisateur

Inscription: Sam 23/Sep/2006 18:32
Messages: 6567
Localisation: Isere
Jsuis en admiration devant ces fonctions.
Ca fait tellement vrai. qu'on va bientôt pouvoir de passer de "machine" qui fait le même son et qu'on écoute plus depuis longtemps...
Bref un bon lave vaisselle, lave linge, allo pizza...une machine qui cause aussi bien voir mieux, et surtout de sujets intéressants...
Pour le reste les japonais ont fait le nécessaire plus vraie que nature pour seulement 5000 euros
Crois moi...la paix et le réel bonheur du geek n'est plus vraiment loin ...... :mrgreen:

_________________
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic


Haut
 Profil  
Répondre en citant le message  
Afficher les messages postés depuis:  Trier par  
Poster un nouveau sujet Répondre au sujet  [ 5 messages ] 

Heures au format UTC + 1 heure


Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 3 invités


Vous ne pouvez pas poster de nouveaux sujets
Vous ne pouvez pas répondre aux sujets
Vous ne pouvez pas éditer vos messages
Vous ne pouvez pas supprimer vos messages

Rechercher:
Aller à:  

 


Powered by phpBB © 2008 phpBB Group | Traduction par: phpBB-fr.com
subSilver+ theme by Canver Software, sponsor Sanal Modifiye