9

Java 6 を使用して Ubuntu 10.10 を実行していますが、FreeTTS でオーディオを出力できません。私は今、3台の異なるコンピューターで試してみましたが、友人にUbuntu PCで試してみるように依頼しましたが、彼も同じ問題を抱えていました. MBROLAを取得した後、MBROLAの音声が検出されないという警告さえ表示されなくなりました。何とか何とか何とか..

同じコンピューターを使用して、仮想ボックスを実行し、Windows XP を起動しました。HelloWorld.jar と TTSHelloWorld.jar を実行すると実際にオーディオを取得できましたが、独自のテキストを入力しようとすると、freetts.jar はまだサイレントです。

私が使用するコマンド。

java -jar lib/freetts.jar -text こんにちは

Enterキーを押すと起動し、MBROLAが見つからないという警告メッセージが表示されていましたが、CTRL-Cで停止するまでそこに留まります。

私は自分が何を間違っているのか、なぜ他の誰もこの問題を抱えていないのか理解できません. 誰でも私を助けることができますか?

ありがとう、

ジョン

4

3 に答える 3

10

私は 1 週間、Ubuntu で FreeTTS を動作させようとしている学生です。そして最後に、ここで答えを見つけました: hakvroot に感謝します!

あなたの答えは完璧でしたが、あなたは実装を入れていませんでした.JavaStreamingAudioPlayerクラスで何が起こっているのかを理解するのにかなり1時間かかりました. 完全に未知の Java コード (私はまだ学生です) で「ダイビング」に慣れていない私のような他の人々を助けるために、ここに私のコードを置き、それが他の人々の助けになることを願っています :) .

まず、より詳細な説明: 152 行目あたりで、JavaStreamingAudioPlayer が Line を開きます。ただし、この操作には時間がかかる場合があるため、使用する前に、開いていることを確認する必要があります。現在の実装で使用されている解決策は、この行をリッスンする LineListener を作成してからスリープすることです (スレッドの wait() メソッドを使用)。

LineListener は、notifyAll() を使用してメイン スレッドを「ウェイクアップ」し、ラインが開かれたことを保証するタイプ「OPEN」の LineEvent を受け取った場合にのみこれを行います。

ただし、ここで hakvroot によって説明されているように、問題は、Ubuntu で使用される DataLine の特定の動作のために、通知が送信されないことです。

そのため、コードの同期、wait()、および notifyAll() 部分を削除しましたが、hakvroot として、JavaStreamingAudioPlayer が Line を開く前に使用しようとする可能性があります。JavaStreamingAudioPlayer を停止するには、新しいメカニズムで確認を待つ必要があります。確認が到着したときに、後でそれを起こしてください。

そこで、havkroot が使用したセマフォを使用しました (このロック システムの説明については、Javadoc を参照してください)。

  • ラインが開かれると、1 つのスタックが取得されます (つまり、0 のままです)

  • 回線を使用したい場合は、別の回線を取得しようとします (そのため停止します)

  • リスナーが探しているイベントを取得すると、セマフォが解放されます

  • これにより、次の部分に進むことができる JavaStreamingAudioPlayer が解放されます

  • セマフォを再度解放することを忘れないでください。これにより、次の行を開くためのスタックが再び 1 つになります。

そして、ここに私のコードがあります:

セマフォ変数を宣言します。

private Semaphore hackSemaphore;

コンストラクターで開始します。

hackSemaphore = new Semaphore(1);

次に、最初の部分を置き換えます (どこに置くかについては、hakvroot を参照してください)。

            line = (SourceDataLine) AudioSystem.getLine(info);
            line.addLineListener(new JavaStreamLineListener());

            line.open(format, AUDIO_BUFFER_SIZE);
            hackSemaphore.acquire(); 
            hackSemaphore.acquire(); 
            opened = true;
            hackSemaphore.release();

そして第二部:

    public void update(LineEvent event) {
        if (event.getType().equals(LineEvent.Type.OPEN)) {
            hackSemaphore.release();
        }
    }
