unoh.github.com

JavaでMP3を再生する

Mon Nov 05 22:49:10 -0800 2007

こんにちは。NAKAMURAです。最近ではFlashでMMLやDTMの話題など、音楽好きには嬉しい情報が飛び交っています。 ここは音楽ネタで便乗してみたいところですので、JavaでMP3を再生する方法を紹介してみたいと思います。

Java Media Framework APIを利用する方法もありますが、今回はLGPLライセンスで公開されている JLayerを利用してMP3を再生してみます。

再生してみる

早速、JLayerを使ってMP3を再生するサンプルクラスを作ってみました。ダウンロードページよりjarを取得してクラスパスに追加しています。

package net.unoh.mp3;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;

public class MyPlayer {

    private Player player;

    private BufferedInputStream stream;

    public void play(String file)
    throws JavaLayerException, FileNotFoundException {
        stream = new BufferedInputStream((new FileInputStream(file)));
        player = new Player(stream);
        player.play();
    }

    public void close() throws IOException {
        if (player != null) {
            player.close();
        }
        if (stream != null) {
            stream.close();
        }
    }

    public static void main(String[] args) {
        MyPlayer player = new MyPlayer();
        try {
            player.play("Pull Me Under.mp3");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JavaLayerException e) {
            e.printStackTrace();
        } finally {
            if (player != null) {
                try {
                    player.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

実行すると、お気に入りのPull Me Underを再生することが出来ました。

少しだけ深追いしてみる

これだけでは面白くありませんので、JLayerのソースコードを少し追ってみることにします。

javazoom.jl.player.Playerクラスのplayメソッドをみてみると、

while (frames-- > 0 && ret)
{
    ret = decodeFrame();
}

というwhileループがあります。ここが再生のループのようです。

次にdecodeFrameメソッドを見てみると、audioという変数がwriteしているのがわかります。

out = audio;
if (out!=null)
{
    out.write(output.getBuffer(), 0, output.getBufferLength());
}

続いて、audio変数の実体のJavaSoundAudioDeviceFactoryを見てみるとwriteImplメソッドでSourceDataLineのwriteをしていることがわかります。

protected void writeImpl(short[] samples, int offs, int len)
    throws JavaLayerException
{
    if (source==null)
        createSource();

    byte[] b = toByteArray(samples, offs, len);
    source.write(b, 0, len*2);
}

これで音を出力することができるのがわかりますが、MP3のフォーマットの制御はどうなっているのでしょうか。

もう一度PlayerクラスのdecodeFrameメソッドを見てみると、decoder変数がアウトプットに必要な情報を取得しているようです。

SampleBuffer output = (SampleBuffer)decoder.decodeFrame(h, bitstream);

javazoom.jl.decoder.DecoderクラスのdecodeFrameメソッドから呼ばれているretrieveDecoderメソッドでMP3のメタ情報の読み込みが行われているのが解ります。

まとめ

JavaでMP3を再生してみました。javax.sound.sampled.AudioFormatクラスやjavax.sound.sampled.SourceDataLineクラスを使ったことのある人であれば、大体想像通りのことをやっているなと思われたのではないでしょうか。

Javaで音を再生してみよう思われた方の参考になれば幸いです。