Introducing sounds and music
Sound and music plays a big role in gameplay for the user. If used properly, they can give a game the extra edge it needs to allow the player to become fully immersed while playing. On the other hand, they can also cause annoyance and disapproval if used incorrectly. In this recipe, we're going to jump into the subject of Sound
and Music
objects in AndEngine, covering the "how-to's" of loading them through to modifying their rates and more.
Getting ready
Complete the Know the life cycle recipe given in this chapter, so that we've got a basic AndEngine project set up in our IDE. Additionally, we should create a new subfolder in our project's assets/
folder. Name this folder as sfx
and add a sound file named sound.mp3
and another named music.mp3
. Once this is done, continue on to the How to do it... section.
How to do it…
Perform the following steps to set up a game to use the Sound
and Music
objects. Note that Sound
objects are meant for sound effects, such as explosions, collisions, or other short audio playback events. The Music
objects are meant for long audio playback events such as looping menu music or game music.
- The first step involves making sure that our
Engine
object recognizes that we plan to useSound
andMusic
objects in our game. Add the following lines in theonCreateEngineOptions()
method of our activity's life cycle after theEngineOptions
object has been created:engineOptions.getAudioOptions().setNeedsMusic(true); engineOptions.getAudioOptions().setNeedsSound(true);
- In step two, we will set our asset paths for the sound and music factories, then load the
Sound
andMusic
objects.Sound
andMusic
objects are resources, so as you may have guessed, the following code can be dropped into theonCreateResources()
method of our activity's life cycle:/* Set the base path for our SoundFactory and MusicFactory to * define where they will look for audio files. */ SoundFactory.setAssetBasePath("sfx/"); MusicFactory.setAssetBasePath("sfx/"); // Load our "sound.mp3" file into a Sound object try { Sound mSound = SoundFactory.createSoundFromAsset(getSoundManager(), this, "sound.mp3"); } catch (IOException e) { e.printStackTrace(); } // Load our "music.mp3" file into a music object try { Music mMusic = MusicFactory.createMusicFromAsset(getMusicManager(), this, "music.mp3"); } catch (IOException e) { e.printStackTrace(); }
- Once the
Sound
objects are loaded into theSoundManager
class, we can play them as we see fit by callingplay()
on them, be it during a collision, button click, or otherwise:// Play the mSound object mSound.play();
- The
Music
objects should be handled in a different manner toSound
objects. In cases where ourMusic
object should loop continuously throughout the game, which is in most cases, we handle allplay()
andpause()
methods within the activity life cycle:/* Music objects which loop continuously should be played in * onResumeGame() of the activity life cycle */ @Override public synchronized void onResumeGame() { if(mMusic != null && !mMusic.isPlaying()){ mMusic.play(); } super.onResumeGame(); } /* Music objects which loop continuously should be paused in * onPauseGame() of the activity life cycle */ @Override public synchronized void onPauseGame() { if(mMusic != null && mMusic.isPlaying()){ mMusic.pause(); } super.onPauseGame(); }
How it works…
In the first step for this recipe, we are required to let the Engine know whether we will be taking advantage of AndEngine's ability to play Sound
or Music
objects. Failing to address this step will cause an error in the application, so before we move forward in implementing audio into our game, make sure this step is done before returning EngineOptions
in the onCreateEngineOptions()
method.
In the second step, we are visiting the onCreateResources()
method of the application's life cycle. Firstly, we are setting the base path of both SoundFactory
and MusicFactory
. As mentioned in the Getting ready section, we should have a folder for our audio files in the assets/sfx
folder in our project, which includes all of our audio files. By calling setAssetBasePath("sfx/")
on each of the two factory classes used for audio, we are now pointing to the proper folder to look for audio files. Once this is done, we can load our Sound
objects through the use of the SoundFactory
class and Music
objects through the use of the MusicFactory
class. The Sound
and Music
objects require us to pass the following parameters: mEngine.getSoundManager()
or mEngine.getMusicManager()
depending on the type of audio object we're loading, the Context
class which is BaseGameActivity
, or this activity, and the name of the audio file in string format.
In the third step, we can now call the play()
method on the audio object that we wish to play. However, this method should only be called after the onCreateResources()
callback has been notified that all resources have been loaded. To be safe, we should simply not play any Sound
or Music
objects until after the onCreateResources()
portion of AndEngine's life cycle.
In the final step, we are setting up our Music
object to call its play()
method when our activity starts up and onResumeGame()
is called from the life cycle. On the other end, during onPauseGame()
, the Music
object's pause()
method is called. It is best practice in most cases to set our Music
objects up this way, especially due to the eventual inevitability of application interruptions, such as phone calls or accidental pop-up clicking. This approach will allow our Music
object to automatically be paused when the application leaves focus and start back up once we return from minimization, including execution.
Note
In this recipe, and others relating to resource loading, the names of the files have been hardcoded in to the code snippets. This is done to add simplicity, but it is advisable to use the strings.xml
Android resource file provided for our project in order to keep strings organized and easy to manage.
There's more…
AndEngine uses Android native sound classes to provide audio entertainment within our games. These classes include a few additional methods aside from play()
and pause()
that allow us to have more control over the audio objects during runtime.
The following list includes methods provided for the Music
objects:
seekTo
: TheseekTo(pMilliseconds)
method allows us to define where the audio playback of a specificMusic
object should start from.pMilliseconds
is equal to the position of the audio track, in milliseconds, where we'd like to start playback upon callingplay()
on theMusic
object. In order to obtain the duration of aMusic
object in milliseconds, we can callmMusic.getMediaPlayer().getDuration()
.setLooping
: ThesetLooping(pBoolean)
method simply defines whether or not theMusic
object should replay from the beginning once it reaches the end of its duration. IfsetLooping(true)
, theMusic
object will continuously repeat until the application is closed or untilsetLooping(false)
is called.setOnCompletionListener
: This method allows us to apply a listener into theMusic
object, which gives us the opportunity to execute a function pending track completion. This is done by addingOnCompletionListener
to ourMusic
object, as follows:mMusic.setOnCompletionListener(new OnCompletionListener(){ /* In the event that a Music object reaches the end of its duration, * the following method will be called */ @Override public void onCompletion(MediaPlayer mp) { // Do something pending Music completion } });
setVolume
: With thesetVolume(pLeftVolume, pRightVolume)
method, we are able to adjust the left and/or right stereo channels independently. The minimum and maximum range for volume control is equal to0.0f
for no volume and1.0f
for full volume.
The following list includes methods provided for the Sound
objects:
setLooping
: See theMusic
object'ssetLooping
method's description above for details. Additionally,Sound
objects allow us to set how many times the audio track will loop withmSound.setLoopCount(pLoopCount)
, wherepLoopCount
is anint
value defining the number of times to loop.setRate
: ThesetRate(pRate)
method allows us to define the rate, or speed, at which theSound
object will play, wherepRate
is equal to the rate as a floating point value. The default rate is equal to1.0f
, while decreasing the rate will lower the audio pitch and increasing the rate will increase audio pitch. Keep in mind, the Android API documentation states that the rate accepts values between a range of0.5f
through to2.0f
. Exceeding this range on a negative or positive scale may cause errors in playback.setVolume
: See theMusic
object'ssetVolume
method's description above for details.
Note
For those of us who are not geared toward audio creativity, there are plenty of resources out there which are free to use. There are plenty of free sound databases that can be found online that we can use in public projects, such as http://www.soundjay.com. Keep in mind, most free-to-use databases require attribution for the files used.