Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

wav(javax.sound)とmp3(javafx.scene.media.mediaPlayer)について

初めて利用させていただきます。よろしくお願いいたします。

シューティングゲーム(リアルタイムで動くような処理)を作っていまして、困っています。

javax.sound.sampledを利用してwavを鳴らしています。
そのwav自体は1秒程度で鳴り終わり、数秒後に再利用しています(javax.sound.sampled.clip.setFramePosition(0); → clip.start();)

JavaFXに置き換えるため、mp3化を検討しているのですが、上記と同じように再利用を行うと(javafx.scene.media.mediaPlayer.seek(Duration.ZERO); → mediaPlayer.play();)、一瞬、他の処理が止まってしまい(カクカクする)、使い物になるとはいえない状態となります。

(ちなみに、JavaFX(javafx.scene.media.mediaPlayer)でwavを鳴らしても、同じような状況となります)

カクカクを回避する方法はありますでしょうか?

よろしくお願いいたします。

6

回答

3151

閲覧

6件の回答

評価

0

そのAPIを使ったことはないが。
一瞬では終わらない処理があったり、処理の長短がその都度違ってメインサイクルではタイミングを狂わせてしまう場合、
その役割をスレッド分割してマルチスレッド処理にすると良い場合も多い。
その音楽再生は、すでに別スレッドで演奏している状態なんだろうか?

評価

0

ご回答ありがとうございます。
質問主です。

補足ですが、mediaPlayer.play()を実行したタイミングが重いようで、その後の演奏中はそこまで重いということは ないようです。再生の途中はカクカクしません。始めのみカクカクします。

コメントいただける前は、自前で実行しているゲーム上のスレッド(JavaFXスレッド。Timelineクラス)の中でmp3を再利用していましたが、その部分のみ、別スレッド(javafx.application.Platform.runLater)で動くように変更してみました。

javafx.application.Platform.runLater(new Runnable() {
    @Override
    public void run() {
        // ポジションを戻す
        mediaPlayer.seek(Duration.ZERO);
        // スタート
        mediaPlayer.play();
    }
});

しかし、カクカクは解消せず。
API自体が重いかもしれません。
mediaPlayer.play()メソッド自体が、synchronizedされてますし・・・。
(ソースをそれ以上、先へは追っていませんが・・・com.sun.media.jfxmediaパッケージに入ってしまって、早々に退散でした。)

とりあえずは、解決するまでは、元々のjavax.soundでwavを鳴らすようにしようかと思います。

もし、また、なにかあれば、情報をいただければと思います。
ありがとうございます。

評価

30

>mediaPlayer.play()メソッド自体が、synchronizedされてますし・・・。
synchronizedは単に「俺がこれを使ってる間、他のスレッドはこれを使うな」という意味だ。
確かに内部的に特殊なことをしているが、synchronized=重いメソッドとはならない。

シークして再利用せず、1回ごとに別のMediaPlayerインスタンスに再生させるとどうなんだろう?
以下を最初とrun()から呼ぶようにでもすると?
void playMedia() {
    (mediaPlayer = new MediaPlayer(media)).play();
}

あと、使っているのがJava8ならRunnableの生成はラムダ式で単純化できるので、
この際一緒に覚えてもいいかもしれない。
javafx.application.Platform.runLater(this::playMedia);

評価

0

ご回答ありがとうございます。
質問主です。

> シークして再利用せず、1回ごとに別のMediaPlayerインスタンスに再生させるとどうなんだろう?
> (mediaPlayer = new MediaPlayer(media)).play();

試してみました。
結果、カクカクしませんでした!すこぶる快調です。
驚きです。解決です。びっくりです!ありがとうございます!
これで、wave利用からmp3へ移行できそうです。

(しかし、なんだか、裏ワザ的な感じですね・・・)


> 確かに内部的に特殊なことをしているが、synchronized=重いメソッドとはならない。

たしかに、こちらは書いてから、しまった~と思いました。
(気づいてはいました)
ご指摘、ありがとうございます。

ラムダ式(メソッド参照ですかね)についても、ご指南、ありがとうございます。
Java8は勉強中です。慣れていきたいと思います。

ありがとうございました。

評価

0

すいません・・・。
質問主です。

改めて、確認をしたところ(動作検証したところ)、まずいところがあり、
取り急ぎ、ご報告しにきました。

どうも、new MediaPlayer(media)をした時点で、
別スレッド(専用のスレッド)が立ち上がり、その前のオブジェクトもそのまま残ってしまうという状況になるようです。
そのため、最後は、メモリリークの状態になりOutOfMemoryErrorになる か スレッドが無数に立ち上がり止まってしまうようです。(数百、数千という単位で再実行しています)
(スレッドが複数上がることは、ThreadGroup.list()で確認)

回避するために、MediaPlayer.dispose()メソッドを呼ぶようにしてみましたが、
またカクカクの状態になり(最初の状態より悪化)、使い物になりません。

他の回避方法を思いつきましたので、これから試してみます。

MediaPlayer.setCycleCount(Integer.MAX_VALUE)
を設定しつつ、
MediaPlayer.setOnEndOfMedia(Runnable value)
or
MediaPlayer.setOnRepeat(Runnable value)
したタイミングで
MediaPlayer.stop()
させてみます。
再開は、
MediaPlayer.play()
です。

よろしくお願いいたします。

評価

0


すいません。追加情報です。

確認しました。
結果、だめでした。

MediaPlayer.stop()→MediaPlayer.play()すると、カクカクの状態となります。
pause→playでも、同様の状態となりました。

他に思いつく手は、今のところ、なしです。

また、アドバイスがあれば、お願いいたします。

よろしくお願いいたします。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。