Page 4 of 5
Re: SAPI : change Voice
Posted: Sat Feb 10, 2024 10:38 pm
by Danielmaximiliano
hello Jimmy
I am reading and reading about how to know that the "Word" event has happened, just for now I am interested in the phoneme or word
applying
Code: Select all | Expand
oNarrator := CreateObject( "Sapi.SPVoice" , "WithEvents" )
oNarrator:EventInterests := SVEPhoneme
oNarrator:Speak( Main.RichEdit_1.VALUE, SVSFlagsAsync)
While ..
...
end
When sending the text to the TTS engine it should know if that event happened but I can't find a way to know yet since there is no real example of how it works.
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 9:05 am
by Antonio Linares
Dear Jimmy,
Those are the different events info!
Please post here the exact code you are using and I will help you to process them
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 9:33 am
by Antonio Linares
Never mind, I got the events working here!
Now lets analize them...
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 9:35 am
by Enrico Maria Giordano
Great!
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 9:40 am
by Antonio Linares
Simply add this line at the top:
static aEvents := {}
and then use this:
oVoice:__hSink = __axRegisterHandler( oVoice:__hObj, { | ... | AAdd( aEvents, { ... } ) } )
Finally, after the dialog, do:
XBrowser( aEvents )
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 9:42 am
by Antonio Linares
IMO the reason why we were not getting the events was that we were not using a window/dialog in the example
As soon as we have tested it with a dialog, the events arrive!
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 10:10 am
by Jimmy
hi,
i "think" we need a RTF Control to use
Code: Select all | Expand
oGetText:SetSel({StreamPosition , StreamPosition + Length})
oGetText:SetFocus()
to get this Effect ( not perfect ) using HMG Syntax and RTF
a Get / MGet will highlight hole Control when get Focus
but i do not know how to change *.RC from EDITTEXT into RTF (?)
who can help me please
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 10:34 am
by Antonio Linares
Dear Jimmy,
Can you share the RC for your example ? In case you are using a RC file...
My mistake: the difference with events is NOT a handle of a window. The difference is to play in ASYNC mode !!!
oVoice:Speak( "harbour and xharbour", 1 ) // that 1 uses Async mode and thus events arrive to us !!!
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 10:53 am
by Enrico Maria Giordano
Can I see a working sample, please?
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 11:58 am
by Antonio Linares
Dear Enrico,
Here you have it:
Code: Select all | Expand
#include "FiveWin.ch"
static aEvents := {}
function Main()
local oVoice := TOleAuto():New( "Sapi.SPVoice" )
oVoice:__hSink = __axRegisterHandler( oVoice:__hObj, { | ... | AAdd( aEvents, { ... } ) } )
oVoice:Speak( "hello my friend", 1 ) // 1 means asynch so events can arrive. Instead of 1, 3 can be used to cancel what is being said and start again in asynch mode
MsgInfo( "waiting" ) // we wait and process windows messages so events can arrive
XBrowser( aEvents )
return nil
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 12:04 pm
by Antonio Linares
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
https://learn.microsoft.com/en-us/previ ... 7(v=vs.85)
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 12:09 pm
by Enrico Maria Giordano
Thank you.
Re: SAPI : change Voice
Posted: Sun Feb 11, 2024 11:24 pm
by Danielmaximiliano
Jimmy wrote:hi Antonio,
thx for the Idea.
Result is same like using Property "Voice"
Error description: (DOS Error -2147352573) WINOLE/1007 Argument error: VOICE
Args:
[ 1] = O
Stack Calls
===========
Called from: => TOLEAUTO:VOICE( 0 )
Called from: main.prg => CHANGEVOICE( 125 )
Called from: main.prg => (b)MAIN( 43
mi solunción
Code: Select all | Expand
Function ChangeVoice() //cambiar voz desde un doble click sobre la lista de narradores
local nGrid := Main.List_1.Value
local cName := aAvoice [ nGrid , 1 ]
Local oVoice
/* oNarrator:voice := oNarrator:GetVoices():Item( nGrid - 1) // Fumciona
oNarrator:Speak( "Narrador " + cName, SVSFlagsAsync ) */
For Each oVoice In oNarrator:GetVoices()
If (oVoice:GetDescription(0) == Main.List_1.item(Main.List_1.Value))
oNarrator:voice := oVoice
oNarrator:Speak( "Narrador " + cName, SVSFlagsAsync )
endif
Next
RETURN
Re: SAPI : change Voice
Posted: Mon Feb 12, 2024 3:09 am
by Danielmaximiliano
Hola Jimmy :
Leyendo creo que se necesita la propiedad "Status"
https://learn.microsoft.com/en-us/previ ... 2(v=vs.85)
pero no consigo descifrar bien el uso aqui
https://learn.microsoft.com/en-us/previ ... 4(v=vs.85)
Code: Select all | Expand
Function Play()
local nStreamNumber , nStreamPosition , nCharacterPosition, nLength , ISpeechVoiceStatus
oNarrator:EventInterests := SVEPhoneme
oNarrator:Speak( Main.RichEdit_1.VALUE, SVSFlagsAsync)
ISpeechVoiceStatus := oNarrator:Status
DO WHILE .not. ISpeechVoiceStatus:RunningState == SRSEDone
nCharacterPosition := ISpeechVoiceStatus:InputWordPosition
nLength := ISpeechVoiceStatus:InputWordLength
Main.RichEditBox_1.CaretPos := nCharacterPosition
Main.RichEdit_1.SelectRange := { nCharacterPosition, nLength }
ENDDO
Return
el codigo para iluminar el tenxto del control Richtedit deberia ser parecido a esto en VBA
Code: Select all | Expand
V.Speak "this is stream number<bookmark mark='2two'/> two.", SVSFlagsAsync + SVSFIsXML
List1.AddItem "LastStreamNumberQueued is " & V.Status.LastStreamNumberQueued
DoEvents
Do
V.WaitUntilDone (500) 'Wait for 0.5 second so we won't get too many outputs
List1.AddItem ""
List1.AddItem "LastStreamNumberQueued is " & V.Status.LastStreamNumberQueued
List1.AddItem "CurrentStreamNumber is " & V.Status.CurrentStreamNumber
List1.AddItem "InputSentenceLength is " & V.Status.InputSentenceLength
List1.AddItem "InputSentencePosition is " & V.Status.InputSentencePosition
List1.AddItem "InputWordLength is " & V.Status.InputWordLength
List1.AddItem "InputWordPosition is " & V.Status.InputWordPosition
List1.AddItem "RunningState is " & V.Status.RunningState
List1.AddItem "LastBookmark is " & V.Status.LastBookmark
List1.AddItem "LastBookmarkId is " & V.Status.LastBookmarkId
List1.AddItem "VisemeId is " & V.Status.VisemeId
List1.AddItem "PhonemeId is " & V.Status.PhonemeId
List1.AddItem "LastHResult is " & V.Status.LastHResult
DoEvents
Loop Until V.Status.RunningState = SRSEDone 'Exit when voice stops
Re: SAPI : change Voice
Posted: Mon Feb 12, 2024 6:02 am
by Jimmy
hi Antonio,
Antonio Linares wrote: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
thx for your List f Event meaning, now it work (almost) perfect
Code: Select all | Expand
oSpVoice:__hSink := __axRegisterHandler( oSpVoice:__hObj, { | a,b,c,d,e | 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
OffSet := aPara[3]
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 )
oGetText:SetSel({CharacterPosition , CharacterPosition + Length})
oGetText:SetFocus()
SYSRefresh()
RETURN
but as i say : it need a RTF in *.RC to show highlight Word