音楽を演奏するには(AndroidMode編)

◆PROCESSING 逆引きリファレンス

 カテゴリー:スマホ(AndroidMode)

音楽を演奏するには(AndroidMode編)

【概要】

PROCESSINGにAndroidMode を導入する事で、PROCESSINGで開発したプログラムをAndroid端末上で動かす事ができるようになります。

AndroidModeの導入については「PROCESSINGをAndroid端末で動かすには(4.0版)」記事を参照してください。

AndroidModeで音楽や効果音を演奏するには、Android SDK が提供している命令を使う事になります。※

  • 効果音:SoundPool を利用する
  • BGM:MediaPlayer を利用する

※この他にも JetPlayer クラスや AudioTrack クラスを使う方法があります。

鳴らしたい音が音楽(BGMなど)なのか効果音なのかにより、利用する命令が異なります。

SoundPoolについては「効果音を鳴らすには(AndroidMode編)」を参照して下さい。

MediaPlayerクラスを使うとBGMの再生を行うことが可能です。また動画再生なども行えるようです。動画再生については、そのうち別記事にしたいと思います。

MediaPlayerの使い方については、以下の記事などが参考となりました。ありがとうございます。

MediaPlayerはオートマトンのような状態遷移を持っており、状態に応じた適切な命令を利用しないと例外を発生します。

以下は 公式サイト にある状態遷移図の抜粋です。

 

状態名 遷移命令 説明
Idle new
reset
new で MediaPlayerを生成した直後の状態です。resetメソッド実行時も、この状態に遷移します。MediaPlayer.create でオブジェクトを生成した場合は、生成が完了すると、Initialized 状態を飛ばして Prepared 状態に遷移します。
Initialized setDataSource 再生する音楽データを割り当てた状態です。ただし、まだデータの読み込みは行われていません。
Prepared prepare
create
再生する音楽データを読み込んだ状態です。再生可能な状態という事ですね。 prepare は同期読み込みのため、大きなサイズの音楽データは処理に時間がかかります。そのようなデータを扱うなら、非同期読み込み命令(prepareAsync)を利用した方が良いでしょう。
Preparing prepareAsync 再生する音楽データを読み込み中の状態です。Initialized状態から非同期読み込み命令(prepareAsync)を利用した場合、この状態になります。prepareAsyncを実行する前に setOnPreparedListener でリスナーを登録しておくと、データの読み込み完了を検知可能です。非同期読み込みを行う場合は、リスナー登録は必須ですね。
Started start 音楽再生中です。再生する前に setCompletionListener でリスナーを登録しておくと、再生完了を検知可能です。再生中か否かは isPlaying メソッドを利用することでも知ることが出来ます。
Paused pause 再生中断状態です。start で演奏している途中で pause メソッドを実行すると、この状態になります。この状態から再度 start メソッドを実行すれば、曲の再生を再開します。
Stopped stop 再生停止状態です。prepare、start または pause 状態から stop メソッドを実行すると、この状態になります。この状態から再度演奏を開始するには prepare または  prepareAsync を実行し、曲データを読み直す必要があります。
PlaybackCompleted なし(再生終了) ループ(繰り返し)再生中ではなく、かつ setCompletionListener で再生完了を検知するリスナーを登録していた場合、曲の演奏が終わるとこの状態になります。この状態から再度 start
メソッドを利用すると、曲の頭から再生が始まります。
End release オブジェクトの利用が終了した状態です。これ以上なにもできません。MediaPlayerは、アプリケーション終了時に必ず release して、この状態にする必要があります。
Error なし(予期せぬタイミング) OnErrorListenerを定義していた場合、エラーを検知するとこの状態になります。

状態遷移が複雑で、かつアプリケーション側で状態を管理する必要がある所が面倒くさいのですが、シンプルに使うだけなら意外とお手軽です。

MediaPlayerには2種類のオブジェクト生成方法が提供されています。

new で素直に生成する方法と、create メソッドで生成する方法です。create で生成した方が1つ手順が省けるので楽ですが、指定した音楽ファイルを必ず同期読み込みするようなので、大きなファイルを扱う場合は注意が必要です。

 

【詳細】

オブジェクト生成

コンストラクタで生成するMediaPlayer mp = new MediaPlayer( ) ;

mp : MediaPlayer インスタンス

MediaPlayerを生成します。new で生成した場合は、Idle 状態になります。

 

create 命令で生成するMediaPlayer mp = MediaPlayer . create( Context context, int resid ) ;

mp : MediaPlayer インスタンス
context : コンテキスト
resid : 音楽ファイルのリソースID

インスタンス生成時に音楽ファイルを指定することが可能です。ceate メソッドで生成すると、指定ファイルが割り当てられて読み込まれ Prepared 状態になります。

 

音楽データ割当

