Androidサンプル - 音を鳴らす
AudioTrackクラスを使って正弦波を鳴らしてみます(Android SDK 2.2で作成)。手順は以下の通りです。
オーディオバッファを作成する
short buffer[] = null; buffer = new short[ SAMPLES * CHANNEL ]; buffer = generateBuffer(); // 信号を生成する関数
正弦波を生成する式です。
a:振幅、t:時刻、f:周波数、fsサンプル周波数、i:現在のサンプル、N:全サンプル数→周期ごとに元の位相に戻す方がよい
signal = amplification * Math.sin(2.0 * Math.PI * frequency * t);
インスタンスを生成する
各引数は以下の通りです。
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, // AudioMangerのモード SAMPLERATE, //サンプル周波数[Hz] AudioFormat.CHANNEL_CONFIGURATION_MONO, // チャネル数 AudioFormat.ENCODING_PCM_16BIT, //ビットレート[bit] bufferSizeInBytes, //バッファサイズ[byte] AudioTrack.MODE_STATIC); // AudioTrackの再生モード
AudioTrackの再生モードにはMODE_STATICとMODE_STREAMの2種類あって処理の流れが異なるので注意してください。
バッファを書き込む
writeメソッドを使います。
audioTrack.write(buffer, offset, buffeSize);
バッファを再読み込みする
一旦停止してから再度再生する前にもう一度バッファを読み込む必要があるようです。なので再生前にreloadStaticDataを実行しておきます。
再生する
playメソッドで再生します。現在の再生状態を取得するにはgetPlayStateを使います。
停止する
stopメソッドで停止します。
バッファを解放する
アプリが終了するときに、バッファを解放しないといけないのでreleaseを呼んでおきます。
以上が大まかな流れになります。
タッチダウンで再生、タッチアップで停止します。
AudioTestActivity.java
public class AudioTestActivity extends Activity { private static final String TAG = "AudioActivity"; private AudioTrack audioTrack = null; protected short[] buffer = null; protected int SAMPLERATE = 44100; // [Hz] protected static final int CHANNEL = 1; // 1:MONO, 2:STEREO protected static final int BITRATE = 16; // [bit/sec] // signal funcion params static private double amplification = 0.5; // [0.0, 1.0] static private double frequency = 720; // [Hz] static private double duration = 1.0; // [sec] @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); generateBuffer(); int bufferSizeInBytes = buffer.length * CHANNEL * BITRATE / 8; // cf // Log.v(TAG, "length:" + buffer.length); // Log.v(TAG, "bufferSize:" + bufferSizeInBytes); // create AudioTrack instance audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLERATE, //[Hz] AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, //[bit] bufferSizeInBytes, //[byte] AudioTrack.MODE_STATIC); // write buffer audioTrack.write(buffer, 0, buffer.length); } @Override public void onStart() { super.onStart(); } @Override public void onStop() { if(buffer != null){ buffer = null; } if(audioTrack != null){ audioTrack.stop(); audioTrack.release(); // release buffer audioTrack = null; } super.onStop(); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if(audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING){ audioTrack.stop(); audioTrack.reloadStaticData(); audioTrack.play(); } break; case MotionEvent.ACTION_UP: if(audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING){ audioTrack.stop(); } break; } return true; } public void generateBuffer(){ int SAMPLES = (int) (duration * SAMPLERATE); buffer = new short[ SAMPLES * CHANNEL ]; double signal = 0; for (int i = 0; i < SAMPLES; i++) { signal = generateSignal(i); buffer[i] = (short)( signal * Short.MAX_VALUE ); } } public double generateSignal(int sample){ double t = (double)(sample) / SAMPLERATE; // y = a * sin (2PI * f * t), t = i/fs, 0 <= i < TotalSamples return amplification * Math.sin(2.0 * Math.PI * frequency * t); } }