Saturday, September 24, 2011

Belajar Memprogram MPEG Audio Layer 3 di Android

Belajar Memprogram MPEG Audio Layer 3 di Android Image
MPEG Audio Layer 3 atau yang lebih dikenal dengan MP3, adalah format kompresi audio yang paling populer digunakan di seluruh dunia. Dengan dukungan terhadap MP3, Android menyediakan akses ke beragam file audio yang tersedia di Internet maupun toko musik.

AMR (Adaptive Multi-Rate)

Format kompresi ini sangat populer digunakan pada aplikasi panggilan suara ponsel. AMR dirancang untuk voice encoding, format kompresi ini tidak cocok untuk jenis audio kompleks seperti musik. Format kompresi ini biasanya disimpan sebagai file .amr atau .3gp.

Ogg Vorbis

Ogg Vorbis (.ogg) adalah format kompresi audio open source dan bebas paten. Kualitasnya sebanding dengan format komersial seperti MP3 maupun AAC. Ogg Vorbis saat ini dikelola oleh Xiph.org.

PCM (Pulse Code Modulation)

PCM adalah format audio yang populer di PC terutama Windows. Format audio ini biasanya format tidak terkompresi seperti WAVE (.wav). PCM menyimpan data audio sebagai sekumpulan data amplitudo yang berubah terhadap waktu. Android mendukung PCM melalui file WAV.

Layanan bawaan untuk memainkan file audio

Android menyediakan aplikasi bawaan untuk memainkan file audio. Untuk menjalankan aplikasi tersebut, Anda hanya perlu menciptakan Intent ACTION_VIEW. Intent ini butuh data lokasi file audio (Uri) dan tipe MIME file audio yang hendak dimainkan. Ketika kode pada Listing 1 dieksekusi, Android akan menjalankan aplikasi yang mampu menangani file audio dengan MIME “audio/mp3”, biasanya adalah aplikasi Music.
Listing 1


1
2
3
4
5
6
//file musik diasumsikan
File sdcard=Environment. getExternalStorageDirectory();
File fileAudio=new File(sdcard.getPath() +"/smoothjazz.mp3");
Uri uriAudioFile=Uri.fromFile(fileAudio);
Intent an_intent = new Intent( android.content.Intent.ACTION_VIEW);
an_intent.setDataAndType(audioFileUri, "audio/mp3"); startActivity(an_intent);

Audio playback dengan MediaPlayer

Cara memainkan file audio di atas adalah memanfaatkan aplikasi lain. Ini tentu tidak cocok bila Anda hendak membuat aplikasi multimedia player sendiri. Untuk hal tersebut, Android menyediakan kelas MediaPlayer yang menyediakan fungsionalitas audio playback yang lengkap. Kelas ini dapat Anda pergunakan dengan mengimpor paket android.media.
MediaPlayer umumnya digunakan untuk memainkan data audio yang berukuran besar dengan cara streaming yakni membaca data sedikit demi sedikit lalu memainkan data tersebut.
Ada beberapa cara kita dapat menciptakan MediaPlayer, yakni dari resource, dari Uri, dari file yang ada penyimpanan lokal (local storage) atau dari jaringan (URL).

Memuat audio pada MediaPlayer

Untuk menggunakan file audio yang diletakkan di resource, Anda cukup meletakkan file audio tersebut di direktori res/raw. Perbarui isi jendela Package Explorer dengan menekan F5 maka plugin Eclipse akan membuatnya dapat diakses lewat kelas R. Jika Anda menyalin file audio bernama smoothjazz.mp3 ke direktori res/raw, maka kode pada Listing 2 adalah cara menciptakan instance MediaPlayer dari data fie audio di resource. Yang harus dipastikan adalah ektensi pada nama file tidak disertakan sebagai pengenal sehingga jika Anda memiliki file dengan nama sama namun ekstensi berbeda, misalkan smoothjazz.mp3 dan smoothjazz.ogg, hal ini menyebabkan kerancuan. Solusinya adalah dengan menamai ulang file, misalnya menjadi smoothjazz-mp3.mp3 dan smoothjazz-ogg.ogg.
Belajar Memprogram MPEG Audio Layer 3 di Android Image
Listing 2


