AudioTrackを使ってWAVEデータを再生する


あけましておめでとうございます!
2011年もTechBoosterを宜しくお願い致します。

さて、2011年最初のHow To AndroidはAudioTrackを使ってWAVEデータを再生する方法についてご紹介します。

詳細はつづきからどうぞ。

AudioTrackクラスではバイトデータをオーディオハードウェアに直接書き込むことができるので、
MediaPlayerクラスと比べて高速に音を鳴らすことができます。
ゲームやGUIの効果音のような、リアルタイムに音を出したいというような用途に向いています。

コンストラクタ

AudioTrackクラスのコンストラクタは以下のようになっています。

AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode, int sessionId)
streamType ストリームタイプを指定します。
sampleRateInHz サンプルレートを指定します。
channelConfig オーディオチャネルを指定します。
audioFormat オーディオフォーマットを指定します。ENCODING_PCM_16BITとENCODING_PCM_8BITの2つがあります。
bufferSizeInBytes オーディオデータのバッファサイズを指定します。
mode STREAMモードかSTATICモードかいずれかを選択します。詳細は後述します。
sessionId オーディオセッションIDを指定します。

STREAMモードとSTATICモード

AudioTrackクラスは以下の2つのモードで動作します。

  • STREAMモード:
    メモリに収まらない大きな音声データを再生したい場合、音声データを一定量ずつ、逐一ハードウェアに出力します。
  • STATICモード:
    メモリに収まる程度の小さな音声データは予めメモり領域上に置いておいて、それを必要なときにハードウェアに出力します。

サンプルコード

以下はAudioTrackクラスを使ってSDカードに保存してあるWAVEファイルを鳴らすサンプルです。
WAVEファイルはサンプリングレート44100Hz、オーディオチャネル2ch、16bitのものを使っています。
大きなバイトデータになりますので、STREAMモードを使います。

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	// ボタンのインスタンスを作成
	play_button = (Button) findViewById(R.id.Button01);
	stop_button = (Button) findViewById(R.id.Button02);

	// WAVEファイルのFileインスタンスを作成
	file = new File("/sdcard/strings.wav");

	// WAVEファイルのサイズを取得
	byteData = new byte[(int) file.length()];

	// WAVEファイルをロード
	FileInputStream in = null;
	try {
		in = new FileInputStream(file);
		in.read(byteData);
		in.close();
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}

	// 再生用初期化処理
	initialize();

	// プレイボタン
	play_button.setOnClickListener(new OnClickListener() {
		public void onClick(View v) {
			// 再生用スレッドを起こす
			play_thread.start();
		}
	});

	// ストップボタン
	stop_button.setOnClickListener(new OnClickListener() {
		public void onClick(View v) {
			// 再生中なら停止させる
			if (myAT.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
				myAT.stop();
				play_thread = null;
				initialize();
			}
		}
	});
}

// 再生用初期化処理
void initialize() {
	// 必要となるバッファサイズを計算
	bufSize = android.media.AudioTrack.getMinBufferSize(44100,
			AudioFormat.CHANNEL_CONFIGURATION_MONO,
			AudioFormat.ENCODING_PCM_16BIT);

	// AudioTrackインスタンス作成
	myAT = new AudioTrack(AudioManager.STREAM_MUSIC,
			44100, AudioFormat.CHANNEL_CONFIGURATION_MONO,
			AudioFormat.ENCODING_PCM_16BIT, bufSize,
			AudioTrack.MODE_STREAM);

	// スレッドインスタンス作成
	play_thread = new Thread(this);
}

// 再生用スレッド処理
public void run() {
	if (myAT != null) {
		// 再生開始
		myAT.play();
		myAT.write(byteData, 0, byteData.length);
	}
}

処理としては、SDカードに保存しているWAVEファイル用のFileインスタンスを作成し、WAVEファイルのバイトデータをFileInputStreamにロードします(10-26行目)
バイトデータをロードしたらAudioTrackインスタンスの初期化処理を行います(29行目, 52-67行目)。
ここで、WAVEファイルのサンプリングレートなどの情報をもとに必要なバッファサイズを計算し、AudioTrackインスタンスを作成します。
あとはボタンが押されたら再生を開始させます(35行目, 69-76行目)。
writeメソッドはバイトデータの書き込みが終わるまでブロックしてしまうのでスレッドで実行するようにしています。