In today’s tutorial I am going to show you my method of creating, managing and using sound effects in Android. In this first part I’ll show you the basic method of encapsulating your sound management code. This method works best when you have a typical application, or simple game all in one thread. After you have read this check out Part 2 which will show you a more advanced way to manage your sound across multiple classes.
The method I use to play sounds is to use the Sound Pool classes rather then the Media Player classes that the Android dev-guide seems to suggest. While there is nothing wrong with using the Media Player classes for simple applications they did not provide the flexibility I needed.
Before I get into the code I will recommend using .ogg files for your sound and music. There have been reports that Sound Pool is unstable for other file types although I was unable to confirm that myself.Even if there was no problem with other file types I would still recommend .ogg for the excellent file compression.
Now on with the code. The first thing we need to do is to create a Sound Manager class to encaspulate all the sound code.
public class SoundManager { private SoundPool mSoundPool; private HashMap mSoundPoolMap; private AudioManager mAudioManager; private Context mContext;
This first bit of code is to set up the member variables needed:
mSoundPool: The Android provided object we use to create and play sounds.
mSoundPoolMap: A Hashmap to store the sounds once they are loaded.
mAudioManager: A handle to the service that plays the sounds we want.
mContext: A handle to the application Context.
public void initSounds(Context theContext) { mContext = theContext; mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0); mSoundPoolMap = new HashMap(); mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); }
This first method sets up the Sound Manager. We start by passing in the Context of the application and getting a handle to it. The next line Create the sound pool object. only the first argument is interesting.The Int passed here states how many concurrent audio streams you want.In other words how many sounds can play at once.If you try to play more then this number then it stops the oldest stream.
The next two lines simply create the Hash map and handle to the audio-manager.
public void addSound(int index, int SoundID) { mSoundPoolMap.put(index, mSoundPool.load(mContext, SoundID, 1)); }
This function is where we start adding sounds. Each sound gets an index that is used to play it back. Make sure you give each of your sounds different indexes. The SoundId argument is from your raw resources file.You can pass this by calling R.raw.mysound to get the id for a sound called mysound for example. I’ll show how to use this function fully later in the tutorial.
public void playSound(int index) { float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f); } public void playLoopedSound(int index) { float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, -1, 1f); }
These two functions control sound playback. You simply pass in the sounds index number that you created in addSound(). The steamVolume variable is used to get the current volume set for media on the device.This is because you don’t want the audio playback to be louder or quieter then the user as set the phone to.
You need to divide it by the streams maximum value in order to get a float value between 0.0 and 1.0 that the play function requires (Thank you to Gyuri for pointing that out for me).
The mSoundPool.play function is quite simple.You first pass the index of the sound you wish to play(remember that you set this index yourself in addSound). The second two are the left and right volumes respectively.I would advise against setting these to anything other then the stream volume unless you have good reason.
The next variable is the priority of the sound. This is currently not implemented so setting it to one is fine. The next variable is more useful as it defines if the sound is looped or not. A -1 will cause it to loop and and a 1 will cause it to be a number single play. This is the reason for the two almost identical functions. I wanted one that lets me loop a sound if I wished.
The final variable affects the rate of play. 1 is normal speed and the range goes from 0.5 to 2.0 for between half and double speed play.
Using the class is very simple. All you need to do is create a member variable where you need you sounds. Once you have that you can initialise the sound manager and start adding sounds as show below.
mSoundManager = new SoundManager(); mSoundManager.initSounds(getBaseContext()); mSoundManager.addSound(1, R.raw.sound);
Then to play a sound simply call play with is index.
mSoundManager.playSound(1);
That is all there is to it. I have created a simple project to illustrate the use of the class and its available here: SoundTutorial.zip.
Look out for part two where I’ll explain more advanced version of this class.
Stephen Flockton
Comments
Leave a comment Trackback