音を扱うクラスとしてSoundPoolがあり、比較的短いものを遅延が少なく再生できるのでゲームの効果音の再生などに向いています。
下はAnimationとsound再生を同時に行った例です。
2024.1.1
SoundPool
Audioの再生にはこのSoundPool以外にもMediaPlayerやAudioTrackがあります。
- SoundPool
- 再生可能なフォーマット:mp3, ogg, wav(非圧縮), etc.
- Audio Mixerのように複数の音源を重ねて再生できる
- 事前にデコードしてメモリに展開するので低レイテンシー
- 再生できるのは5秒程度
- 繰り返し再生
- 再生スピードを可変できる
- それぞれの音源に優先度をつけられる
- ゲームの効果音再生に適している
- MediaPlayer
- Supported media formatsおそらくこれらをサポート
- BGMとしてあるいは楽曲の再生用途で使う
- AudioTrack
- メモリに直接展開して再生するので低レイテンシー
- 細かい操作ができる(してあげないといけない)
SoundPool の設定
SoundPoolはLollipop以降使い方が変わりました。
- AudioAttributes audioAttributes = new AudioAttributes.Builder(…)
- SoundPool soundPool = new SoundPool.Builder()…
- soundPool.load(…)
- soundPool.play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
- soundID: load()で決めたID
- leftVolume, rightVolume: 左音量, 右音量(range = 0.0 to 1.0)
- priority: (0 = lowest priority) default 0
- loop: (0 = no loop, -1 = loop forever)
- rate: (1.0 = normal playback, range 0.5 to 2.0)
SoundPoolは、事前に音源をロードしておく必要があります。いきなりロード再生ではうまくいきません。そのためアプリとして音源を抱えたままになりかねないため、release, unload等を使ってOut Of memoryに陥らない対策が必要です。
SoundPool、AudioAttributes
wavファイルを res/raw/ 以下に置きます。
「res」から
「New」「Folder」「Raw Resources Folder」
でフォルダーを作成
rawフォルダーにwavファイルを入れます。参考までに以下wavファイルを名前をつけて保存できます。
one two
多くの音声ファイルをフォルダ階層で管理したい場合はassetsに置きます。ただし、assetsからのデータ取得はAssetManagerを使う作業が必要です。簡単なMediaPlayerで音楽を再生
サンプルコード
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 |
//package com.example.testsoundpool; import android.media.AudioAttributes; import android.media.SoundPool; import android.os.Bundle; import android.util.Log; import android.view.animation.RotateAnimation; 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; public class MainActivity extends AppCompatActivity { private SoundPool soundPool; private int soundOne, soundTwo; private Button button1, button2; @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; }); AudioAttributes audioAttributes = new AudioAttributes.Builder() // USAGE_MEDIA // USAGE_GAME .setUsage(AudioAttributes.USAGE_GAME) // CONTENT_TYPE_MUSIC // CONTENT_TYPE_SPEECH, etc. .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .build(); soundPool = new SoundPool.Builder() .setAudioAttributes(audioAttributes) // ストリーム数に応じて .setMaxStreams(2) .build(); // one.wav をロードしておく soundOne = soundPool.load(this, R.raw.one, 1); // two.wav をロードしておく soundTwo = soundPool.load(this, R.raw.two, 1); // load が終わったか確認する場合 soundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> { Log.d("debug","sampleId="+sampleId); Log.d("debug","status="+status); }); button1 = findViewById(R.id.button1); button2 = findViewById(R.id.button2); button1.setOnClickListener( v -> { // one.wav の再生 // play(ロードしたID, 左音量, 右音量, 優先度, ループ,再生速度) soundPool.play(soundOne, 1.0f, 1.0f, 0, 0, 1); // ボタンの回転アニメーション RotateAnimation buttonRotation = new RotateAnimation( 0, 360, (float)(button1.getWidth()/2), (float)(button1.getHeight()/2)); buttonRotation.setDuration(2000); button1.startAnimation(buttonRotation); }); button2.setOnClickListener( v -> { // two.wav の再生 soundPool.play(soundTwo, 1.0f, 1.0f, 1, 0, 1); // ボタンの回転アニメーション RotateAnimation buttonRotation = new RotateAnimation( 0, 360, (float)(button2.getWidth()/2), (float)(button2.getHeight()/2)); buttonRotation.setDuration(2000); button2.startAnimation(buttonRotation); }); } } |
activity_main.xmlなどは以下にあります
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 39 |
<?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"> <Button android:id="@+id/button1" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_margin="40dp" android:text="@string/one" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.35" /> <Button android:id="@+id/button2" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_margin="40dp" android:text="@string/two" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.573" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.65" /> </androidx.constraintlayout.widget.ConstraintLayout> |
strings.xml
1 2 3 4 5 |
<resources> <string name="app_name">TestSoundPool</string> <string name="one">One</string> <string name="two">Two</string> </resources> |
ついでに、ボタンを押してSoundPoolで音を再生し、ボタンを回転させてみました。
- 関連ページ
- 簡単なMediaPlayerで音楽を再生
- WAV音声ファイルをAudioTrackで再生
- SoundPoolで効果音を鳴らす
References:
SoundPool
AudioAttributes