音楽データ割当(同期)void mp . setDataSource ( String path ) ;
void mp . setDataSource ( FileDescriptor fd, long offset, long length ) ;
void mp . setDataSource ( Context context, Uri uri ) ;

mp : MediaPlayer インスタンス
path : 音楽ファイルへのパス
fd : ファイル識別子
offset : 開始位置
length : ファイルサイズ
context : コンテキスト
uri : 音楽ファイルへのURIパス

音楽ファイルを割り当てます。割当が完了すると Initialized 状態になります。

音楽ファイルが外部ストレージ(SDカードなど)にある場合、Assetsフォルダにある場合、resフォルダのrawにある場合(およびWeb上にある場合)用の命令が上記になります。

以下、それぞれのケースにおける music.ogg という名前の音楽ファイルの割当例を紹介します。

●外部ストレージ(SDカードなど)にある場合の割当例

●Assetsフォルダにある場合の割当例

●resフォルダのrawにある場合の割当例

 

音楽データの読み込み

音楽データ読み込みvoid mp . prepare ( ) ;
void mp . prepareAsync ( ) ;

mp : MediaPlayer インスタンス

prepare は同期読み込み、prepareAsync は非同期読み込みです。両方共、音楽データの読み込みが完了すると Prepared  状態になります。

prepare は大きなサイズの音楽データを読み込むと、処理がブロックされるので注意してください。

prepareAsync は、読み込みが完了する前にプログラムに制御が戻ってきます。読み込み途中は Preparing 状態となります。

ただし、非同期読み込みの場合は読み込みが完了する前に、start や stop などの操作を行ってはいけません。非同期読み込みを利用するなら、リスナーを使って読み込みの完了を確認してから、start や stop などの操作を行って下さい。

 

読み込み完了通知を受け取るvoid mp . setOnPreparedListener ( MediaPlayer.OnPreparedListener listener ) ;

mp : MediaPlayer インスタンス
listener : 読み込み完了受信リスナー

非同期読み込みを開始する前に、読み込み完了リスナーを登録しておくと、音楽データの読み込みが完了した事がわかります。

OnPreparedListener を実装した専用のクラスを作成しても良いのですが、面倒くさいので無名クラスを用いても良いでしょう。

こんな感じです。

なおリスナーの登録は prepareAsync  を行う前に設定する事を推奨します。

prepareAsync  の後でリスナーを登録すると、極端に短い音楽データを読み込んだ場合、リスナーでイベントがキャッチできない(リスナーが動作する前に読み込みが終わる)ケースが考えられるためです。

また MediaPlayer  はBGMや動画の再生などを目的としているため、極端に短い(試した範囲では 0.2秒以下の)音楽データを読み込むと、再生しても音が鳴らない事があります。

短い音(効果音)を鳴らすなら、SoundPool を使いましょう。

 

再生開始

再生開始void mp . start () ;

mp : MediaPlayer インスタンス

再生を開始します。pause(再生中断)している場合は、中断した位置から再生を再開します。

演奏中は Started 状態になります。

 

再生完了を知るvoid mp . setOnCompletionListener ( MediaPlayer.OnCompletionListener listener ) ;
boolean playing = mp . isPlaying () ;

mp : MediaPlayer インスタンス
listener : 再生完了受信リスナー
playing : 再生中ならTrue、それ以外はFalse

再生中か否かは isPlaying メソッドを使って判定可能です。

また演奏を開始する前に、再生完了リスナーを登録しておくと、音楽データの再生が完了した事がわかります。リスナーで再生完了を検知した場合は、状態が PlaybackCompleted になります。

OnCompletionListener を実装した専用のクラスを作成しても良いのですが、面倒くさいので無名クラスを用いても良いでしょう。

こんな感じです。

なおリスナーの登録は start を行う前に設定する事を推奨します。

 

再生位置を知る

曲の長さを得るint len = mp . getDuration();

mp : MediaPlayer インスタンス
len : 曲の長さ(ミリセカンド)

音楽データの長さをミリセカンド単位で知ることが可能です。

曲の長さは Prepared 、Started 、PlaybackCompleted 、Paused 、Stopped のいずれかの状態にある時だけ取得可能です。

 

曲の再生位置を得るint pos = mp . getCurrentPosition();

mp : MediaPlayer インスタンス
pos : 曲の再生位置(ミリセカンド)

音楽データの再生位置をミリセカンド単位で知ることが可能です。再生位置は曲の頭から見た再生時間になります。

曲の再生位置は Prepared 、Started 、PlaybackCompleted 、Paused 、Stopped のいずれかの状態にある時だけ取得可能です。

 

再生速度を変更する

再生速度を変更するPlaybackParams params = new PlaybackParams( ) ;
PlaybackParams p = params . setSpeed( float speed );
void mp . setPlaybackParams(PlaybackParams params );

