注册 登录
编程论坛 VFP论坛

求助:SAPI.SpVoice大量文字内容朗读终止问题

igaoyuan 发布于 2023-01-17 10:05, 2217 次点击
大量文字朗读时,如需终止,有没有好的办法?

程序代码:
oSpeech =CreateObject("SAPI.SpVoice")        &&连接到系统的语音功能
sWord='窗前明月光,疑是地上霜'                &&被阅读的字串
oSpeech.Speak(sWord)                        &&让系统读出字符串里的内容
sWord = This.parent.edtNote.Value  &&备注字段内容
oSpeech.Speak(sWord)


有资料显示可使用oSpeech.Speak(sWord,2)来终止,尝试后不行,仍旧需要播放完
参考资料:https://sysdzw.blog.

同时还有一个问题,播放sWord='窗前明月光,疑是地上霜',一遍停止;播放sWord = This.parent.edtNote.Value 时总是播放两遍

额外一个问题,选择TTS里不同语音的语句是哪一条?谢谢!
16 回复
#2
laowan0012023-01-17 11:37
oSpeech.Speak(sWord,2)
这里的参数“2”表示本条语音要朗读完毕
正在朗读的语音能否被中断,取决取正在朗读的文本发送时的参数,比如3是可被中断的
#3
igaoyuan2023-01-17 11:46
改为oSpeech.Speak(sWord,3)后就不执行朗读,直接中断了
#4
吹水佬2023-01-17 13:00
SPEAK(cStr, 1)  && 1 = 异步方式,0 = 同步方式
#5
igaoyuan2023-01-17 13:46
回复 4楼 吹水佬
谢谢吹水佬!

改动后,oSpeech.Speak(sWord)可以朗读,oSpeech.Speak(myWord,1)不读,去掉IF语句可以读,不能终止
   
程序代码:
myword = This.parent.edtNote.Value
oSpeech =CreateObject("SAPI.SpVoice")        &&连接到系统的语音功能

sWord    = [你好!为您阅读题目]+This.parent.grdMynote.Column1.Text1.Value   &&'窗前明月光,疑是地上霜'                &&被阅读的字串
oSpeech.Speak(sWord)                        &&让系统读出字符串里的内容

oSpeech.Speak(myWord,1)                        &&让系统读出字符串里的内容
If oSpeech.Status.runningState = 2 .and. INKEY()= 27          &&如果当前正在播放,那么就播放一个空字符串,并且使用挂断之前的模式
    oSpeech.Speak("", 2)
ENDIF
#6
laowan0012023-01-17 14:31
oSpeech.Speak('这是可被中断的朗读,这是可被中断的朗读,这是可被中断的朗读',3)
inkey(0.5)
oSpeech.Speak('这句话不能被中断,这句话不能被中断',2)
oSpeech.Speak('听完第二句话,这是第三句',2)
#7
吹水佬2023-01-17 15:05
回复 5楼 igaoyuan
观察 oSpeech.Status.runningState 看看
#8
sam_jiang2023-01-17 15:57
利用vfp智能感应补全,可以得知speak方法的两个参数:ospeech.speak(text as string,[flag SpeechVoiceSpeakFlags=0] as number)
网上搜索到SpeechVoiceSpeakFlags的每个值的含义如下:
枚举SpeechVoiceSpeakFlags
    “SpVoice标志
    SVSFDefault = 0
    SVSFlagsAsync = 1
    SVSFPurgeBeforeSpeak = 2
    SVSFIsFilename = 4
    SVSFIsXML = 8
    SVSFIsNotXML = 16
    SVSFPersistXML = 32

    “正规化标志
    SVSFNLPSpeakPunc = 64

    “面具
    SVSFNLPMask = 64
    SVSFVoiceMask = 127
    SVSFUnusedFlags = -128   
结束枚举
SVSFDefault
指定应使用的默认设置。默认值是:
讲定的文本字符串同步(覆盖与SVSFlagsAsync),
不清除挂起说话请求(覆盖与SVSFPurgeBeforeSpeak),
为了解析XML的文本,如果第一个字符是左尖括号(覆盖与SVSFIsXML或SVSFIsNotXML),
不坚持全球XML状态更改在讲电话(覆盖SVSFPersistXML),
不扩展的标点字符成字(覆盖与SVSFNLPSpeakPunc)的。
那我来当个翻译器:

