SAPI : change Voice

Re: SAPI : change Voice

Postby Danielmaximiliano » Tue Feb 13, 2024 4:38 am

Hola Jimmy :
me explicarias como se disparan los eventos al utilizar
Code: Select all  Expand view
oSpVoice:__hSink := __axRegisterHandler( oSpVoice:__hObj, { | a, b, c, d, e | OnEvent( a, b, c, d, e ) } )

al hacer Play en el form
Code: Select all  Expand view
DEFINE BUTTON oBtnPlay
         ROW 160
         COL 460
         WIDTH 90
         HEIGHT 28
         ACTION( oSpVoice:Speak( cTextToRead, ( SVSFlagsAsync + SVSFPurgeBeforeSpeak ) ) )


Code: Select all  Expand view
FUNCTION OnEvent()

LOCAL iMax  := PCOUNT()
LOCAL i
LOCAL aPara := ARRAY( 5 )

   FOR i := 1 TO iMax
      aPara[ i ] := PValue( i )
   NEXT

   DO CASE
      CASE aPara[ 1 ] = 2
         oSpVoice_Word( aPara[ 2 ], aPara[ 3 ], 0, 0 )
      CASE aPara[ 1 ] = 5
         oSpVoice_Word( aPara[ 2 ], aPara[ 3 ], aPara[ 4 ], aPara[ 5 ] )
   ENDCASE
RETURN NIL


Code: Select all  Expand view
PROCEDURE oSpVoice_Word( StreamNumber, StreamPosition, CharacterPosition, Length )

   //  In order to show this selection,
   //  the Text1.HideSelection property must be False!

   SetProperty( "SPEAK", "oGetText", "HideSelection", .F. )

   SetProperty( "SPEAK", "oGetText", "SelectRange", { CharacterPosition, CharacterPosition + Length } )
   Domethod( "SPEAK", "oGetText", "SetFocus" )
   //   Domethod("SPEAK","oGetText","ScrolltoCaret")
   DO EVENTS
RETURN
Danielmaximiliano
 
Posts: 17
Joined: Tue Mar 20, 2012 11:06 pm

Re: SAPI : change Voice

Postby Jimmy » Wed Feb 14, 2024 8:22 am

hi Daniel,

i have try to Debug Events (see last Page) and have ask "what does they mean"
Antonio found Solution that 1st Parameter are the Event "Number"

Events and meanings:
1 --> Start
3 --> An OLE object is received, probably self OLE object ?
5 --> Word, 4th param is position, 5th param is length
6 --> ???
7 --> Sentence, 4th param is position, 5th param is length
8 --> ???
2 --> End

so i watch for
Code: Select all  Expand view
     CASE aPara[ 1 ] = 2
         // End of Text
      CASE aPara[ 1 ] = 5
         // highlight WORD
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1584
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: SAPI : change Voice

Postby Danielmaximiliano » Wed Feb 14, 2024 11:56 am

Hola Jmmy :
yo lo resolví asi en HMG/Harbour
Code: Select all  Expand view
Function Play()

 oNarrator:EventInterests := SVEAllEvents + SVEAudioLevel
 oNarrator:Speak( Main.RichEdit_1.VALUE, ( SVSFlagsAsync + SVSFPurgeBeforeSpeak ))
 
 Do While .NOT. (oNarrator:WaitUntilDone (.1) )
    SetProperty( "Main", "RichEdit_1", "HideSelection", .F. )
    SetProperty( "Main", "RichEdit_1", "SelectRange", { oNarrator:Status:InputWordPosition , ;
                                                        oNarrator:Status:InputWordPosition  + oNarrator:Status:InputWordLength } )
    Domethod( "Main", "RichEdit_1", "SetFocus" )
    DoEvents()
 ENDDO
Return