1
2
3
MediaPlayer mplayer = MediaPlayer.create(
context,R.raw.smoothjazz);
Instance MediaPlayer yang diciptakan dengan create() telah dalam status Prepared dan siap untuk dimainkan.

Memuat audio dari penyimpanan lokal

File audio yang tersimpan di memori lokal seperti SD card dapat dimainkan dengan terlebih dahulu mengatur sumber data yang digunakan MediaPlayer. Metode setDataSource() disediakan untuk maksud ini. Ada tiga bentuk metode setDataSource(), yakni setDataSource(String path), setDataSource(Context context, Uri uri) dan setDataSource(FileDescriptor fd).
Listing 3


1
2
3
4
5
MediaPlayer mplayer = new MediaPlayer();
mplayer.setDataSource(“/mnt/sdcard/smootjazz.mp3?);
mplayer.prepare();
Setelah itu, Anda harus memanggil prepare() untuk menyiapkan data audio. Metode prepare() berjalan secara sinkron. Kendali alir program tidak akan keluar dari fungsi prepare() sebelum proses persiapan selesai. Setelah proses persiapan selesai, status MediaPlayer akan diubah menjadi Prepared. Proses persiapan ini mungkin cukup menyita waktu dan akan menyebabkan aplikasi tampak berhenti sejenak terutama bila data audio cukup besar atau akses bacanya lambat seperti jaringan.
Jika Anda ingin aplikasi tetap responsif saat proses persiapan. Anda bisa menggunakan prepareAsync(). Metode prepareAsync() digunakan untuk menyiapkan data audio secara asinkron. Kendalir alir program akan segera keluar dari metode prepareAsync() tanpa menunggu proses persiapan selesai.
Untuk memastikan kapan proses persiapan selesai, Anda harus memberitahukan fungsi callback yang akan dipanggil ketika proses persiapan selesai melalui metode setOnPreparedListener() milik MediaPlayer. Metode ini mengharapkan instance interface MediaPlayer.onPreparedListener. Metode pada interface ini adalah onPrepared(). Metode onPrepared() ini akan dipanggil bila audio siap dimainkan.

Memuat audio dari Uri

Untuk memuat audio dari Uri Anda bisa memodifikasi Listing 3 dengan menggunakan metode setDataSource(Context context, Uri uri)

Kendali audio playback pada MediaPlayer

Kendali audio playback disediakan oleh MediaPlayer melalui metode start(), stop(), pause() dan seekTo().
Belajar Memprogram MPEG Audio Layer 3 di Android Image

Mulai playback

Metode start() (Listing 4) akan memicu aksi audio playback dan mengubah status MediaPlayer menjadi Started bila pemanggilan start() sukses. Status Started ini dapat diuji dengan metode isPlaying() yang akan mengembalikan nilai boolean true atau false. Pemanggilan start() berulang-ulang ketika berada dalam status Started tidak berdampak apa-apa.
Listing 4


1
mplayer.start();


Menghentikan sementara

Playback bisa dihentikan sementara dengan metode pause(). Ketika pause() sukses dijalankan, status akan berubah dari Started ke Paused. Metode pause() dikerjakan secara asinkron yakni akan keluar tanpa menunggu status Started berubah menjadi Paused. Untuk audio yang dimainkan secara streaming dari jaringan, waktu yang dibutuhkan untuk mencapai status Paused mungkin cukup panjang.
Listing 5


1
mplayer.pause();

Melanjutkan playback

Playback yang telah dihentikan sementara dapat dilanjutkan dengan memanggil start() pada saat MediaPlayer dalam status Paused. Pemanggilan start() selanjutnya akan menyebabkan transisi status Paused menjadi Started.
Bila posisi kursor playback tidak diubah sejak dihentikan sementara, maka start() akan mulai dari posisi kursor playback terakhir ketika pause() dijalankan.

Menghentikan playback

