wavなどの短い音データなどをandroidで再生させる場合にAudioTrackを使うと素早くできます。ゲームのワンフレーズ等に使えるでしょう。
2024.1.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 |
package com.example.testaudiotrack; 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 androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import java.io.InputStream; import java.util.Locale; public class MainActivity extends AppCompatActivity { // hello_world.wav のサンプリングレート private static final int SamplingRate = 32000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); // ボタンを設定 Button button = findViewById(R.id.button); // リスナーをボタンに登録 // expression lambda button.setOnClickListener(v-> wavPlay()); } private void wavPlay() { byte[] wavData; try (InputStream input = getResources().openRawResource(R.raw.how_are_you) ){ // wavを読み込む 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); }catch(Exception e){ throw new RuntimeException(e); } // バッファサイズの計算 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 27 28 29 30 31 32 33 34 35 36 37 38 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main" 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" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> --> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="40dp" android:text="@string/button" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.8" /> </androidx.constraintlayout.widget.ConstraintLayout> |
strings.xml
1 2 3 4 5 |
<resources> <string name="app_name">TestAudioTrack</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