Microsoft Note :
The WaitUntilDone method blocks execution until the voice finishes speaking, enabling an application to speak a text stream asynchronously and determine when it finishes. The hidden SpeakCompleteEvent method is similar to WaitUntilDone, except that it returns an event handle for the background speaking process, and does not block application execution.
Danielmaximiliano
 
Posts: 17
Joined: Tue Mar 20, 2012 11:06 pm

Re: SAPI : change Voice

Postby Silvio.Falconi » Fri Feb 16, 2024 2:35 pm

please can you post the entire test with the recources so we can help you too?


¿Puedes publicar la prueba completa con los recursos para que podamos ayudarte también?
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 6768
Joined: Thu Oct 18, 2012 7:17 pm

Re: SAPI : change Voice

Postby Danielmaximiliano » Fri Feb 16, 2024 5:50 pm

Silvio.Falconi wrote:please can you post the entire test with the recources so we can help you too?


¿Puedes publicar la prueba completa con los recursos para que podamos ayudarte también?


Hola Silvio
ya está la solución con respecto a Sapi.Voice con la ayuda de Antonio Linares
Danielmaximiliano
 
Posts: 17
Joined: Tue Mar 20, 2012 11:06 pm

Re: SAPI : change Voice

Postby Silvio.Falconi » Fri Feb 16, 2024 7:51 pm

Danielmaximiliano wrote:
Silvio.Falconi wrote:please can you post the entire test with the recources so we can help you too?


¿Puedes publicar la prueba completa con los recursos para que podamos ayudarte también?


Hola Silvio
ya está la solución con respecto a Sapi.Voice con la ayuda de Antonio Linares


Yes It run ok but i Wish change the voices
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 6768
Joined: Thu Oct 18, 2012 7:17 pm

Re: SAPI : change Voice

Postby Danielmaximiliano » Sat Feb 24, 2024 12:37 am

Silvio.Falconi wrote:
Yes It run ok but i Wish change the voices

Hola Silvio :
no soy programador en FW sino en HMG/Harbour no recordaba estar en este foro pero ingrese en el 2012, vi que Jimmy y varios
en harbour tenian el mismo problema de elegir la voz del narrador de windows y jimmy hizo esta pregunta en este foro, la cual fue resuelta por Antonio Linares al cual estoy muy agradecido.
Jimmy tendria que dejar un ejemplo en FW para los otros usarios de este foro pero yo dejo el ejemplo de Harbour/HMG

Code: Select all  Expand view
Function ChangeVoice()  //cambiar voz desde un doble click sobre la lista de narradores
//oNarrator  := CreateObject( "Sapi.SPVoice" , "WithEvents" )
Local oVoice

  For Each oVoice In oNarrator:GetVoices()                      
     If (oVoice:GetDescription(0) == Main.List_1.item(Main.List_1.Value))
      oNarrator:voice := oVoice
      //oNarrator:voice   := oNarrator:GetVoices():Item(  Main.Lis t_1.Value)  // Funciona tambien
      oNarrator:Speak( "Narrador " + oVoice :GetAttribute("Name"), SVSFlagsAsync )
     endif
  Next 

RETURN
Danielmaximiliano
 
Posts: 17
Joined: Tue Mar 20, 2012 11:06 pm

Re: SAPI : change Voice

Postby Jimmy » Sat Feb 24, 2024 5:39 am

hi,

i have not post a Sample while Original Source use *.RC and EDITTEXT
but for full working Sample i need RTF but don´t know how to change *.RC

please can somebody change EDITTEXT to RTF to get it full working, please
https://forums.fivetechsupport.com/viewtopic.php?t=12983

i have used that Source and add CODE, to highlight WORD which is spoken
Code: Select all  Expand view
 oVoice:__hSink := __axRegisterHandler( oVoice:__hObj, { | a,b,c,d,e,f | OnEvent( a,b,c,d,e ) } )

