[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
ssが音を出さなくなる問題と白藤さんの解決案 (長文)
渡辺@湘南工科大です。
CC:小出様、
今日 白藤さんから、スピーチサーバーが音を出さなくなる問題に関して、解
決のアイデアを頂きました。BEP MLで議論した方がよいように思ったので、
MLに白藤さんへの返事を書きます。
今、ソースを見て思い出したのですが、stop()はBishopさんのオリジナルでは
以下のようになっていたのですが、このままでは日本語エンジンを使ったときに
stop()でハングアップするので、小出さんに調べてもらって修正しました。
A オリジナル:
void VoiceManager::stop()
{
m_speaking_cs.Lock();
QueueBlock *qb = speaking_head;
for(int i=0; i<NUMENGINES; i++) {
engines[i].mpITTSCentral->AudioReset();
}
while(qb != 0) { // empty the blocks but keep them...
qb->QText = "";
qb->QInit = "";
qb = qb->next;
}
m_speaking_cs.Unlock();
}
B 小出改良版:
void VoiceManager::stop()
{
m_speaking_cs.Lock();
QueueBlock *qb = speaking_head;
// BEP
while(qb != 0) { // empty the blocks but keep them because...
qb->QText = "";
qb->QInit = "";
qb = qb->next;
}
for(int i=0; i<NUMENGINES; i++) {
engines[i].mpITTSCentral->AudioReset();
}
m_speaking_cs.Unlock();
}
英語と日本語ではエンジンの応答速さが異なり、英語で問題なかったところ
が日本語で問題化したようです。AudioResetをかけると TextDataDoneが発生
してqueueを更新してしまい、そのあとで qbを操作すると不法なアクセスに
なりました。
C 白藤改良版は:
> しゃべらない場合、start_queue() のif文の
> 最後の else に入ってきています。
>
> if(head == 0) {
> } else if(speaking_head == 0) {
> } else {
> //しゃべらないときはここに入ってくる。
> }
>
> この部分に問題があるのか、speaking_head
> から続くリストが長くて、そのほとんどのQInit, QTextが空で
> あるために、TTS の解析で時間だけがかかってしまい、結果として
> 人間側が求める時間以内にしゃべり始められないのが原因の
> 可能性があります。
> 今回のソースは問答無用(SAPIと同期もとらずに)に、リストの
> 長さを0にすることで、SAPIが空の文を解析する必要がないように
> しています。
void VoiceManager::stop()
{
m_speaking_cs.Lock();
QueueBlock *qb = speaking_head;
// BEP
while(qb != 0) { // empty the blocks but keep them
// because notifications may come in...
qb->QText = "";
qb->QInit = "";
qb = qb->next;
}
for(int i=0; i<NUMENGINES; i++) {
engines[i].mpITTSCentral->AudioReset();
}
// BEP
while(qb != 0) {
QueueBlock *qbnext = qb->next;
delete qb;
qb = qbnext;
}
speaking_head = NULL;
speaking_tail = NULL;
m_speaking_cs.Unlock();
}
として、立て続けにstopを送った際に音がでなくなる問題を回避しようとい
うわけですね。
全エンジンにAudioResetをかけたら、キューを空にしても問題ないような気
がするからこれで構わないような気がします。
と思ったのですが、前の文の途中でstop()をかけて次の文を音声化すると、
次の文のキューの音声化がフライングします。
たとえば、
MyPrintMessage();
for ( i=0 ; i < MAX_SIZE ; i++ ){
の場合、MyPrintMessageを読んでいる途中でC-nで次の文を読ますと、
以下 VoiceManger.cppの関数呼び出しのログ:
// MyPrintMessage();を読んでいる途中でstop()がかかった
(行664) Stopped speaking
// 次の行を読む
(行522) Start queue
(行549) :np-indent TextData '\rst\\spd=225\indent 4'
(行875) TextDataDone dw=0
(行579) next queue
(行586) deleting 7960e0
(行619) BEP; :nu nq TextData '\rst\\spd=225\for'
(行875) TextDataDone dw=0
(行579) next queue
(行586) deleting 796120
(行619) BEP; :np nq TextData '\rst\\spd=225\ open parenthesis i
equal 0 semicolon i less than'
(行875) TextDataDone dw=0
(行579) next queue
(行586) deleting 796320
(行619) BEP; :np-smooth nq TextData '\rst\\spd=225\MAX underscore SIZE'
(行875) TextDataDone dw=0
(行579) next queue
(行586) deleting 796e20
(行619) BEP; :np nq TextData '\rst\\spd=225\ semicolon i plus plus
close parenthesis left brace '
(行875) TextDataDone dw=0
(行579) next queue
(行586) deleting 797da0
と正しい順番にキューイングしてキューを処理しているのに、この文の読み
上げに参加する 3つのキューが重なって聞こえてしまいます。
なぜだろう? TextDataDoneが返ってくるタイミングが早すぎるからというの
が正しい答えだと思いますが、ではなぜBだとタイミングが合うのだろう?
Bのバージョンに戻すとちゃんと同期して喋ります。
またCでも、MyPrintMessage()を読み終わるまで待ってから次の行を読ますと
ちゃんと喋ります。
というわけでなんかおかしくなっていますが、なぜだろう、難しい...
白藤さんや小出様、理由がわかりますか?