于 2012-07-17T01:17:02.070 に答える
10

すでにこの問題を解決できたかどうかはわかりませんが、同じ問題 (Ubuntu 10.10 / JavaSE6) に遭遇しました。FreeTTS ソースを調査した結果、com.sun.speech.freetts.audio.JavaStreamingAudioPlayer にデッドロックが原因であることがわかりました。このデッドロックは、Line が開かれ、Line のタイプが org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine である場合に発生します (これは、JavaSE6 を使用する Ubuntu 10.10 のデフォルトである可能性があります)。Line を開いて音声を出力したい場合は常に、このデッドロックが発生します。

このデッドロックの原因は、JavaStreamingAudioPlayer で Line に関する仮定が行われていることにあります。つまり、Line.open() が呼び出されたのと同じ Thread から、または Line.open() が呼び出された後に、タイプが open の LineEvent がすべての LineListener に通知されるということです。が開かれました (そして Line.open() への呼び出しが戻ることができます)。これは、PulseAudioSourceDataLine には当てはまりません。最初に PulseAudio イベント Thread からすべての LineListeners を呼び出し、それらすべてが戻るのを待ってから、open 呼び出しから戻ります。JavaStreamingAudioPlayer が Line.open() の呼び出しの周りで同期を強制し、Line が実際に開いているかどうかを確認するタスクである特定の LineListener を処理すると、デッドロックが発生します。

この問題を解決するために私が選択した回避策は、この問題のない AudioPlayer を実装することです。基本的に JavaStreamingAudioPlayer をコピーし、196 行目と 646 行目の同期ブロックを変更しました (参照用の完全なソース: http://www.javadocexamples.com/java_source/com/sun/speech/freetts/audio/JavaStreamingAudioPlayer.java.html )。

___: // This is the actual JavaStreamAudioPlayer source, not the fix
195: ...
196:     synchronized (openLock) {
197:         line.open(format, AUDIO_BUFFER_SIZE); // Blocks due to line 646
198:         try {
199:             openLock.wait();
200:         } catch (InterruptedException ie) {
201:             ie.printStackTrace();
202:     }
203: ...

643: ...
644: public void update(LineEvent event) {
645:     if (event.getType().equals(LineEvent.Type.OPEN)) {
646:         synchronized (openLock) { // Blocks due to line 196
647:             openLock.notifyAll();
648:         }
649:     }
650: }
651: ...

両方の同期ブロックを削除し、両方の部分が相互に除外されるようにする代わりに、セマフォを使用して Line が実際に開いていることを通知しました。もちろん、PulseAudioSourceDataLine は戻り時に開かれることが既に保証されているため、これは実際には必要ではありませんが、別のプラットフォームで同じコードをテストする場合はうまくいく可能性が高くなります。同時に複数のスレッドでラインを開いたり閉じたり開いたりすると何が起こるかを説明するのに十分なほど長くコードを掘り下げませんでした。これを行う場合は、おそらく JavaStreamingAudioPlayer のより大きな書き換えを見ていることになります;)。

最後に、新しい AudioPlayer を作成した後、デフォルトの JavaStreamingAudioPlayer ではなく実装を使用するように FreeTTS に指示する必要があります。これは、

System.setProperty("com.sun.speech.freetts.voice.defaultAudioPlayer", "classpath.to.your.AudioPlayer");

コードの早い段階で。

うまくいけば、これはすべてうまくいくでしょう。

于 2011-06-07T09:43:41.907 に答える
1

Ubuntu 12.04 / OpenJDK-6でも同じ問題が発生したと思いますが、Voice.allocate()で実行がスタックし、エラーも応答もありません。OpenJDKの代わりにOracle/Sun JDK-6を使用してみましたが、問題なく動作しました。

PS UbuntuにSunJDKをインストールし、デフォルトとして構成するための優れたガイド http://www.devsniper.com/ubuntu-12-04-install-sun-jdk-6-7/

于 2012-07-03T16:45:39.727 に答える