FUNCTION onEvent()
LOCAL iMax  := PCOUNT()
LOCAL i
LOCAL aPara := ARRAY(5)

   FOR i := 1 TO iMax
     aPara[i] := PValue( i )
   NEXT
   
   DO CASE
      CASE aPara[1] = 2
         oSpVoice_Word(aPara[2],aPara[3],0, 0)
      CASE aPara[1] = 5
         oSpVoice_Word(aPara[2],aPara[3],aPara[4], aPara[5])
   ENDCASE
RETURN NIL

PROCEDURE oSpVoice_Word(StreamNumber, StreamPosition, CharacterPosition, Length )
   // NEED RTF Control
   oGetText:SetSel({CharacterPosition , CharacterPosition+Length})
   oGetText:SetFocus()
   SYSRefresh()
RETURN
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1584
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: SAPI : change Voice

Postby Antonio Linares » Sat Feb 24, 2024 5:55 am

Dear Jimmy,

Please post your current PRG and RC and I will help you to use RTF

thanks
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: SAPI : change Voice

Postby Jimmy » Sat Feb 24, 2024 6:50 am

hi Antonio,

here is the CODE of PRG
Code: Select all  Expand view
#include "FiveWin.ch"

static lIsPaused := .F.

MEMVAR oGetText
function Main()

   local oDlg, oBtnPlay, oBtnPause, oBtnStop, oBtnInterroga, oBrowVoices, cVoice, oCbxOutPut, oCbxVoiceNormal
   local oCbxVoiceAlert, oMeter
   local oBtnVolumeUp, oBtnVolumeDown, oBtnVelocityUp, oBtnVelocityDown
   local oGetVolumeLevel, oGetVelocityLevel
   local cMeter
   local aVoices := {}, aPhoneme := {}, aVoiceForSelect := {}
   local aOutPutStream := { "Voz", "File" }, cSelOutPutStream := "Voz"
   local oFile := tOleAuto():New( "Sapi.SpFileStream" )
   local nVolume := 50
   local nVelocity := 0
   local n := 0, n2 := 0
   local oVoice := tOleAuto():New( "Sapi.SPVoice", "WithEvents" )
   local oVoiceAlert := tOleAuto():New( "Sapi.SPVoice", "WithEvents" )
   local cSelNormalVoice, cSelAlertVoice


   // SpeechVoiceFlags
   local SVSFDefault := 0
   local SVSFlagsAsync := 1
   local SVSFPurgeBeforeSpeak  := 2
   local SVSFIsXML := 8
   // SpeechVoiceEvents
   local SVEStartInputStream := 2
   local SVEEndInputStream := 4
   local SVEVoiceChange := 8
   local SVEBookmark := 16
   local SVEWordBoundary := 32
   local SVEPhoneme := 64
   local SVESentenceBoundary := 128
   local SVEViseme := 256
   local SVEAudioLevel := 512
   local SVEPrivate := 32768
   local SVEAllEvents := 33790
   //SpeechVoicePriority
   local SVPNormal := 0
   local SVPAlert := 1
   local SVPOver := 2
   local cTextToRead := "La Guía de Programación de FiveWin, ofrece una introducción dirigida a técnicas" + CRLF +;
                        "de desarrollo de aplicaciones de Windows utilizando (x)Harbour y FiveWin. Esta" + CRLF +;
                        "guía explicará los conceptos básicos que usted debe tener para construir correctamente" + CRLF +;
                        "sus aplicaciones de Windows."
   local ISpeechObjectTokens

   PUBLIC oGetText

   ISpeechObjectTokens := oVoice:GetVoices()

   SET ALTER ON
   SET ALTER TO "_LOGIT2.TXT "

   For n = 0 To Len( oVoice:GetVoices() )
   TRY
       Aadd( aVoices, { n, ISpeechObjectTokens[n]:GetAttribute( 'Name' ), ISpeechObjectTokens[n]:GetAttribute( 'Gender' ),;
                          ISpeechObjectTokens[n]:GetAttribute( 'Age' ), ISpeechObjectTokens[n]:GetAttribute( 'Language' ),;
                          ISpeechObjectTokens[n]:GetAttribute( 'Vendor' ) } )
       Aadd( aVoiceForSelect, ISpeechObjectTokens[n]:GetAttribute( 'Name' ) )
   CATCH
   END
   Next

   cSelNormalVoice := aVoiceForSelect[1]
   cSelAlertVoice := aVoiceForSelect[1]

   oVoiceAlert:Priority := SVPAlert // Set oVoiceAlert as an 'alert' voice
   oVoiceAlert:Voice := oVoiceAlert:GetVoices( "Name = " + cSelNormalVoice ):Item( 0 )
   oVoiceAlert:Volume := 90 // Set the volume of the Alert Voice at 90 to a Maximum of 100

   oVoice:AlertBoundary := SVEPhoneme // Allow to Stop voice by Another one with Alert priority
   oVoice:EventInterests := SVEWordBoundary // SVEAllEvents + SVEAudioLevel

   oVoice:Voice := oVoice:GetVoices( "Name = " + cSelNormalVoice ):Item( 0 )
   oVoice:Volume := nVolume
   oVoice:Rate := nVelocity
   
   oVoice:__hSink := __axRegisterHandler( oVoice:__hObj, { | a,b,c,d,e,f | OnEvent( a,b,c,d,e ) } )

   DEFINE DIALOG oDlg RESOURCE "sound"

   REDEFINE GET oGetText VAR cTextToRead ID 10 OF oDlg MULTILINE UPDATE

   REDEFINE METER oMeter VAR cMeter ID 3000 OF oDlg NOPERCENTAGE UPDATE

   REDEFINE BUTTON oBtnPlay ID 2010 OF oDlg ACTION ( oVoice:Speak( cTextToRead, ( SVSFlagsAsync + SVSFIsXML ) ) ) UPDATE

   REDEFINE BUTTON oBtnPause ID 2020 OF oDlg ACTION ( PauseResume( oVoice, oBtnPause ), oDlg:Update() ) UPDATE

   REDEFINE BUTTON oBtnStop ID 2030 OF oDlg ACTION ( iif( lIsPaused, ( lIsPaused := .F., oBtnPause:SetText( "Pause" ) ) , ),;
            oVoice:Speak( " ",SVSFPurgeBeforeSpeak ) ) UPDATE

   REDEFINE BUTTON oBtnInterroga ID 2040 OF oDlg ACTION ;
           ( oVoiceAlert:Speak( "This is a Warning Interrupt", SVSFlagsAsync ), MsgInfo( "Esto es una prueba de interrupción de Alerta" ) )

   REDEFINE BUTTON oBtnVolumeUp ID 120 OF oDlg;
            ACTION ( nVolume := nVolume + 10, iif( nVolume > 100, ( nVolume := 100 , MsgInfo( "Máximum Volume" ) ) ,;
            oVoice:Volume := nVolume ), oGetVolumeLevel:SetText( AllTrim( Str( nVolume ) ) ) ) UPDATE

   REDEFINE BUTTON oBtnVolumeDown ID 130 OF oDlg;
            ACTION ( nVolume := nVolume - 10, iif( nVolume < 0, ( nVolume := 0 , MsgInfo( "Mínimum Volume" ) ),;
            oVoice:Volume := nVolume ), oGetVolumeLevel:SetText( AllTrim( Str( nVolume ) ) ) ) UPDATE

   REDEFINE BUTTON oBtnVelocityUp ID 140 OF oDlg;
            ACTION ( nVelocity++, iif( nVelocity > 10, ( nVelocity := 10 , MsgInfo( "Máximum Velocity" ) ),;
            oVoice:Rate := nVelocity ), oGetVelocityLevel:SetText( AllTrim( Str( nVelocity ) ) ) ) UPDATE

   REDEFINE BUTTON oBtnVelocityDown ID 150 OF oDlg;
            ACTION ( nVelocity--, iif( nVelocity < -10, ( nVelocity := -10 , MsgInfo( "Mínimum Velocity" ) ),;
            oVoice:Rate := nVelocity ), oGetVelocityLevel:SetText( AllTrim( Str( nVelocity ) ) ) ) UPDATE

   REDEFINE GET oGetVolumeLevel VAR nVolume ID 160 OF oDlg UPDATE

   oGetVolumeLevel:SetText( Str( nVolume ) )

   REDEFINE GET oGetVelocityLevel VAR nVelocity ID 170 OF oDlg UPDATE

   oGetVelocityLevel:SetText( Str( nVelocity ) )

   REDEFINE LISTBOX oBrowVoices FIELDS AllTrim( Str( aVoices[ oBrowVoices:nAt, 1 ] ) ), aVoices[ oBrowVoices:nAt, 2 ],;
            aVoices[ oBrowVoices:nAt, 3 ], aVoices[ oBrowVoices:nAt, 4 ], aVoices[ oBrowVoices:nAt, 5 ], aVoices[ oBrowVoices:nAt, 6 ];
            HEADERS "Item", "Nombre", "_", "Edad", "Idioma ID", "Empresa";
            COLSIZES 31, 77, 72, 42, 58, 64;
            ON DBLCLICK oVoice:Voice := oVoice:GetVoices():Item( aVoices[ oBrowVoices:nAt, 1 ]  );
            ID 200 OF oDlg UPDATE

   oBrowVoices:SetArray( aVoices )

   REDEFINE COMBOBOX oCbxOutPut VAR cSelOutPutStream;
                  ITEMS aOutPutStream ID 210 OF oDlg UPDATE ;
            ON CHANGE OutPutStream( cSelOutPutStream, oVoice, oFile )

   REDEFINE COMBOBOX oCbxVoiceNormal VAR cSelNormalVoice;
                  ITEMS aVoiceForSelect ID 220 OF oDlg UPDATE;
            ON CHANGE oVoice:Voice := oVoice:GetVoices( "name = " + cSelNormalVoice ):Item( 0 )


   REDEFINE COMBOBOX oCbxVoiceAlert VAR cSelAlertVoice;
                  ITEMS aVoiceForSelect ID 230 OF oDlg UPDATE;
            ON CHANGE oVoiceAlert:Voice := oVoiceAlert:GetVoices( "name = " + cSelAlertVoice ):Item( 0 )


   ACTIVATE DIALOG oDlg CENTERED

  SET ALTER TO
  SET ALTER OFF