>>1、IsFilename;

该值表示,传入的字符串变量是代表一个文件名,所以speaker应该将这个文件里的字符串读出来,而不是读这个字符串本身。

>>2、IsXML;

该值表示这个文件的内容是按XML格式写的。可以用XML 标记来解析。而不应该将它当着是纯字符串。

>>3、FlagsAsync;

它表示,这个读的操作是异步的。比如你再一个button里调用了speak这个方法,当指定了这个flag后,马上就可以再次点击button了。而不用等到它读完了才能点。

>>4、FNLPMask;

由SAPI处理的标识是放在这个mask里的。

>>5、FNLPSpeakPunc;

表示会将标点符号读出来,而不是做停顿。比如前面这句话里的逗号和句号,如果指定该标识,那么会将(,)读成逗号。

>>6、PersistXML;

全局状态的改变量会一直保持到整个speak结束。

>>7、PurgeBeforeSpeak;

在开始本次speak之前,清除之前所有暂停住的speak任务。尤其是当你启用了上面的异步模式,你可以同时启动好多好多任务。他们会排队一个一个讲完。

>>8、UnusedFlags;

就是字面意思,不使用的。

>>9、VoiceMask;

它是5.3新加的,是从SVSFParseMask扩展而来的,SVSFParseMask= SVSFParseSapi|SVSFParseSsml,

SVSFParseSapi强制按SAPI解析XML

SVSFParseSsml强制按W3C解析XML

根据不同的需求组合就可以了,比如要求异步朗读,并且可打断,就是3(1+2);要求异步朗读文件可中断,就是7(1+2+4)...
#9
sam_jiang2023-01-17 16:04
ospeech.speak("根据不同的需求组合就可以了,比如要求异步朗读,并且可打断,就是3(1+2);要求异步朗读文件可中断,就是7(1+2+4)...",3)
要中断它,就直接发出ospeech.speak("",2),前面未完成的语音就结束播放了。
#10
sam_jiang2023-01-17 16:14
回复 8楼 sam_jiang
你可以试试看下面这句话,系统是怎么朗读的?
ospeech.speak("根据不同的需求组合就可以了,比如要求异步朗读,并且可打断,就是3(1+2);要求异步朗读文件可中断,就是7(1+2+4)...",1+2+64)
#11
igaoyuan2023-01-17 16:21
回复 6楼 laowan001

太好了!3 是可以中断的,IF语句不需要oSpeech.Status.runningState,搞定了!!!

程序代码:
oSpeech = CreateObject("SAPI.SpVoice")        &&连接到系统的语音功能
sWord    ='窗前明月光,疑是地上霜'            &&被阅读的字串
oSpeech.Speak(sWord)                        &&让系统读出字符串里的内容
oSpeech.Speak('这是可被中断的朗读,这是可被中断的朗读,这是可被中断的朗读',3)
? oSpeech.Status.runningState      &&return 0
inkey(3.0)
oSpeech.Speak('这句话不能被中断,这句话不能被中断',2)
oSpeech.Speak('听完第二句话,这是第三句',2)
? oSpeech.Status.runningState     &&&&return 1
#12
igaoyuan2023-01-17 16:22
回复 7楼 吹水佬
谢谢!
返回值0或1,没有2,不需要这条语句
#13
igaoyuan2023-01-17 16:27
回复 10楼 sam_jiang
正解!!非常感谢!
#14
sam_jiang2023-01-17 16:32
回复 11楼 igaoyuan
事实上,只要是异步的,都可以被中断。同步的没法中断,必须读完才可以执行下一步。
#15
kangss2023-01-17 16:33
回复 楼主 igaoyuan
给你提供一些资料

微软语音库使用实例代码
*!* 语音库:使用示例
*!* 此程序的运行依赖于Microsoft Speech SDK 5.0 或  Microsoft Speech SDK 5.1 的安装
*!* 作  者:TLDS_ZGM
*----------------------------------------------------------
* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSSam                       男_英文
* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSMike                      男_英文
* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSMary                      女_英文
* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSSimplifiedChineseVoice    中文
* HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\SampleTTSVoice              男_???