Audio playback dihentikan dengan memanggil stop(). Bila stop() sukses, status Started akan diubah menjadi Stopped. Perubahan status dari Started ke Stopped mungkin tidak terjadi seketika.
Listing 6


1
mplayer.stop()

Mengatur posisi kursor playback

Ketika status adalah Prepared, Starterd, Paused atau PlaybackCompleterd. posisi playback bisa diubah dengan seekTo(). Metode ini mengharapkan parameter bertipe integer yakni waktu dalam milidetik dihitung dari awal (Listing 7).
Listing 7


1
2
3
4
5
//ubah posisi playback
//20 detik dari awal
mplayer.seekTo(20000);

Memainkan audio berulang-ulang

Metode setLooping() Anda perlukan jika Anda ingin memainkan musik yang diulang-ulang ketika telah selesai (Listing 8). Metode ini mengharapkan sebuah parameter bertipe boolean yang bila diisi true akan menyebabkan audio playback diulang terus menerus.
Listing 8


1
mplayer.setLooping(true);
Penggunaan setLooping() menyebabkan pengulangan tak terhingga hingga audio dihentikan secara eksplisit dengan stop(). Jika Anda hanya ingin mengulang audio sejumlah tertentu saja, Anda bisa mengatur fungsi callback yang akan dipanggil ketika audio selesai dimainkan dengan setOnCompletionListener(). Metode ini mengharap parameter bertipe interface OnCompletionListener.
Anda perlu membuat implementasi metode OnCompletionListener.onCompletion(). Dalam metode onCompletion(), Anda hitung jumlah pengulangan yang terjadi dan bila masih kurang, Anda memanggil start() untuk memulai audio playback dari awal.

Kendali volume pada MediaPlayer

Volume MediaPlayer dapat diatur dengan setVolume() (Listing 9). Metode ini mengharapkan dua parameter bertipe float yakni volume speaker kiri dan volume speaker kanan.
Listing 9


1
mplayer.setVolume(leftvol,rightvol);

Audio playback dengan SoundPool

SoundPool adalah kelas yang mengelola dan memainkan data audio bertipe PCM 16-bit mono atau stereo tidak termampatkan. SoundPool dirancang untuk memainkan audio berdurasi pendek dengan latensi rendah. Tingkat latensi yang rendah ini dicapai karena SoundPool mengasumsikan semua data audio yang ditanganinya adalah data berformat PCM tidak termampatkan. Data audio PCM tersebut selanjutnya disimpan di memori sehingga bisa diakses dengan cepat tanpa perlu dekompresi. Untuk format audio lain, SoundPool akan menggunakan MediaPlayer untuk melakukan dekompresi format tersebut ke format PCM ketika proses memuat data ke memori. Dengan demikian, aplikasi dapat menyimpan data audio termampatkan seperti MP3 atau Ogg yang saat runtime dimuat ke memori sebagai data PCM
SoundPool dapat digunakan untuk memainkan beberapa data audio secara bersamaan. Ketika menciptakan instance kelas ini, Anda akan diminta menentukan jumlah stream maksimum yang akan digunakan. Nilai ini adalah banyaknya audio yang dapat dimainkan secara bersamaan pada satu saat.
Jika data audio yang Anda mainkan bersamaan lebih banyak dari jumlah stream maksimum. SoundPool akan menghentikan playback audio yang sedang dimainkan berdasarkan prioritas dan kapan waktu mulai dimainkan. Hal ini guna memberi ruang bagi audio baru untuk dimainkan.
Semakin banyak jumlah stream SoundPool, semakin berat beban CPU untuk mencampur audio-audio yang dimainkan bersamaan. Untuk itu, Anda sebaiknya meminimalkan jumlah stream maksimum sesuai kebutuhan saja.
Dengan fitur seperti latensi rendah dan kemampuan memainkan beberapa audio secara bersama, SoundPool sangat cocok untuk digunakan dalam aplikasi game. Listing 10 berisi contoh bagaimana menciptakan instance SoundPool dengan maksimal jumlah stream 6, tipe stream untuk musik dan kualitas default.
Listing 10


