Android SoundPool Example

Recently I was writing an app where I wanted to generate a sound to accompany an alert dialog box popping up. Initially I intended to use a MediaPlayer but it seemed like a lot of hassle just to produce a brief blast of sound. And as I scanned the forums I found that other programmers were suggesting SoundPool as a simpler alternative.

The SoundPool class allows the programmer to gather up a collection of sound objects into memory and play them with very low latency. Internally it uses the MediaPlayer. A full description is here – http://developer.android.com/reference/android/media/SoundPool.html

I made a little standalone app to play with this. All it does is allow the user to select one of two sound files and play them. It also allows the user to select playback speeds of slow, normal, or fast.

I started by making a default Android project with a simple LinearLayout. Because this project uses audio files I created a folder in the “res” part of the workspace tree called “raw”, i.e., res\raw. I dropped a couple of short .MP3 files, shosta_7sec.mp3 and mozart_4sec.mp3

It helps to have a junkbox of little soundfiles of different lengths lying around. I use a free MP3 editor called MP3DirectCut (http://mpesch3.de1.cc/mp3dc.html) to make them out of files in my regular music library.

Anyway, I added a Play button to my layout along with two groups of radio buttons. For more details on radio Buttons in Anddroid see my blog post “Radio Buttons and Checkboxes

This is what it looks like . . .
Example Output

“Sound1” and “Sound2” are to demonstrate having multiples sounds in the “pool”. The other three buttons are to demonstrate radio button groups and some cutesy stuff we can do with playback.

public class AudioPlayer1 extends Activity {

	private SoundPool soundPool;
	private HashMap<Integer, Integer> soundsMap;
    int SOUND1=1;
    int SOUND2=2; 

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
        soundsMap = new HashMap<Integer, Integer>();
        soundsMap.put(SOUND1, soundPool.load(this, R.raw.shosta_7sec, 1));
        soundsMap.put(SOUND2, soundPool.load(this, R.raw.mozart_4sec, 1));
    }

        public void playSound(int sound, float fSpeed) {
        AudioManager mgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
        float streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
        float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        float volume = streamVolumeCurrent / streamVolumeMax;  

        soundPool.play(soundsMap.get(sound), volume, volume, 1, 0, fSpeed);
       }

    // User has clicked "Play" . . .
    public void Audio1ButtonHandler(View target) {
       RadioButton radioSound1 =
             (RadioButton)this.findViewById(R.id.radioSound1);
       RadioButton radioSpeedLo =
             (RadioButton)this.findViewById(R.id.radioSpeedLo);
       RadioButton radioSpeedNorm =
              (RadioButton)this.findViewById(R.id.radioSpeedNorm);
   	   float fSpeed = 1.0f;
       if (radioSpeedLo.isChecked()) {
    	   fSpeed = 0.5f;
       }
       else if (radioSpeedNorm.isChecked()) {
    	   fSpeed = 1.0f;
       }
       else {
    	   fSpeed = 2.0f;
       }

       // select the sound file
   	   if (radioSound1.isChecked()) {
   	   	 playSound(SOUND1, fSpeed);
   	   }
   	   else {
  	   	 playSound(SOUND2, fSpeed);
   	   }
    }
}

The “Play” button handler takes advantage of the android:onClick feature to avoid messy listener code. In the handler we interrogate the various radio buttons to determine the user’s choice of sound and playback speed before calling our playSound() method.
That’s where we compute our volume levels and call the SoundPool’s play() method.

The first parameter of play() is the selection of a sound, which in this case we get from a HashMap. HashMap is a Java class that lets us associate key/value pairs where the key is an integer and the value is the sound file. We set up those relationships in onCreate(). The next two parameters to play() are the left and right volumes, computed a few lines above. The next param is priority, which we’ve set to 1, 0 being the lowest. Then the looping value which we’ve set to 0, meaning “don’t loop”. Finally the playback speed, which we’ve passed in based on the radio button selections.

The resulting app is not particularly useful by itself, but the concepts in it can be applied to lots of real-world apps.

Comments are closed.