*!*常用属性和方法
*----------------------------------------------------------
* speak("中文发音",n)   && 朗读(n=0,2),停止(n=1,3) 此处解释*****有错误
* pause()               && 暂停
* resume()              && 恢复
* Volume =100           && 音量(0__100)
* Rate =0               && 语速(越大越快)
* GetVoices.Count       && 语音库数量
* getvoices.item(i)     && 第I个语音库

*!*实例:(注意:标点符号应与文字之间有间隔,否则可能会朗读标点)
*----------------------------------------------------------
RUN /N REGSVR32 /S COMCTL32.OCX
LOVOICE=CREATEOBJECT('sapi.spvoice')    && 建立对象
DIMENSION 语音库(lovoice.GetVoices.Count)
FOR i=0 TO lovoice.GetVoices.Count-1                  && 用于枚举语音库
    语音库(i+1)=lovoice.getvoices.item(i).id          && 语音库标志
ENDFOR

FM_DWJESET=CREATEOBJECT('DWJESET_FORM')
FM_DWJESET.SHOW(1)
DEFI CLASS DWJESET_FORM AS FORM
     WIDTH =600
     HEIGHT=400
     AUTOCENTER=.T.
     BORDERSTYLE=1
     CAPTION='  语音识别'
     ADD OBJECT 表单边框  AS SHAPE         WITH TOP=5  ,LEFT=5,  WIDTH=590,HEIGHT=390 ,SPECIALEFFECT=0    && 大线框
     ADD OBJECT 提示信息  AS LABEL         WITH TOP=20 ,LEFT=20, AUTOSIZE=.T.,CAPTION='朗读内容:',BACKSTYLE=0
     ADD OBJECT 朗读内容  AS EDITBOX       WITH TOP=35 ,LEFT=15, WIDTH=400,HEIGHT=350,value="Enter text you wish spoken here."&& text you wish spoken here.'&&ControlSource='内容'&&,READONLY=.T.
     ADD OBJECT 开始朗读  AS COMMANDBUTTON WITH TOP=230,LEFT=450,WIDTH=110,HEIGHT=24,CAPTION='开 始 朗 读'
     ADD OBJECT 停止朗读  AS COMMANDBUTTON WITH TOP=270,LEFT=450,WIDTH=110,HEIGHT=24,CAPTION='停 止 朗 读'
     ADD OBJECT 暂停朗读  AS COMMANDBUTTON WITH TOP=310,LEFT=450,WIDTH=110,HEIGHT=24,CAPTION='暂 停 朗 读'
     ADD OBJECT 退出程序  AS COMMANDBUTTON WITH TOP=350,LEFT=450,WIDTH=110,HEIGHT=24,CAPTION='退 出 程 序'
     ADD OBJECT 音库信息  AS LABEL         WITH TOP=35 ,LEFT=430, AUTOSIZE=.T.,CAPTION='当前语音库:',BACKSTYLE=0
     ADD OBJECT 语速信息  AS LABEL         WITH TOP=93 ,LEFT=430, AUTOSIZE=.T.,CAPTION='语速:',BACKSTYLE=0
     ADD OBJECT 音量信息  AS LABEL         WITH TOP=153,LEFT=430, AUTOSIZE=.T.,CAPTION='音量:',BACKSTYLE=0
     ADD OBJECT 语音库表  AS COMBOBOX      WITH RowSource=[语音库],TOP=54,LEFT=430,WIDTH=150,HEIGHT=22,ROWSOURCETYPE=5,STYLE=2,TABSTOP=.F.,value=1
     ADD OBJECT 语速控件  AS OLECONTROL    WITH OLECLASS='MSComctlLib.Slider.2',TOP=110,LEFT=420,WIDTH=165,HEIGHT=22,ENABLED=.T.
     ADD OBJECT 音量控件  AS OLECONTROL    WITH OLECLASS='MSComctlLib.Slider.2',TOP=170,LEFT=420,WIDTH=165,HEIGHT=22,ENABLED=.T.

     PROCEDURE 语音库表.InteractiveChange
         lovoice.voice=lovoice.getvoices.item(THISFORM.语音库表.value-1)
     ENDPROC

     PROCEDURE 语速控件.INIT
         THISFORM.语速控件.MIN=-10
         THISFORM.语速控件.MAX=10
         THISFORM.语速控件.value=0
     ENDPROC

     PROCEDURE 语速控件.CHANGE
         LOVOICE.RATE=THISFORM.语速控件.value
     ENDPROC

     PROCEDURE 音量控件.INIT
         THISFORM.音量控件.MIN=0
         THISFORM.音量控件.MAX=100
         THISFORM.音量控件.value=100
     ENDPROC

     PROCEDURE 音量控件.CHANGE
         LOVOICE.VOLUME=THISFORM.音量控件.value
     ENDPROC

     PROCEDURE 开始朗读.CLICK
         LOVOICE.SPEAK(THISFORM.朗读内容.value,3) &&(为1\3时在朗读时也响应其他事件)&&有6个选项(0=)
     ENDPROC

     PROCEDURE 停止朗读.CLICK
         LOVOICE.SPEAK('',2)
     ENDPROC

     PROCEDURE 暂停朗读.CLICK
         IF THISFORM.暂停朗读.CAPTION='暂 停 朗 读'
            LOVOICE.PAUSE()               && 暂停
            THISFORM.暂停朗读.CAPTION='继 续 朗 读'
         ELSE
            LOVOICE.RESUME()              && 恢复
            THISFORM.暂停朗读.CAPTION='暂 停 朗 读'
         ENDIF
     ENDPROC

     PROCEDURE 退出程序.CLICK
         THISFORM.RELEASE
     ENDPROC