1
2
3
4
5
SoundPool gPool=new SoundPool(6,
AudioManager.STREAM_MUSIC,
0);

Memuat audio pada SoundPool

Kelas SoundPool menyediakan metode load() untuk memuat data audio ke memori. Metode ini terdiri atas empat variasi, namun yang kita akan pergunakan hanya dua, yakni: load(String path, int priority), load(Context context, int resid, int priority). Metode load() pertama memuat data audio dari file yang tersimpan di penyimpanan lokal dan load() yang kedua memuat data audio dari resource. Untuk memuat data audio dari Uri, Anda bisa menggunakan load() pertama.
Metode load() mengembalikan nilai integer berisi pengenal audio yang nantinya dapat digunakan untuk mengacu pada data audio yang baru dimuat. Anda harus menyimpan pengenal ini karena semua fungsionalitas kendali playback menggunakannya.
Parameter terakhir load() adalah prioritas audio tersebut. Prioritas digunakan untuk menentukan bagaimana audio akan dihapus dari audio track ketika audio track sudah penuh terpakai dan ada audio lain yang hendak dimainkan. Menurut dokumentasi Android SDK, parameter ini belum berpengaruh apa-apa dan menyarankan menggunakan nilai 1 agar kompatibel dengan rilis Android di masa datang. Listing 11 berisi contoh
Listing 11


1
gSoundID=gPool.load(pFilename, 1);

Kendali audio playback pada SoundPool

Metode play() milik SoundPool digunakan untuk memulai playback (Listing 12). Parameter metode ini berturut-turut adalah pengenal audio yang dikembalikan oleh load() bertipe integer, volume kiri dan kanan bertipe float (0.0=volume minimum hingga 1.0=volume maksimum), prioritas audio bertipe integer, jumlah pengulangan bertipe integer (0=tidak diulang, -1=diulang terus menerus) dan playback rate.
Playback rate mengatur kecepatan playback. Nilai defaultnya adalah 1.0 dan berkisar 0.5 hingga 2.0. Bila kurang dari 1.0, suara akan menjadi lambat dan berat (Anda bisa bayangkan suara Darth Vader pada film Star Wars). Bila lebih dari 1.0, suara menjadi cepat dan tinggi (terdengar seperti suara pada karakter Alvin and the chipmunks).
Metode play() mengembalikan nilai bertipe integer yang merupakan pengenal stream yang sedang dimainkan. Anda menggunakan pengenal stream ini untuk mengendalikan playback lebih lanjut.
Listing 12


1
2
3
4
5
6
7
8
9
10
11
gStreamID=gPool.play(gSoundID,
gLeftVolume,
gRightVolume,
gPriority,
gLoop,
gRate);

Menghentikan sementara playback

Metode pause() mengharapkan sebuah parameter bertipe integer berisi pengenal stream yang akan dihentikan sementara (Listing 13).
Listing 13


1
gPool.pause(gStreamID);

Melanjutkan playback

Playback dilanjutkan dengan memanggil resume() dan melewatkan pengenal stream (Listing 14).
Listing 14


1
gPool.resume(gStreamID);

Menghentikan playback

Playback dihentikan dengan stop() dan melewatkan pengenal stream (Listing 15).
Listing 15


1
gPool.stop(gStreamID);

Merancang sistem audio untuk game

Kita akan membungkus MediaPlayer dan SoundPool menjadi sistem audio yang cocok untuk digunakan dalam aplikasi game. Pada aplikasi game, umumnya developer hanya peduli pada audio playback, terutama untuk memainkan musik latar dan efek-efek suara dalam game.
Musik latar pada dasarnya adalah data audio biasa, namun berdurasinya lebih panjang, sehingga untuk memainkannya lebih cocok menggunakan teknik streaming untuk meminimalkan kebutuhan buffer sementara. Musik latar ini kadang dimainkan secara berulang-ulang selama game berlangsung.
Efek suara adalah data audio berdurasi pendek. Suara dentuman meriam, suara desing peluru, suara hembusan angin dan lain-lain adalah contoh efek suara. Efek suara kadang dimainkan sebagai reaksi atas aksi yang dikerjakan oleh pemain. Untuk efek suara seperti ini, waktu latency (waktu yang dilampaui sejak proses playback dimulai hingga terdengar di speaker) harus cukup rendah. Jika latency terlalu tinggi, maka visualisasi game bisa jadi tidak singkron dengan audio. Ketika pemain menekan tombol untuk menembakkan peluru, Anda tentu ingin efek suara desing peluru terdengar bersamaan dengan penekanan tombol tersebut, bukan beberapa detik setelahnya.

