Friday, 30 September 2011

Playing Sounds with SoundPool

Android provides us with two main classes for playing sounds; SoundPool and MediaPlayer. SoundPool is used ideally for playing shorter tracks and MediaPlayer for longer ones, and in this post I'm going to be focusing on using SoundPool.

First of all, to create a new SoundPool object use the constructor

SoundPool soundpoolexample = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);

The first parameter states how many sounds can be played at the same time before some are stopped even if they aren't finished. The second is the stream type, which you can just leave as STREAM_MUSIC for games, and the final number is the sample-rate converter quality, although apparently this doesn't actually do anything yet so just leave it at 0. The most important one of these is obviously how many concurrent sounds you want to be able to play.

Next you have to load all of the different sounds that you are going to use. To do this use the line

int soundID = soundPool.load(context, R.raw.example, 1);

In this example I have a track in my res/raw/ directory called example. Note that the file extension is dropped. The context is simply the activity context, which if you're calling this line from your main activity you can probably just put this to get the context. The final 1 is the priority, although again apparently this does nothing yet but a 1 should be used for future compatibility.

You will have no doubt noticed that SoundPool.load will return something since I have made an int equal the return value. What is returned is an int that is later used as a reference to that specific sound and used to play it. (Also note that it might take a few seconds after the call to load() for the sound to be ready, so if you try and play it straight away and it doesn't work that might be the reason why.)

soundPool.play(soundID, float leftVolume, float rightVolume, int priority, int loop, float rate);

As you can see we need to use the int that was returned to play the sound, and NOT the resourceID of the sound (i.e. R.raw.example). The two volume 's are floats from 0-1 that represent the left and right speaker volumes respectively. priority tells the SoundPool which sound to stop playing first if there are too many being played at the same time. loop is obviously how many times to loop, with -1 meaning keep looping and 0 don't loop. Finally, rate is how fast it should be played, with 1 .0 being normal frequency and 2 being twice as fast etc..

That's basically all there is to it. Other things to note are that SoundPool.play returns a StreamID that can later be used as SoundPool.pause(StreamID) to pause that sound if you wish, and SoundPool.resume(StreamID) to resume it.

Below is a sample MusicPlayer class that I wrote which you're free to use to simplify playing short sound tracks. It uses a HashMap to store the resource IDs of the sounds and the sound ID returned from SoundPool.load() as key/value pairs so that you can later simply call the play method with the sound's resource ID to play it. It is a static class so you don't need to create an instance of it and can play 4 sounds concurrently but you can easily change that if you wish. An example of using it would be:

MusicPlayer.initSounds(context,R.raw.example1,R.raw.example2,R.raw.example3);


A few seconds later so it has time to load

MusicPlayer.play(R.raw.example2);




import java.util.HashMap;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;



/**
 * @author tixopi
 * @initSounds
 *             Call first with the context from your main activity
 *             and a comma separated list of the resource IDs of the tracks you want to be able to play
 * @play
 *       Call with the resource ID of the track as a parameter to play it
 * @playBackground
 *                 Use to set the background track
 * @mute-and-unMute
 *                  Self-explanatory
 */




public class MusicPlayer {


	static SoundPool					soundPool;
	static boolean						muted			= false;
	static HashMap<Integer, Integer>	soundPoolMap	= new HashMap<Integer, Integer>();

	static float						volume			= (float) 0.6;



	public static void initSounds(Context context, int... trackIDs) {


		int length = trackIDs.length;


		soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);

		for (int i = 0; i < length; i++) {


			//Uses the track resource id as the hashmap key, which allows the track to later be played
			//The value is the sound id returned by load which is what is used to play
			//This way the two are linked to together and the sound can be played knowing only its resource id

			soundPoolMap.put(trackIDs[i], soundPool.load(context, trackIDs[i], 1));


		}
	}



	public static void play(int resID) {

		if (!muted) {

			soundPool.play(soundPoolMap.get(resID), volume, volume, 1, 0, 1f);


		}
	}




	public static void mute() {

		muted = true;

	}



	public static void unMute() {

		muted = false;

	}



}


Questions regarding the post or ideas for an upcoming article? Go ahead and leave a comment

No comments:

Post a Comment