wavなどの短い音データなどをandroidで再生させる場合にAudioTrackを使うと素早くできます。ゲームのワンフレーズ等に使えるでしょう。
2021.2.1
AudioTrack
API level 26から以下のAPIは非推奨になりました。
1 2 |
AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) |
代わりは
1 2 3 |
AudioTrack.Builder or AudioTrack(AudioAttributes, AudioFormat, int, int, int) |
とのことです
AudioTrack
AudioTrack.Builder
AudioTrack.Builder を使ってみたいと思います。AudioTrack.Builderにサンプルがありますから、それをそのまま使いましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
AudioTrack player = new AudioTrack.Builder() .setAudioAttributes(new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_ALARM) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build()) .setAudioFormat(new AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_16BIT) .setSampleRate(44100) .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) .build()) .setBufferSizeInBytes(minBuffSize) .build(); |
そのままといっても、音源に合わせて設定しないといけませんが
AudioAttributes
最初にrawフォルダをres以下に作成します。適当なwavファイルをその res/raw/ 以下に置きます。多くの音声ファイルをフォルダ階層で管理したい場合はassetsに置きます。
ここでは、how_are_you というwavファイルを使ってみます。
AudioAttributes からAudioAttributesを選定します。
- AudioAttribute:音源は音声なのでこれらを設定
- setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
- setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
- AudioFormat:これらは音源ファイルを調べればわかります
- setEncoding(AudioFormat.ENCODING_PCM_16BIT)
- setSampleRate(SamplingRate)
- setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
- ステレオ/モノラルの設定
sampling rate
サンプリングレートを調べるには、windowsなどのエクスプローラーでこの音声ファイルのプロパティを見ます。ビットレートが512kbpsであることが分かり、PCMは16bitなので、
512000bps/16bps = 32000 がサンプリングレートとなります。
Macの場合はファイルの情報を見ます。
サンプルコード
以上を踏まえて簡単なテストコードを書いてみました。
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
//package your.package.name; import android.app.Activity; import android.media.AudioAttributes; import android.media.AudioFormat; import android.media.AudioTrack; import android.os.Bundle; import android.util.Log; import android.widget.Button; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Locale; public class MainActivity extends Activity { // hello_world.wav のサンプリングレート private static final int SamplingRate = 32000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ボタンを設定 Button button = findViewById(R.id.button); // リスナーをボタンに登録 // expression lambda button.setOnClickListener(v-> wavPlay()); } private void wavPlay() { InputStream input = null; byte[] wavData = null; try { // wavを読み込む input = getResources().openRawResource(R.raw.audio_sample); wavData = new byte[input.available()]; // input.read(wavData) String readBytes = String.format( Locale.US, "read bytes = %d",input.read(wavData)); // input.read(wavData)のwarning回避のためだけ Log.d("debug",readBytes); input.close(); } catch (FileNotFoundException fne) { fne.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); Log.d("debug", "error"); } finally{ try{ if(input != null) input.close(); }catch(Exception e){ e.printStackTrace(); } } // バッファサイズの計算 int bufSize = android.media.AudioTrack.getMinBufferSize( SamplingRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); // AudioTrack.Builder API level 26より AudioTrack audioTrack = new AudioTrack.Builder() .setAudioAttributes(new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .build()) .setAudioFormat(new AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_16BIT) .setSampleRate(SamplingRate) .setChannelMask(AudioFormat.CHANNEL_OUT_MONO) .build()) .setBufferSizeInBytes(bufSize) .build(); // 再生 audioTrack.play(); //audioTrack.write(wavData, 0, wavData.length); // ヘッダ44byteをオミット assert wavData != null; audioTrack.write(wavData, 44, wavData.length-44); } } |
レイアウト、画像は特に必要ないですが気分です
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <!-- 画像はなくても大丈夫です --> <ImageView android:src="@drawable/img" android:scaleType="centerCrop" android:contentDescription="@string/description" android:layout_width="match_parent" android:layout_height="match_parent" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="70dp" android:layout_margin="40dp" android:layout_alignParentBottom="true" android:textSize="20sp" android:background="#fa8" android:text="@string/button" /> </RelativeLayout> |
strings.xml
1 2 3 4 5 |
<resources> <string name="app_name">YourAppName</string> <string name="button">Audio Play</string> <string name="description">Jenifier</string> </resources> |
サンプル動画
audioTrack.write(wavData, 44, wavData.length-44);
としているのは、wavファイルのヘッダ部分が44byteあるので、それがノイズ、プチッ音になるのを回避するためです。
それと注意しないといけないのが、このまま使うと他の処理、画面が止まったりします。それが都合が悪い場合はThreadを使って非同期にするなど対応が必要です。
- 関連ページ
- 簡単なMediaPlayerで音楽を再生
- WAV音声ファイルをAudioTrackで再生
- SoundPoolで効果音を鳴らす
Reference:
AudioTrack