return nil

function PauseResume( oVoice, oBtnPause )

   iif( lIsPaused,;
      ( oVoice:Resume(), lIsPaused := .F., oBtnPause:SetText( "Pause" ) ),;
      ( oVoice:Pause(), lIsPaused := .T., oBtnPause:SetText( "Resume" ) ) )

return nil

function OutPutStream( cSelOutPutStream, oVoice, oFile )

   local SSFMCreateForWrite := 3

   if cSelOutPutStream = "File"
      MsgInfo( "OutPut redirected to a File in 'c:\TeechToSpeak.wav'", "Warning!!!" )
      oFile:Open( "c:\TeechToSpeak.wav" , SSFMCreateForWrite )
      oVoice:AudioOutputStream := oFile
   else
      MsgInfo( "OutPut redirected to Speakers", "Warning!!!" )
      oFile:Close()
      oVoice:AudioOutputStream := nil
   endif

return nil

FUNCTION onEvent()
LOCAL iMax  := PCOUNT()
LOCAL i
LOCAL aPara := ARRAY(5)

   FOR i := 1 TO iMax
     aPara[i] := PValue( i )
   NEXT
   
   DO CASE
      CASE aPara[1] = 2
         oSpVoice_Word(aPara[2],aPara[3],0, 0)
      CASE aPara[1] = 5
         oSpVoice_Word(aPara[2],aPara[3],aPara[4], aPara[5])
   ENDCASE
