こんにちは。いつもお世話になっています。
日本語文と英語文を交互に発音させるために、
日本語の発音をC言語で作り使っていますが、
下の例では、ボタンを交互に押すと、発音されないことがあります。
SpeaktoMeを使うと、すべて発音されます。
日本語は発音されなくてもいいやと思って日本語文に使っていますが。
何か解決策があれば、教えていただきたいと思い投稿しました。
よろしくお願いします。
procedure TFLily.JSpeak(WD:string);
var
s:string;
res:boolean;
Si: TStartupInfo;
Pi: TProcessInformation;
begin
Bunput(WD); application.ProcessMessages;
s := 'c:\lily\JapaneseSpeakB.exe';
FillChar(SI, SizeOf(SI), #0);
SI.cb := SizeOf(SI);
SI.dwFlags := STARTF_USESHOWWINDOW;
SI.wShowWindow := 1;
Res := CreateProcess(PChar(s),nil,nil,nil,False,
CREATE_DEFAULT_ERROR_MODE,nil,nil,SI, PI);
end;
procedure Tlily.BunPut(wd:string);
var
InBuff: string;
FileName1:string;
F: textfile;
i:integer;
begin
FileName1:='c:\Flily\日本語文.txt';
AssignFile(F, FileName1); Rewrite(F);
INbuff:=WD;
writeln(F,inBuff);
CloseFile(F);
end;
procedure TFLily.Button3Click(Sender: TObject);
begin
//SpeakToMe(Edit1.text); application.processMessages;
JSpeak(Edit1.text); application.processMessages;
end;
procedure TFLily.Button4Click(Sender: TObject);
begin
//SpeakToMe(Edit2.text); application.processMessages;
JSpeak(Edit2.text); application.processMessages;
end;
procedure TFLily.SpeakToMe(WD:string);
var
tts : OleVariant;
begin
// if EJSWFLG=false then exit;
// then tts.selectVoice('Zira') else tts.selectVoice('Haruka');
tts := CreateOleObject('SAPI.SpVoice');
// tts.volume:=100;
// tts.voice:= 'Microsoft Haruka desktop';
tts.Speak(WD);
{
<英語用モジュール>
synth.SelectVoice(英語者名:Zira)
synth.Speak(英語発声文)
synth.Dispose()
<日本語用モジュール>
synth.SelectVoice(日本語者名:Haruka)
synth.Speak(日本語発声文)
synth.Dispose()
}
end;
まずわかりにくさの整理を
CreateProcessを使ってコマンドライン実行で音声データをしゃべらせる場合と
CreateOleObjectを使ってOLEオブジェクトとしてしゃべらせる場合とで挙動が異なります。
前者は再生されないときがありますが、後者は正常に再生されます。
こういうことかな?
で次
CreateProcessもCreateOleObjectも使い終わったら終了処理が必要なのではないでしょうか?
CreateOleObjectは連続で実行されても多重で実行されるので見た目問題なし(メモリには残りそうですが)
CreateProcessは呼ばれたときに、現在再生中かどうか判断して
再生中なら再生しない仕様になっているのだと思います。
そしてCreateProcessで呼んだ場合はプロセス終了(音声の再生終了)まで待機してから終了処理を
実行すべきです。
どうやるかは、使いたい命令の後ろにスペースを空けて Delphi でググればすぐ答えが出てきます。
takeさんへ
ありがとうございます。
ネットで調べてみます。
ネットで検索すると、X-RAYさんのHPに行けて下記のように変更しました.
しかし、コンパイルすると、
GetExitCodeProcess(PI.hProcess, Result);
の行でタイプが一致しないといけないとかのエラーが出ます。
IF分より上はマネしてないのですが、そこが問題でしょうか??
procedure TForm1.JSpeak(WD:string);
var
s:string;
result:integer; //boolean;
Si: TStartupInfo;
PI: TProcessInformation;
begin
Bunput(WD); application.ProcessMessages;
s := 'c:\英文練\JapaneseSpeakB.exe';
FillChar(SI, SizeOf(SI), #0);
SI.cb := SizeOf(SI);
SI.dwFlags := STARTF_USESHOWWINDOW;
SI.wShowWindow := 1;
if CreateProcess(PChar(s),nil,nil,nil,False,
CREATE_DEFAULT_ERROR_MODE,nil,nil,SI, PI)=false then
begin
Result := WAIT_FAILED
else
begin //起動したプロセスが終了するまで待つ
while WaitForSingleObject(PI.hProcess, 100) = WAIT_TIMEOUT do
Application.ProcessMessages;
GetExitCodeProcess(PI.hProcess, Result);
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
end;
// Res := CreateProcess(PChar(s),nil,nil,nil,False,
// CREATE_DEFAULT_ERROR_MODE,nil,nil,SI, PI);
end;
GetExitCodeProcessの定義を検索してみましたか?(ソースコード上で[Strl]+クリック)
第2パラメータが var lpExitCode: DWORD となってますよね?ですからここにはDWOD型の変数しか書けません。
通りすがりさんへ
いつもありがとうございます。
Var
result:Dword;
とすると、コンパイルは成功しました。
連続使用すると、発音されない時があるという現象は変わりませんでした。
うまい方法があれば、教えてくださいませ。
とりあえずJSpeakを連続に呼び出すときに、1回ずつSleep(1000);を挟んだらどうなりますか?
またうまくいくのであれば1000を減らしていくとどうなりますか?あたりを試してみては。
アプリケーションの動きがちょっと理解しておられないだけかと
ボタンクリックイベント内で
JSpeak発音→JSpeak発音終了待ち
処理が行われますが
この間も Application.ProcessMessagesによりボタンクリックが可能です。
発音中に再度発音させるので発音できないのでしたら
発音中は
1.発音中は発音させない
2.「キュー」を用意して処理を後回しにする
のどちらかが必要です。
とりあえず前者の処理を作ってみましょうか?
通りすがりさん、takeさん、ありがとうございました。
JSpeakの前後に2秒とかを置いて、起動後しゃべる前にボタンを
4連続クリックしたら4連続話をさせることができました。
ただ、やはり、話してるときにボタンをクリックしたら話しはしません。
話をさせないということで、話してる途中であるという変数speakingflgを
作って、話し中なら待つということもやってみましたが、
while speakingflg=true do sleep(1000);
いつまでも終わらない感じで、うまくいきませんでした。
で、ボタンが押されても、SpeakingFlg=trueのときは処理をしないようにしました。
形の上では、問題はなくなりました。
ツイート | ![]() |