まず第一に、これはDelphi と SAPIの複製ではありません。「Delphi の SAPI」という件名に特定の問題があります。
コンポーネント パレットで TSpVoice コンポーネントを取得するために、Delphi 2009 の優れた Import Type-Library ガイドを使用しました。これはうまくいきます。と
var
SpVoice: TSpVoice;
私は書くことができます
SpVoice.Speak('This is an example.', 1);
非同期オーディオ出力を取得します。
最初の質問
ドキュメントによると、私は書くことができるでしょう
SpVoice.Speak('This is an example.', 0);
同期オーディオ出力を取得しますが、代わりに EZeroDivide 例外が発生します。なぜですか?
2 番目の質問
しかし、もっと重要なことは、SpVoice オブジェクトを動的に作成できるようにしたいということです (これは、SpVoice オブジェクトを "遅延バインド" するために呼び出されると思います)。また、エンド ユーザーのシステムに SAPI サーバーが存在することを想定したくないという理由もあります。
この目的のために、私は試しました
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: Variant;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SpVoice.Speak('this is a test', 0);
end;
明らかに何もしません!(0 を 1 に置き換えると、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;
さらに、サウンドを非同期で再生したい場合は、プレーヤーが範囲外にならないようにする必要があります。