RETURN NIL

PROCEDURE oSpVoice_Word(StreamNumber, StreamPosition, CharacterPosition, Length )
   // NEED RTF Control
   oGetText:SetSel({CharacterPosition , CharacterPosition+Length})
   oGetText:SetFocus()
   SYSRefresh()
RETURN

and this is the RC
Code: Select all  Expand view
   #ifdef __FLAT__
      1 24 "WindowsXP.Manifest"
    #endif

    #define IDC_GROUPBOX1   11
    #define DIALOG_10   10
    #define DIALOG_8   8
    #define DIALOG_7   7
    #define DIALOG_6   6
    #define DIALOG_4   4
    #define DIALOG_3   3
    #define DIALOG_2   2
      #define DIALOG_1   1
    #define DIALOG_5   5




    sound DIALOG 76, 48, 379, 241
    STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
    CAPTION "Text To Speech (TTS)"
    FONT 8, "MS Sans Serif"
    {
    PUSHBUTTON "Play", 2010, 312, 98, 55, 14
    PUSHBUTTON "Pause", 2020, 312, 115, 55, 14
    PUSHBUTTON "Stop", 2030, 312, 132, 55, 14
    PUSHBUTTON "Alert!!!", 2040, 312, 149, 55, 14
    LTEXT "Text To Speech:", -1, 16, 7, 59, 10
    EDITTEXT 10, 16, 17, 278, 74, ES_MULTILINE | ES_READONLY | ES_WANTRETURN | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | ES_NOHIDESEL
    LTEXT "Volumen:", -1, 306, 175, 40, 10
    LTEXT "Velocity:", -1, 344, 175, 37, 10
    PUSHBUTTON "+", 120, 313, 185, 17, 14
    PUSHBUTTON "-", 130, 313, 202, 17, 14
    PUSHBUTTON "+", 140, 351, 185, 17, 14
    PUSHBUTTON "-", 150, 351, 202, 17, 14
    CONTROL "", 200, "TWBrowse", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP, 16, 141, 278, 88
    COMBOBOX 210, 308, 15, 55, 22, CBS_DROPDOWNLIST | WS_TABSTOP
    LTEXT "Double Click to Select:", -1, 16, 128, 78, 10
    LTEXT "Voice OutPut:", -1, 308, 5, 49, 10
    GROUPBOX "", IDC_GROUPBOX1, 304, 91, 70, 77, BS_GROUPBOX
    GROUPBOX "", -1, 4, 0, 298, 122, BS_GROUPBOX
    GROUPBOX "", -1, 4, 121, 298, 115, BS_GROUPBOX
    GROUPBOX "", -1, 304, 0, 70, 33, BS_GROUPBOX
    GROUPBOX "", -1, 304, 165, 70, 71, BS_GROUPBOX
    EDITTEXT 160, 313, 220, 17, 13, ES_READONLY | WS_BORDER | WS_TABSTOP
    EDITTEXT 170, 351, 220, 17, 13, ES_READONLY | WS_BORDER | WS_TABSTOP
    CONTROL "TMeter", 3000, "TMeter", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 16, 95, 279, 22
    COMBOBOX 220, 308, 46, 61, 33, CBS_DROPDOWNLIST | WS_TABSTOP
    LTEXT "Normal Voice:", -1, 308, 36, 49, 10
    GROUPBOX "", -1, 304, 31, 70, 33, BS_GROUPBOX
    COMBOBOX 230, 308, 76, 61, 33, CBS_DROPDOWNLIST | WS_TABSTOP
    LTEXT "Alert Voice:", -1, 308, 66, 49, 10
    GROUPBOX "", -1, 304, 61, 70, 33, BS_GROUPBOX
    }
 
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1584
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Previous

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 64 guests