Antar muka dasar sistem audio

Sistem audio yang kita bangun akan diturunkan dari dua buah interface dasar yang menentukan antar muka pemrograman yang harus disediakan oleh kelas yang mengimplementasi interface tersebut. Interface pertama adalah IAudio (Listing 12), adalah interface bagi enkapsulasi data audio baik musik latar maupun efek suara. Interface kedua adalah IAudioManager (Listing 13). Sesuai namanya ia adalah interface pengelola IAudio.

IAudio

Interface ini menyediakan antar muka yang harus diimplementasi oleh kelas turunan meliputi:
  • Metode untuk memuat data audio dari file berdasar yang nama file, Uri atau resource.

  • Metode kendali audio playback

  • Metode pengaturan volume.

Listing 12


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
package juhara.jhr_engine.audio;
import java.io.IOException;
import android.net.Uri;
/**
* Interface dasar management audio clip
* @version 1.0
* @author Zamrony P. Juhara
*
*/
public interface IAudio
{
public void loadFromFile(
final String pFilename)
throws IOException;
public void loadFromUri(
final Uri an_uri)
throws IOException;
public void loadFromResource(
final int resId)
throws IOException;
public void play();
public void pause();
public void resume();
public void stop();
public void release();
public void reset();
public boolean isPlaying();
public void setVolume();
public void setVolume(float leftvol,
float rightvol);
public void setLeftVolume(float vol);
public void setRightVolume(float vol);
public float getLeftVolume();
public float getRightVolume();
}

IAudioManager

Audio manager menyediakan antar muka pengelolaan IAudio meliputi metode untuk menambah, menghapus dan mendapatkan instance interface IAudio dan membebaskan audio engine internal (Listing 13).
Listing 13


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
package juhara.jhr_engine.audio;
import android.content.Context;
import juhara.jhr_engine.audio.IAudio;
public interface IAudioManager
{
public void add(
final AudioClass pAudio);
public AudioClass get(
final int indx);
public void remove(final int indx);
public void clear();
public int size();
public void release();
public void reset();
public Context getContext();
}

Kelas dasar audio

Kelas Audio (Listing 14) adalah kelas abstrak dan merupakan implementasi interface IAudio. Sebagian besar metode pada interface IAudio dibiarkan belum diimplementasi karena tidak relevan. Sebagian besar fungsionalitas yang disediakan kelas ini adalah metode pengaturan volume, prioritas playback, sample rate dan jumlah pengulangan playback.
Listing 14


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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package juhara.jhr_engine.audio;
import juhara.jhr_engine.audio.IAudio;
public abstract class Audio
implements IAudio
{
public static final int
LOOP_FOREVER=-1;
public static final int
NO_LOOP=0;
protected final IAudioManager
gManager;
private float
gLeftVolume=1.0f,
gRightVolume=1.0f,
gRate=1.0f;
private int
gPriority=0,
gLoopCount=0;
public Audio(
IAudioManager
aManager)
{
gManager=aManager;
}
@Override
public float getLeftVolume()
{
return gLeftVolume;
}
@Override
public float getRightVolume()
{
return gRightVolume;
}
@Override
public void setLeftVolume(final
float aLeftVolume)
{
this.gLeftVolume = aLeftVolume;
setVolume();
}
@Override
public void setRightVolume(final
float aRightVolume)
{
this.gRightVolume = aRightVolume;
setVolume();
}
protected IAudioManager
getManager()
{
return this.gManager;
}
public float getRate()
{
return gRate;
}
public void setRate(final float aRate)
{
gRate = aRate;
}
public int getPriority()
{
return gPriority;
}
public void setPriority(final
int aPriority)
{
gPriority = aPriority;
}
public int getLoop()
{
return gLoopCount;
}
public void setLoop(final
int aLoopCount)
{
gLoopCount = aLoopCount;
}
@Override
public void setVolume()
{
setVolume(gLeftVolume,
gRightVolume);
}
}