mp : MediaPlayer インスタンス
params: パラメータインスタンス
speed : 再生速度(0.0f – 20.0f)

音楽データの再生速度を変更します。1.0 ならノーマル速度、0.5なら半分の速度、2.0なら倍速での再生になります。

speed に負の値や大きな値を与えると IllegalArgumentException 例外が発生するので注意してください。試した範囲では 20.0f 程度まではOKなようでした。

speed に 0.0 を与えた場合、pause (一時停止) したのと同意になります。

本命令は Android 6.0 (Marshmallow) 以降でサポートされた命令です。ターゲットOSが 6.0 以前 (Lollipop 以前)の場合は利用できません。

Lollipop 以前のOSでプログラムから再生速度を変更するには、なにやら難しい操作が必要なようで、少なくとも MediaPlayer では実現できないようです(汗)。

 

ボリュームを変更する

ボリュームを変更するvoid mp . setVolume ( float leftVolume, float rightVolume ) ;

mp : MediaPlayer インスタンス
leftVolume : 左音量(0.0 – 1.0)
rightVolume : 右音量(0.0 – 1.0)

左右独立で音量を変更します。1.0 が最大音量、0.0 が無音です。

MediaPlayer の音量は特に指定しない限り、システムのストリーム音量(メディア音量)に同調します。

ただし setVolume() メソッドで音量変更しても、システムのストリーム音量には影響を与えません。

つまりsetVolume() メソッドで音量を変更しても、該当MediaPlayerの音量のみが変更され、他のアプリケーションには影響が及ばないという事です。

またメディア音量以外のストリーム音量を変更しても、MediaPlayerのボリュームには影響しません。

 

再生中断

再生中断void mp . pause ();

mp : MediaPlayer インスタンス

再生を中断します。中断すると Paused 状態になります。

演奏を再開するには start メソッドを実行します。

 

再生終了

再生終了void mp . stop () ;

mp : MediaPlayer インスタンス

再生を終了します。終了すると Stopped 状態になります。

この状態から再度演奏を開始するには prepare または  prepareAsync を実行し、曲データを読み直す必要があります。

 

初期化

初期化void mp . reset () ;

mp : MediaPlayer インスタンス

MediaPlayer オブジェクトを初期化します。初期化すると Idle 状態に戻ります。

本命令の使い所は、なにか問題が発生して最初からやりなおしたい場合と、ある曲が再生完了した後(あるいは再生途中)に、別の曲を再生したい場合となります。

その場合は、一度 reset して setDataSource からやり直す手順となります。

 

リソース開放

リソース開放void mp . release () ;

mp : MediaPlayer インスタンス

MediaPlayer オブジェクトを開放します。開放すると End 状態になります。

アプリケーションが onPause または onStop 状態になったら、release メソッドで資源を開放する事が推奨されています。

PROCESSINGの場合は、フラグメントの onDestroy をオーバライドして、release 処理を記述するのが良いでしょう。

開放されたオブジェクトは再利用できません。再度音楽を演奏するには、new または create から始める事になります。

 

【関連記事】

 


サンプルプログラム

シンプルな音楽再生例:

Dataフォルダの下にある「bgm01.ogg」を読み込んでいます。タップを行うと演奏を始めます。演奏中にタップすると一時停止します。

PROCESSINGの標準エディタでは R クラスを使ってリソースを読み込めないため、シンプルといいつつ、長いコーディングになっています(汗)。

下記にAndroidStudioで同じことを行うサンプルを掲載しておきます。

<出力サンプル>

 

シンプルな音楽再生例2:

上記例と同じことを行うプログラムを、AndroidStudioでコーディングしました。resフォルダの rawに「bgm01.ogg」という音楽データがある前提です。

MediaPlayer  を new するのではなく  create メソッドを使ってリソースフォルダの音楽データを読み込む事で、標準エディタの例に比べてシンプルにコーディングできていると思います。

 

ボリューム操作例:

ボリュームの操作機能付きの超超簡易音楽プレーヤー例です。

画面に表示されるスピーカーの絵のボタンを押下すると、音量が変更可能です。

<出力サンプル>


(画像URL:illust-AC 様:yamaboshiさん)

 

下記はサンプルプログラムと同じ動きになるように、 P5.js で書き直したものです。動作イメージを確認できます。※細かい動作や表示が少しだけ異なりますが・・・そこはご愛嬌で・・(汗)。

音楽ファイルは wingless-seraph 様からお借りしました。かっこいいBGMです。

なお一部のスマホ搭載ブラウザからは正しく表示されない場合があります。その場合はPCから閲覧してください。


(画像URL:illust-AC 様:yamaboshiさん、効果音:wingless-seraph 様)

 


PROCESSING逆引きリファレンス一覧 へ戻る

本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。