音を扱うクラスとしてSoundPoolがあり、比較的短いものを遅延が少なく再生できるのでゲームの効果音の再生などに向いています。
 
下はAnimationとsound再生を同時に行った例です。
 
![[Android & Kotlin] SoundPool で効果音を鳴らす 1x1.trans - [Android & Kotlin] SoundPool で効果音を鳴らす](https://akira-watson.com/wp-content/themes/simplicity2/images/1x1.trans.gif)
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以降使い方が変わりました。
- val audioAttributes = AudioAttributes.Builder()…
 - val soundPool = 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」「Directory」
![[Android & Kotlin] SoundPool で効果音を鳴らす 1x1.trans - [Android & Kotlin] SoundPool で効果音を鳴らす](https://akira-watson.com/wp-content/themes/simplicity2/images/1x1.trans.gif)
res以下にできたディレクトリーにwavファイルを入れます。参考までに以下wavファイルを名前をつけて保存できます。
one two
![[Android & Kotlin] SoundPool で効果音を鳴らす 1x1.trans - [Android & Kotlin] SoundPool で効果音を鳴らす](https://akira-watson.com/wp-content/themes/simplicity2/images/1x1.trans.gif)
多くの音声ファイルをフォルダ階層で管理したい場合はassetsに置きます。ただし、assetsからのデータ取得はAssetManagerを使う作業が必要です。
サンプルコード
MainActivity.kt
| 
					 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 92 93 94 95 96  | 
						//package com.example.kotlinsoundpool 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.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat class MainActivity : AppCompatActivity() {     private lateinit var soundPool: SoundPool     private var soundOne = 0     private var soundTwo = 0     private lateinit var button1: Button     private lateinit var button2: Button     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         enableEdgeToEdge()         setContentView(R.layout.activity_main)         ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->             val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())             v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)             insets         }         val audioAttributes = AudioAttributes.Builder() // USAGE_MEDIA             // USAGE_GAME             .setUsage(AudioAttributes.USAGE_GAME) // CONTENT_TYPE_MUSIC             // CONTENT_TYPE_SPEECH, etc.             .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)             .build()         soundPool = 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.0f)             val bw1: Float = button1.getWidth().toFloat()             val bh1: Float = button1.getHeight().toFloat()             // ボタンの回転アニメーション             val buttonRotation = RotateAnimation(                 0f,                 360f,                 bw1 / 2.0f,                bh1 / 2.0f             )             buttonRotation.duration = 2000             button1.startAnimation(buttonRotation)         }         button2.setOnClickListener { v ->             // two.wav の再生             soundPool.play(soundTwo, 1.0f, 1.0f, 1, 0, 1.0f)             val bw2: Float = button2.getWidth().toFloat()             val bh2: Float = button2.getHeight().toFloat()             // ボタンの回転アニメーション             val buttonRotation = RotateAnimation(                 0f,                 360f,                 bw2 / 2.0f,                 bh2 / 2.0f             )             buttonRotation.duration = 2000             button2.startAnimation(buttonRotation)         }     } }  | 
					
 
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">KotlinSoundPool</string>     <string name="one">One</string>     <string name="two">Two</string> </resources>  | 
					
 
ついでに、ボタンを押してSoundPoolで音を再生し、ボタンを回転させてみました。
References:
SoundPool
AudioAttributes