Manajemen audio dasar

Kelas BasicAudioManager (Listing 15) mengelola daftar instance Audio dan merupakan kelas implementasi interface IAudioManager. Daftar instance kelas Audio disimpan dalam sebuah instance ArrayList. Sebenarnya kelas BasicAudioManager ini hanyalah pembungkus instance ArrayList dengan tambahan metode untuk mereset dan membebaskan instance Audio yang tersimpan di ArrayList.
Listing 15


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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package juhara.jhr_engine.audio;
import java.util.ArrayList;
import android.content.Context;
import juhara.jhr_engine.audio.IAudio;
import juhara.jhr_engine.audio.IAudioManager;
public abstract class BasicAudioManager
implements IAudioManager
{
private final
ArrayList
gAudioList = new ArrayList();
private final Context gAppContext;
public BasicAudioManager(final Context aContext)
{
gAppContext=aContext;
}
@Override
public void add(final AudioClass pAudio)
{
gAudioList.add(pAudio);
}
@Override
public AudioClass get(final int indx)
{
return gAudioList.get(indx);
}
@Override
public void reset()
{
for(int i=0; i
{
final AudioClass
aAudio = gAudioList.get(i);
aAudio.reset();
}
}
@Override
public void release()
{
for(int i=0; i
{
final AudioClass
aAudio = gAudioList.get(i);
aAudio.stop();
aAudio.release();
}
}
@Override
public void clear()
{
gAudioList.clear();
}
@Override
public void remove(int indx)
{
gAudioList.remove(indx);
}
@Override
public Context getContext()
{
return gAppContext;
}
@Override
public int size()
{
return gAudioList.size();
}
}

Sistem audio musik latar

Instance pembungkus fungsionalitas audio playback untuk musik latar akan memanfaatkan MediaPlayer karena kita butuh streaming untuk memainkan musik latar yang cenderung berdurasi panjang. Latency bukan prioritas penting karena musik latar dapat dimainkan terlambat beberapa saat tanpa pengaruh besar pada gameplay.
Kelas StreamSound akan diturunkan dari kelas Audio dan melengkapi implementasi semua metode abstrak termasuk kendali audio playback seperti play(), pause(), resume() dan stop() dan proses memuat data audio dari file, uri atau resource.
Belajar Memprogram MPEG Audio Layer 3 di Android Image

Manajemen musik latar

Sistem audio untuk musik latar terbagi atas kelas StreamSoundManager dan StreamSound yang masing-masing bertugas sebagai pengelola instance StreamSound dan pembungkus audio playback untuk musik latar.

Sistem audio efek suara

Efek suara berdurasi pendek akan dibungkus dalam kelas SoundFX. Untuk efek suara, kita akan menggunakan SoundPool. Semua instance SoundFX akan menggunakan instance SoundPool yang sama. Instance SoundPool sendiri dikelola oleh pengelola SoundFX yakni kelas SoundFXManager.
Fungsionalitas yang disediakan SoundFX adalah proses memuat data audio, kendali playback dan pengaturan volume serta prioritas.

Manajemen efek suara

Tugas utama kelas SoundFXManager adalah mengelola masa hidup instance SoundPool karena semua instance SoundFX menggunakan kelas ini untuk kendali playback. Instance SoundPool diciptakan saat konstruksi SoundFXManager dan dibebaskan saat pemanggilam metode release(). Akses ke SoundPool hanya akses read-only dan disediakan metode getPool() untuk meminta instance SoundPool.

No comments:

Post a Comment