Phát hiệu ứng âm thanh trong Android với SoundPool
Xem thêm các chuyên mục:

Là một website được viết trên công nghệ web Flutter vì vậy hỗ trợ rất tốt cho người học, kể cả những người học khó tính nhất.
Hiện tại website đang tiếp tục được cập nhập nội dung cho phong phú và đầy đủ hơn. Mong các bạn nghé thăm và ủng hộ website mới của chúng tôi.


Trước hết tôi đặt ra một tình huống, bạn đang tạo một trò chơi, nó phát ra các âm thanh chẳng hạn như tiếng súng, tiếng bom, đó là các hiệu ứng âm thanh trong trò chơi. Android cung cấp cho bạn lớp SoundPool, nó giống như một bể chứa các nguồn nhạc và sẵn sàng phát ra khi có yêu cầu.
SoundPool chứa một tập hợp các nguồn nhạc, nguồn âm có thể từ file nhạc trong ứng dụng hoặc trong file hệ thống,.. SoundPool hỗ trợ phát đồng loạt nhiều nguồn nhạc cùng một lúc.
SourcePool sử dụng MediaPlayer service để phát ra âm thanh.
SoundPool chứa một tập hợp các nguồn nhạc, nguồn âm có thể từ file nhạc trong ứng dụng hoặc trong file hệ thống,.. SoundPool hỗ trợ phát đồng loạt nhiều nguồn nhạc cùng một lúc.
SourcePool sử dụng MediaPlayer service để phát ra âm thanh.

Bạn có thể chỉ định để SoundPool phát ra âm thanh tại stream (luồng) cụ thể. Có một số kiểu stream sau:
Loại luồng âm thanh | Mô tả |
AudioManager.STREAM_ALARM | Các dòng âm thanh cho báo động |
AudioManager.STREAM DTMF | Các dòng âm thanh cho DTMF |
AudioManager.STREAM_MUSIC | Các dòng âm thanh để phát lại âm nhạc |
AudioManager.STREAM_NOTIFICATION | Các dòng âm thanh cho thông báo |
AudioManager.STREAM_RING | Các dòng âm thanh cho điện thoại reo |
AudioManager.STREAM_SYSTEM | Các dòng âm thanh cho âm thanh hệ thống |
AudioManager.STREAM_VOICE_CALL | Các dòng âm thanh cho các cuộc gọi điện thoại |
AudioManager cho phép bạn điều chỉnh âm lượng trên các luồng (stream) âm thanh khác nhau. Chẳng hạn bạn đang nghe nhạc bài hát trên thiết bị đồng thời chơi Game, bạn có thể thay đổi âm lượng của Game mà không ảnh hưởng tới âm lượng của bài hát.
Một vấn đề khác được đề cập là thiết bị âm thanh sẽ phát ra âm thanh.
Sử dụng STREAM_MUSIC âm thanh sẽ được phát ra thông qua một thiết bị âm thanh (loa điện thoại, tai nghe, bluetooth loa hay cái gì khác) kết nối với điện thoại.
Sử dụng STREAM_RING âm thanh sẽ được phát ra thông qua tất cả các thiết bị âm thanh kết nối với điện thoại. Hành vi này có thể khác nhau đối với mỗi thiết bị.
Sử dụng STREAM_MUSIC âm thanh sẽ được phát ra thông qua một thiết bị âm thanh (loa điện thoại, tai nghe, bluetooth loa hay cái gì khác) kết nối với điện thoại.
Sử dụng STREAM_RING âm thanh sẽ được phát ra thông qua tất cả các thiết bị âm thanh kết nối với điện thoại. Hành vi này có thể khác nhau đối với mỗi thiết bị.
SoundPool API:
Phương thức | Mô tả |
int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) |
Phát một nguồn nhạc, mà trả về một số là ID của luồng âm đang phát (streamID). |
void pause(int streamID) | Tạm dừng luồng âm đang phát có ID là streamID. |
void stop(int streamID) | Ngừng luồng âm ứng với streamID. |
void setVolume(int streamID, float leftVolume, float rightVolume) | Sét đặt âm lượng cho luồng âm với ID là streamID |
void setLoop(int streamID, int loop) | Sét đặt số lần phát lại luồng âm với ID là streamID. |
Tạo mới một project SoundPoolDemo.
- Name: SoundPoolDemo
- Package name: org.o7planning.soundpooldemo