ENDDEFI



/*
ISpVoice//成员函数
ISpEventSource继承方法 :ISpEventSource的所有方法都可以从该接口访问
SetOutput :设置当前的输出对象。可以使用NULL值来选择默认音频设备。
GetOutputObjectToken :检索当前音频输出对象的对象标记。
GetOutputStream :检索当前输出流的指针。
Pause :将声音暂停在最近的警报边界并关闭输出设备。
Resume : 将输出设备设置为RUN状态并恢复渲染。
SetVoice :设置用于文本合成的声音的身份。默认情况下,ISPVoice将使用“控制面板”中“语音”属性中设置的语音信息。
GetVoice :检索标识文本合成中使用的声音的对象标记。
Speak :说出文本字符串或文件的内容。
SpeakStream :说出流的内容。
GetStatus :检索与此ISpVoice实例关联的当前呈现和事件状态。
Skip :导致语音向前或向后跳过当前通话文本内的指定数量的项目。
SetPriority :设置语音的优先级。正常,警报,结束。
GetPriority :检索当前语音优先级。
SetAlertBoundary :指定哪个事件应该用作警报的插入点。
GetAlertBoundary :检索当前正用作警报插入点的事件。
SetRate :实时设置文本渲染速率调整。
GetRate :检索当前文本渲染速率调整。
SetVolume :实时设定合成器的输出音量。
GetVolume :检索合成器的当前输出音量。
WaitUntilDone :阻止呼叫者,直到语音完成说话或指定的时间间隔过去了。
SetSyncSpeakTimeout :设置以毫秒为单位的超时时间间隔,此语音同步Speak和SpeakStream调用此超时。
GetSyncSpeakTimeout :检索此ISpVoice实例的同步语音操作的超时间隔。
SpeakCompleteEvent :返回一个事件句柄,当语音完成后,将发出所有待处理的请求信号。
IsUISupported :确定是否支持指定类型的UI。
DisplayUI :显示所请求的UI。
*/

sp = createobject("sapi.spvoice")
spfs = CREATEOBJECT("Sapi.SpFileStream")
spfs.Open("d:\abc.wav", 3, .f.)
sp.AudioOutputStream = spfs
sp.Speak("hello word", 1)
sp.WaitUntilDone(-1)
spfs.Close


&&=== tts word2wav
         xx=NEWOBJECT("Sapi.SpVoice")
         mfs=NEWOBJECT("SAPI.SpFileStream")
         mfs.Format.Type = 4
         mfs.Open(this.wavfile,3,0)
       *   Set the .wav file stream as the output for the Voice object
         xx.AudioOutputStream = mfs
         xx.Rate =  10
         xx.Volume =  99
         xx.Speak("hello word",0)
         wait 'a moment!'  
         mfs.Close
         release xx
#16
kangss2023-01-17 16:36
...

[此贴子已经被作者于2023-1-17 16:44编辑过]

#17
igaoyuan2023-01-17 17:08
回复 15楼 kangss
太好了!感谢感谢!看到有相关更换语音的选项参数
1