2011年12月24日

Android/Java Mediaplayer と SoundPool


本日先ほど学校の合宿から帰ってきました。
ちょっとAndroidの話だけどJavaもかぶるので、Java Advent Calendar 2011のネタにします。26日約束だったのにネットが使えなかったので27日になってしまいました!(Oh!my god.)どうもすいません。
学生の卒業研究でAndroidでドラム作成の相談をされた時の事を少しお話。
通常、音楽はMdiaPlayerクラスを扱うのですが、例えば10個のドラムを画面に配置して、クリックされたときにその位置に対応するドラムの音をならせばよい。
つまりこんな感じ。。。
public class drumSound extends Activity {
private MediaPlayer mp[10];
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this.getApplicationContext();
//–
for (10個分のドラムサウンドファイルをクリエイトする) {
mp[i] = MediaPlayer.create(this, R.raw.music01);
mp[i].prepare();
・・・・・
}
@Override
public boolean onMotionEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = getX(int);
int y = getY(int);
if (1つ目のドラム位置だったら) {
try{
mp[i].start();
}catch( Exception e ){
Log.d(“Err”, “err mpPlay : ” +path );
}
}else if (2つ目の・・・・
ただし、メモリにゴミを残さない様にdestoryメソッドをオーバーライドしておかないといけない。
最初のコードの例だと、多重再生ができなく1回目の再生終了後にしか次のドラムの音が鳴らない。
したがって、ここはSoundPoolクラスを使って下記のように多重再生できるようにする。
public class drumSound extends Activity {
private SoundPool sdPool;
private int sdIds[10];
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this.getApplicationContext();
sdPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
for (int i=0; i<10; i++) {
sdIds[i] = sdPool.load(context, soundResouces[i], 1);
}
@Override
public boolean onMotionEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = getX(int);
int y = getY(int);
if (1つ目のドラム位置だったら) {
sdPool.play( sdIds[0], 1.0F, 1.0F, 0, 0, 1.0F);
でも、よーく考えたら違う位置のドラムは良いが同じドラムなら前に鳴らしていた音はほぼ消されないとハウリングのような音の具合になるので、sdPool.play()の直前に下記を追加して一度ストップさせてから再生すると良い。
sdPool.stop(sdIds[0]);
ドラムの場合は、短い再生音なので良いがデフォルトで再生時数秒のリソースが限界のようだ、もっと長い音を多重で再生するには先のMediaPlayerのインスタンスをスレッドを使って明示的に再生することになる。
例えば、ある程度の長さのメロディーを割り当てた鍵盤楽器があってそれを制御するには次のようなコードになるはず。
private Thread thread[10];
………….
@Override
public boolean onMotionEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = getX(int);
int y = getY(int);
if (1つ目のミュージック鍵盤位置だったら) {
if (thread[0]) {
mp[0].stop();
}
thread[0] = new Thread(newRunnable(H
public void run(){
mp[0].play();
while (mp[0].isPlaying()) {
sleep(50); //50ms毎にチェック。
}
}
thread.start();

0 件のコメント:

コメントを投稿