Delphi SAPI 文本转语音
首先:这不是 Delphi 和 SAPI 的重复。我对“SAPI in Delphi”主题有一个具体问题。
我使用了 Delphi 2009 中出色的导入类型库指南来在组件选项板中获取 TspVoice 组件。这很好用。我
var
SpVoice: TSpVoice;
可以编写
SpVoice.Speak('This is an example.', 1);
以获得异步音频输出。
第一个问题
根据文档,我可以编写
SpVoice.Speak('This is an example.', 0);
以获得同步音频输出,但我得到了 EZeroDivide 异常。这是为什么呢?
第二个问题
但更重要的是,我希望能够动态创建 SpVoice 对象(我认为这被称为“后期绑定”SpVoice 对象),部分因为我的应用程序的所有会话中只有一小部分会使用它,部分原因是我不想假设最终用户系统上存在 SAPI 服务器。
为此,我尝试了,
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: Variant;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SpVoice.Speak('this is a test', 0);
end;
但显然没有任何作用! (用 1 替换 0 会导致 EZeroDivide 异常。)
免责声明
我对 COM/OLE 自动化相当陌生。对于我在这篇文章中表现出的任何无知或愚蠢,我深表歉意...
更新
为了每个遇到与我相同问题的人的利益,François 的视频解释了 SAPI/Windows 中存在一个错误(某些地方不兼容),这使得以下代码引发 EZeroDivide 异常:
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: variant;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SpVoice.Speak('This is a text.');
end;
如视频所示,解决方案是更改 FPU 控制字:
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: variant;
SavedCW: Word;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SavedCW := Get8087CW;
Set8087CW(SavedCW or $4);
SpVoice.Speak('This is a text.');
Set8087CW(SavedCW);
end;
另外,如果您想异步播放声音,则必须确保播放器不超出范围!
First of all: this is not a duplicate of Delphi and SAPI. I have a specific problem with the "SAPI in Delphi" subject.
I have used the excellent Import Type-Library guide in Delphi 2009 to get a TSpVoice component in the component palette. This works great. With
var
SpVoice: TSpVoice;
I can write
SpVoice.Speak('This is an example.', 1);
to get asynchronous audio output.
First question
According to the documentation, I would be able to write
SpVoice.Speak('This is an example.', 0);
to get synchronous audio output, but instead I get an EZeroDivide exception. Why's that?
Second question
But more importantly, I would like to be able to create the SpVoice object dynamically (I think this is called to "late-bind" the SpVoice object), partly because only a very small fraction of all sessions of my app will use it, and partly because I do not want to assume the existance of the SAPI server on the end-user's system.
To this end, I tried
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: Variant;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SpVoice.Speak('this is a test', 0);
end;
which apparently does nothing at all! (Replacing the 0 with 1 gives me the EZeroDivide exception.)
Disclaimer
I am rather new to COM/OLE automation. I am sorry for any ignorance or stupidity shown by me in this post...
Update
For the benefit of everyone encountering the same problem as I did, the video by François explained there is a bug in SAPI/Windows (some incompatibility somewhere), which makes the following code raise the EZeroDivide exception:
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: variant;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SpVoice.Speak('This is a text.');
end;
The solution, as presented by the video, is to alter the FPU control word:
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: variant;
SavedCW: Word;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SavedCW := Get8087CW;
Set8087CW(SavedCW or $4);
SpVoice.Speak('This is a text.');
Set8087CW(SavedCW);
end;
And, in addition, if you want to play a sound asynchronously, then you have to make sure that the player doesn't go out of scope!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可能会对 此 CodeRage 4 会议感兴趣,时间为 "支持语音的 Delphi 应用程序 (zip)"
您将获得您正在寻找的“操作方法”...
(我猜你使用的是 Vista 或 +,因为 XP 上没有发生零除法)
You may find interesting to see this CodeRage 4 session on "Speech Enabling Delphi Applications (zip)"
You'll get the "how-to" you're looking for...
(and I guess you are on Vista or + as the the zero divide did not happend on XP)
我在 Delphi XE2 中遇到了同样的问题。问题中提出的
Set8087CW(SavedCW or $4)
解决方案对我不起作用。它只是用另一个浮点异常替换了除零异常。对我有用的是:
I was having the same problem in Delphi XE2. The
Set8087CW(SavedCW or $4)
solution presented in the question did not work for me. It merely replaced the division by zero exception with another floating point exception.What did work for me is this: