Androidサンプル - 音を鳴らす

AudioTrackクラスを使って正弦波を鳴らしてみます(Android SDK 2.2で作成)。手順は以下の通りです。

オーディオバッファを作成する
short buffer[] = null;
buffer = new short[ SAMPLES * CHANNEL ];
buffer = generateBuffer(); // 信号を生成する関数

正弦波を生成する式です。
a:振幅、t:時刻、f:周波数、fsサンプル周波数、i:現在のサンプル、N:全サンプル数→周期ごとに元の位相に戻す方がよい
y = a  sin (2\pi  f  t) , t = i/f_s , 0 \leq < 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);
    }
}