コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

AudioTrackで音を鳴らす

Luaridaのユーザさんから、Beep音が欲しいという要望がありました。おぉぉ、Beep音、これは懐かしい。BASICなどで、ピーとなる音です。
これは作るしかないということで、Androidでピーって鳴らすプログラムを作ってみました。エイヤッとBeepCommandクラスを作りました。中身は、sin波を使ってwave波形データを作り、配列に入れてAudioTrackに渡すというものです。いろいろと参考になるサイトがたくさんありまして、それほど苦労せずに作ることができました。
修正版を次のブログに書きました。

BeepCommand

Beep音の周波数は最大10kHzとしました。そこで、サンプリング周波数は20kHz固定にしました。また、Beep音なので量子化ビットは8ビットとし、繰り返し鳴らすことも考えないことにしました。
引数には、鳴らす時間(sec)と周波数(Hz)が取れるようにしました。そして、stop()したら必ずリリースします。

public class BeepCommand {
  private static double prRegion = 0.5;         //振幅の幅 -0.5 から 0.5
  private byte[] prSoundData = null;            //波形データ
  private static int prSampleRate = 20000;      // サンプリング周波数20kHz
  private AudioTrack prAudioTrack = null;

  public void start(float sec, float hz){
    //**** sin波形を生成 ****
    int dsu = (int)( (long)(sec*1000.0f)*5000L/250L);
    prSoundData = new byte[dsu];
    for (int i = 0; i < dsu; i++) {
      double d = prRegion * Math.sin(2.0 * Math.PI * hz*sec * i /dsu);
      prSoundData[i] = (byte)(d * 127.0);
    }
    //***********************

    if( prAudioTrack!=null ){ prAudioTrack.release();	}
    prAudioTrack = new AudioTrack(
            AudioManager.STREAM_MUSIC,
            prSampleRate,                             //サンプリング周波数
            AudioFormat.CHANNEL_CONFIGURATION_MONO,   //モノラル
            AudioFormat.ENCODING_PCM_8BIT,            //量子化ビット8ビット
            prSoundData.length,                       //データ長
            AudioTrack.MODE_STATIC
        );

    prAudioTrack.setPlaybackPositionUpdateListener(
            new AudioTrack.OnPlaybackPositionUpdateListener() {
                public void onPeriodicNotification(AudioTrack track) {
                }
                // 再生完了時のコールバック
                public void onMarkerReached(AudioTrack track) {
                  if(track.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){
                    track.stop();// 再生完了したので発声停止
                  }
                }
            }
        );

    prAudioTrack.reloadStaticData();   //stop()後に再び再生するときに必要
    prAudioTrack.write(prSoundData, 0, prSoundData.length);  //再生するデータをセット
    prAudioTrack.setNotificationMarkerPosition(prSoundData.length);  //コールバックタイミング指定
    prAudioTrack.play();
  }

  public void stop(){
    if( prAudioTrack!=null ){
      if(prAudioTrack.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){
        prAudioTrack.stop();// 発声中なら停止
      }
      prAudioTrack.release();
    }
  }
}

Beep音なので、これで多めに見てもらうということで、Luaridaの次のバージョンに入れたいと思います。