Tạo thư mục raw là con của thư mục res. Copy 2 file nhạc vào thư mục raw, ở đây tôi copy 2 file mô phỏng âm thanh vật thể bị phá hủy (destroy.wav) và âm thanh của tiếng súng (gun.wav). Chú ý bạn có thể sử dụng file nhạc đuôi mp3 hoặc wav.



Giao diện ứng dụng Demo.

activity_main.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_destroy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginLeft="32dp"
android:layout_marginTop="50dp"
android:text="Destroy"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_gun"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="50dp"
android:text="Gun"
app:layout_constraintStart_toEndOf="@+id/button_destroy"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package org.o7planning.soundpooldemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private SoundPool soundPool;
private AudioManager audioManager;
private Button buttonDestroy;
private Button buttonGun;
// Maximumn sound stream.
private static final int MAX_STREAMS = 5;
// Stream type.
private static final int streamType = AudioManager.STREAM_MUSIC;
private boolean loaded;
private int soundIdDestroy;
private int soundIdGun;
private float volume;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.buttonDestroy = (Button) this.findViewById(R.id.button_destroy);
this.buttonGun = (Button) this.findViewById(R.id.button_gun);
this.buttonDestroy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playSoundDestroy();
}
});
this.buttonGun.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playSoundGun();
}
});
// AudioManager audio settings for adjusting the volume
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
// Current volumn Index of particular stream type.
float currentVolumeIndex = (float) audioManager.getStreamVolume(streamType);
// Get the maximum volume index for a particular stream type.
float maxVolumeIndex = (float) audioManager.getStreamMaxVolume(streamType);
// Volumn (0 --> 1)
this.volume = currentVolumeIndex / maxVolumeIndex;
// Suggests an audio stream whose volume should be changed by
// the hardware volume controls.
this.setVolumeControlStream(streamType);
// For Android SDK >= 21
if (Build.VERSION.SDK_INT >= 21 ) {
AudioAttributes audioAttrib = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
SoundPool.Builder builder= new SoundPool.Builder();
builder.setAudioAttributes(audioAttrib).setMaxStreams(MAX_STREAMS);
this.soundPool = builder.build();
}
// for Android SDK < 21
else {
// SoundPool(int maxStreams, int streamType, int srcQuality)
this.soundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, 0);
}
// When Sound Pool load complete.
this.soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
loaded = true;
}
});
// Load sound file (destroy.wav) into SoundPool.
this.soundIdDestroy = this.soundPool.load(this, R.raw.destroy,1);
// Load sound file (gun.wav) into SoundPool.
this.soundIdGun = this.soundPool.load(this, R.raw.gun,1);
}
// When users click on the button "Gun"
public void playSoundGun( ) {
if(loaded) {
float leftVolumn = volume;
float rightVolumn = volume;
// Play sound of gunfire. Returns the ID of the new stream.
int streamId = this.soundPool.play(this.soundIdGun,leftVolumn, rightVolumn, 1, 0, 1f);
}
}
// When users click on the button "Destroy"
public void playSoundDestroy( ) {
if(loaded) {
float leftVolumn = volume;
float rightVolumn = volume;
// Play sound objects destroyed. Returns the ID of the new stream.
int streamId = this.soundPool.play(this.soundIdDestroy,leftVolumn, rightVolumn, 1, 0, 1f);
}
}
}
Chạy ứng dụng:
