Handling Sound in Cocos2D for Android

Screenshot_2000-01-24-00-59-25

Screenshot credits from one of my games – Puzzbox Africa

In many games, sound remains a vital component for achieving interactivity. You may need to play short sound clips in response to events e.g when a button is pressed, a user slides an object, a ninja fires an arrow etc. Other times you might need long running sound play such as  background music for an entire game. More importantly, you need to ensure that your users can control and disable the sound at their convenience – wouldn’t do to have a game that just wont shut-up. This is especially important as it does not happen automatically in cocos2D. Your background sound will keep playing after users exit the app if you don’t explicitly restrict it from doing so. Also , your sound volume might not respond to the device volume up and volume down keys. Both situations above can cause disapproval of your android app on some app-distribution platforms (such as Samsung and Nokia X).

In this post, I’ll provide snippets on how to handle the above sound issues in your Cocos2D for android game. If you are new to cocos2D , feel free to review previous posts  on building simple games with cocos2D for android.

Playing Short Sound Clips in Cocos2D .

Following best practices, it is best to create an option for users to disable both sound effects and background music . You then create a single method which  that plays all your your sound effects – and every sound play event calls this method . The benefit of this design principle is to ensure you can easily deactivate all sound by with a single condition and at a single position in code. Cocos2D plays sound using the SoundEngine.sharedEngine().playEffect(app, resourceId) method which takes two arguments. First argument is the application context and the second is the mp3 or wave file resource id. A sample method that checks if the user has opted to play sound before playing the sound is given below

public static void playeffectsound(int resourceID) {
// if sound effect setting is true
if (effectsetting == 1){
SoundEngine.sharedEngine().playEffect( this, resourceID); }

}

Playing a long background sound.

Cocos2D for android uses the  SoundEngine.sharedEngine().playSound(app, resourceID, true) method to play background sounds and takes 3 arguments. Similar to palying sound effects, the first argument is the application context, second is the sound resourceId ( a wav or mp3 file) and the final argument specifies if the sound should be played in a look or not. A sample method is given below.

public static void playbackgroundsound() {
if (bgsoundetting == 1){
SoundEngine.sharedEngine().playSound(app, R.raw.jungle, true);
}
}

Managing Sound on App Exit.

To ensure that your sound pauses and resumes when your users exit and resume your app respectively, you must be sure to specify these in the onPause() and onResume() methods of your main activity.

@Override
public void onResume()
{
super.onResume();
SoundEngine.sharedEngine().resumeSound();
}

@Override
public void onPause()
{
super.onPause();
SoundEngine.sharedEngine().pauseSound();
}

Managing Game Volume.

You can manage sound volume by listening for the volume up and volume down keypress event and increasing/decreasing your sound volume accordingly. This is achieved using the SoundEngine.sharedEngine().getSoundsVolume() method and the SoundEngine.sharedEngine().setSoundsVolume(volume) method. A snippet is shown below.

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {

float newVolume = SoundEngine.sharedEngine().getSoundsVolume() - 0.1f ;
if (newVolume <= 0.0f) { newVolume = 0.0f; } SoundEngine.sharedEngine().setSoundVolume(newVolume); //backgroundMusicPlayer.setBackgroundVolume(newVolume); //result = true; } else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP){ float newVolume = SoundEngine.sharedEngine().getSoundsVolume() + 0.1f; if (newVolume >= 1.0f) {
newVolume = 1.0f;
}
SoundEngine.sharedEngine().setSoundVolume(newVolume);

//result = true;
}

return true;

}

Managing Play Pitch/Rate (My Matt)

One the readers of this tutorial (Matt) kindly provided his solution to changing the playrate/pitch. This approach is feasible if you use the Cocos2D java files directly in your project (i recommend this) . You can adjust the soundengine.java class by allowing the playEffect method take a rate argument , and setting the sound play rate

public void playEffect(Context app, int resId, float effectsRate ) {
if (effectsRate != null) {
sp.setRate(streamId, effectsRate);
...
...

}

Here , sp is the Android SoundPool objected used to play audio files. The effectsRate argument is a floating point value (0.5 – 2.0 )that can control play speed. You can then call this method in your playEffects code above by passing a rate argument

 SoundEngine.sharedEngine().playEffect( this, resourceID, effectsRate) ; 

Thanks Matt!

About Vykthur

Mobile and Web App Developer and Researcher. Passionate about learning, teaching, and recently - writing.
This entry was posted in Android Tutorials, Cocos2d, Cocos2D for android, Developer Tips, Education, Programming, Tutorials and tagged , , , , , , . Bookmark the permalink.
  • Gieh widodo

    hey part 3 of this tutorial is missing, can you upload it again..thank you

  • Matt

    One thing missing from SoundEngine is pitch/rate. But this is easily solved by editing SoundEngine.java and adding a few simple lines to the playEffect method and then create a new method called setEffectsRate (or whatever you wish to call it).

    For example, add these three lines to the playEffect…

    if (effectsRate != null) {
    sp.setRate(streamId, effectsRate);
    }

    And create this method somewhere within the SoundEngine class…

    public void setEffectRate(float rate) {
    effectsRate = rate;
    }

    • Vykthur

      Thanks Matt!
      I just updated the tutorial to reflect your excellent suggestions and fix!

      -V.

      • Matt

        Just discovered that on some devices (e.g. Nexus 7) you need to also alter the streamId line too…
        int streamId = sp.play(sndId, 1.0f, 1.0f, 0, 0, effectsRate);

        • Vykthur

          thanks matt .. Great work!