Android Tips #48 BGM や効果音を再生する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Android アプリで音データを再生するには

Android アプリで BGM や効果音などのような音データを再生するにはいくつか方法(クラス)があります。ただ方法が分かれているわけではなく、それぞれのクラスには特徴があるので再生したいデータや場面に応じて適切なクラスを使う必要があります。
ということで、SoundPool、MediaPlayer、AudioTrack、JetPlayer のそれぞれのクラスの使いかたと特徴をまとめました。

SoundPool

SoundPool は短い音データの再生に適したクラスです。ファイルサイズによっては読み込みに少し時間が必要な場合はありますが、一度読み込んでしまえば遅延なく再生できます。

特徴

  • データをあらかじめデコード、Nativeのヒープ領域に一時展開して再生する
  • データの読み込みに時間がかかるが、一度読み込んでしまえば遅延は少ない
  • 1つのインスタンスで複数のデータを再生できる
  • 再生できるデータは10秒程度まで
  • 効果音の再生に適している

サンプル

private SoundPool mSoundPool;
private int mSoundId;
@Override
protected void onResume() {
    super.onResume();
    // 予め音声データを読み込む
    mSoundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
    mSoundId = mSoundPool.load(getApplicationContext(), R.raw.cat, 0);
}
@Override
protected void onPause() {
    super.onPause();
    // リリース
    mSoundPool.release();
}
private void playFromSoundPool() {
    // 再生
    mSoundPool.play(mSoundId, 1.0F, 1.0F, 0, 0, 1.0F);
}

音声データの読み込みは onResume() のときなど実際に再生するときより前に処理しておいたほうが良いでしょう。

MediaPlayer

MediaPlayer は音楽ファイルなどの再生に適しているクラスです。ストリーミング再生ができるので、サーバーにある音データをストリーミング再生する、などという実装ができます。

特徴

  • 音データをストリーミング再生する
  • 尺が長い音データの再生ができる
  • 同時に4つまでしか再生できない(らしい)
  • BGM の再生に適している

サンプル

private void playFromMediaPlayer() {
    MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.strings);
    mediaPlayer.start();
}

AudioTrack

AudioTrack はバイトデータを再生するクラスです。プログラム上から動的作った音データを再生するときに適しています。

特徴

  • 音データをバイト配列で渡して再生する
  • MODE_STATIC と MODE_STREAM の2つのモードを選択できる
  • 音データをプログラムから動的に作って再生したい場合に適している

サンプル

private void playFromAudioTrack() {
    try {
        // 音データを読み込む
        InputStream is = getResources().openRawResource(R.raw.bird);
        byte[] byteData = new byte[(int) is.available()];
        is.read(byteData);
        is.close();
        // バッファサイズを取得
        int bufSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
        // AudioTrackインスタンスを生成
        AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT, bufSize, AudioTrack.MODE_STREAM);
        // 再生
        audioTrack.play();
        audioTrack.write(byteData, 0, byteData.length);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

データの読み込みが発生しているので、実際に使う場合は非同期で実装しましょう。また、サンプルソースでよく見かける AudioFormat.CHANNEL_CONFIGURATION_MONO は非推奨になっているので AudioFormat.CHANNEL_OUT_MONO を使いましょう。
以下の記事で音データをプログラムから作って再生する方法が載っていますので、ぜひ参考にしてください!

【クリスマスだし】Androidで8ビット音を生成してジングルベルを奏でてみる【25日目の1】

JetPlayer

JetPlayer は JET 形式のファイルを再生するためのクラスです。複数の音データを1ファイルにでき、そのデータを読み込んで管理できるところが特徴です。

特徴

  • 主に MIDI 形式のファイルをベースにして作る JET 形式のファイルを再生する
  • 複数の音データを一つのファイルとして扱い、管理することができる
  • 鍵盤アプリなど、インタラクティブなアプリに適している

サンプル

private void playFromJetPlayer() {
    // JetPlayerインスタンスを取得
    JetPlayer jetPlayer = JetPlayer.getJetPlayer();
    // 既存のキューをクリア
    jetPlayer.clearQueue();
    // JETファイルの読み込み
    jetPlayer.loadJetFile(getResources().openRawResourceFd(R.raw.level1));
    // 指定したセグメントの音データを再生
    byte segmentId = 0;
    jetPlayer.queueJetSegment(1, 0, 1, 0, 0, segmentId);
    jetPlayer.play();
}

サンプルの JET データは Android SDK のサンプルソースを使いました。samples/android-17/JetBoy がプロジェクトファイルなのでこれをインポートして試してみても良いと思います。

ソースコード

今回サンプルで作ったソースコードを GitHub に公開しました!それぞれのクラスでどんな感じで再生されるのか確かめたいときに使ってください。

suwa-yuki/PlaySoundSample

なお、再生した音データは以下のサイト様よりいただきました!ありがとうございます。

フリーBGM Music with myuu

まとめ

ということで、効果音には SoundPool を、BGM には MediaPlayer を使っていけば良さそうです。BGM や効果音を取り扱うアプリはゲームが主流ですが、タップしたときの効果音に使うなど、どんなアプリにおいても分かりやすいフィードバックになると思うので、ぜひ活用していきたいところです。まぁ、マナーモードにされると無意味なんですが…。
特徴を簡潔にまとめましたが、ご指摘大歓迎です!ここが違うよなどありましたらぜひぜひお気軽にコメントください。

参考