Adding Audio to Our Game - Sparrow iOS Game Framework Beginner's Guide (2014)

Sparrow iOS Game Framework Beginner's Guide (2014)

Chapter 9. Adding Audio to Our Game

In the previous chapter, we learned about artificial intelligence. We learned theory about finite state machines and fuzzy logic. We applied these elements to our game. We also implemented the remaining gameplay elements into our game. In this chapter, we are going to add music and sound to our game. Audio in itself is an important aspect to any game as it is part of the player's experience. Try to play your favorite game without music and you'll find yourself having a different experience when playing the game.

We will cover the following topics in this chapter:

· Loading sound and music files

· Generating our own sound effects

· Playing audio

Let's add music and sound to our game, shall we?

Finding music and sound

When developing a game, the developer is usually not a jack of all trades and may have a hard time when looking for sound and music. Apple's own GarageBand provides an easy way to create music using predefined loops or even one's own instruments. Another possibility is to find talented people who can help to create audio files. One of the places to look out for are the TIGSource forums—a place for independent game developers—which has a portfolio section at http://forums.tigsource.com/index.php?board=43.0 and a section that offers paid work at http://forums.tigsource.com/index.php?board=40.0.

Generating sound effects

Bxfr is a procedural sound generator which is often used in game jams. It is available online at http://www.bfxr.net/; the standalone versions for Windows and Mac OS X can be downloaded from this link as well. Its purpose is to generate 8-bit sound effects in just a few clicks:

Generating sound effects

First of all, we need to select a type, which we can then modify with several sliders such as the frequency or the length of the sound.

Once we are done, we can export the sound effect using the Export Wav button.

Learning about audio formats

Sparrow allows all audio files supported by iOS to be loaded. Some audio codecs support hardware-assisted decoding, while others don't.

The iOS devices contain specialized hardware that can handle the encoding and decoding of certain audio formats (for example, AIFC), thereby freeing up the CPU that would otherwise be required to handle these expensive operations. The drawback of the hardware-assisted approach is that only one file can be handled at a time. For example, you can't play background music and sound effects with it simultaneously.

For more information about how iOS handles audio playback, take a look at Apple's documentation at https://developer.apple.com/library/ios/documentation/audiovideo/conceptual/multimediapg/UsingAudio/UsingAudio.html.

The best formats for audio formats in Sparrow are AIFC and CAFF.

Let's see what they are:

· AIFC is a compressed Audio Interchange Format (AIFF) file. This is usually the best option for background music. There is one other thing to consider: if the audio playback is hardware-assisted (as it is in the case of AIFC), only one file can be played at a time.

· The Core Audio File Format (CAFF) is an uncompressed audio format. This format is best used for short sound effects.

Both these formats have the lowest footprint on the CPU. If application size is an issue, there is an unconventional way to solve this: some devices still only have mono speakers, so converting audio files to mono could be a valid option if there are a lot of sound files.

To convert audio files, the iOS SDK provides a command-line tool called afconvert. Assuming our audio file is called myAudioFile.wav, we can use the following examples:

· Convert to CAFF: The command to convert to CAFF is afconvert –f caff –d LE16 myAudioFile.wav

· Convert to AIFC: The command to convert to AIFC is afconvert –f AIFC –d ima4 myAudioFile.wav

Music and sound effects for our game

The necessary audio files are once again uploaded to our GitHub repository. In order to use them, download them from https://github.com/freezedev/pirategame-assets/releases/download/0.9/Audio_09.zip, extract the file, and copy the contents in our template. When copying the files to the project, we need to make sure that we add them to the target.

Adding audio playback

Now that we know about audio formats, we can generate sounds for ourselves if needed, and if we have the necessary files, we can play some audio.

Starting the audio engine

Before we can play any sounds, we need to start the audio engine.

Time for action – getting audio files to play

Perform the following steps to start the audio engine:

1. Open our Xcode project if it's not already open.

2. Switch to the Game.m file.

3. Inside the initializer, start the audio engine as shown; it should be one of the first few statements:

[SPAudioEngine start];

4. Add a dealloc method that stops the audio engine:

5. -(void) dealloc

6. {

7. [SPAudioEngine stop];

}

8. Run the example.

When we run this example in the simulator, we might see the following lines in the console:

Time for action – getting audio files to play

What just happened?

To play any audio file, we need to start the audio engine at the start of our application, which in our case, is the initializer from the Game class.

There are different operational modes for the audio engine, which influence how the iPod music app will behave when we run our game.

If the audio is muted, the game audio will be muted as well. This is the default operational mode; other modes include the game audio continue even when the device is muted or the iPod music mixes with the game audio. Take a look at what the latter will look like in code:

[SPAudioEngine start: SPAudioSessionCategory_AmbientSound];

For more through information, take a look at the Sparrow SPAudioEngine documentation at http://doc.sparrow-framework.org/v2/Classes/SPAudioEngine.html.

When we run this example, we get some information about the audio engine in the console.

Have a go hero

Currently, the audio engine starts and stops when the game starts or stops, respectively. It's also a good idea to start and stop the engine if the background and foreground events (such as applicationWillResignActive and applicationDidBecomeActive) are triggered.

Playing music in our scenes

Now that the audio engine is up and running, let's play the background music.

Time for action – playing music in our scenes

Perform the following steps to play background music in our scenes:

1. Open the Scene.h file.

2. Add an instance variable named backgroundMusic, which is a pointer to SPSoundChannel using the following line of code:

SPSoundChannel *backgroundMusic;

3. Declare a method called stop as follows:

-(void) stop;

4. Inside the Scene.m file, define the stop method with an empty body.

5. Update the showScene method in the SceneDirector.m file to fit the following block of code:

6. -(void) showScene:(NSString *)name

7. {

8. for (NSString* sceneName in _dict) {

9. ((Scene *) _dict[sceneName]).visible = NO;

10. [((Scene *) _dict[sceneName]) stop];

11. }

12. if (_dict[name] != nil) {

13. ((Scene *) _dict[name]).visible = YES;

14. [((Scene *) _dict[name]) reset];

15.

16. }

}

17. Switch to PirateCove.m.

18. Inside the initializer, add the following lines at the top:

19.SPSound *sound = [Assets sound:@"music_cove.aifc"];

20.backgroundMusic = [sound createChannel];

backgroundMusic.loop = YES;

21. Update the reset method to look like the following:

22.-(void) reset

23.{

24. [backgroundMusic play];

25.

26. _goldDamage = (150 + (50 * (World.level - 1)));

27. _dialogUpdateDamage.content.text = [NSString stringWithFormat:@"Increasing damage costs %d gold. Do you wish to proceed?", _goldDamage];

28.

29. _goldHitpoints = (200 + (75 * (World.level - 1)));

30. _dialogUpdateHitpoints.content.text = [NSString stringWithFormat:@"Increasing hitpoints costs %d gold. Do you wish to proceed?", _goldHitpoints];

31.

32. [self updateGoldTextField];

}

33. Implement the scene's stop method as follows:

34.-(void) stop

35.{

36. [backgroundMusic stop];

}

37. Run the example and you will see the following output. We can now hear the music in the background.

Time for action – playing music in our scenes

What just happened?

First of all, we added an instance variable (backgroundMusic) to hold the background music. The SPSound variable holds the data of a sound file while SPSoundChannel plays the sound itself, similar to the relationship between SPTexture and SPImage. It is recommended that you keep a reference to SPSoundChannel. This is required if we want to stop the playback sound for any reason whatsoever.

To allow us to have background music in multiple scenes, we need to stop the background music from the current scene and start the music from the next scene because we don't want to run into any nasty side effects. These side effects are that the first music file will use the hardware codec and the second one will use software decoding, thereby heavily impacting the performance of our game. Both music files will play, though.

If we want to stop the background music when we are in the scene, we can utilize the scene's reset method. Now, we wanted to do the same only when the scene is deactivated. We first declared the stop method for exactly this purpose in step 3 and implemented it as an empty method in the step afterwards. In the SceneManager class, we need to call the stop method of each scene when we are hiding the scene.

Inside the initializer of the PirateCove scene, we created a local SPSound variable that loads the music file through our asset management system. We then used the createChannel method and saved the result in the instance variable. We want to loop the music endlessly, so we set the loop property to YES.

In step 8, we updated the reset method to play the background music and in step 9, we overwrote the stop method and stopped the background music.

When we run this example now, we can hear the music playing in a loop.

Have a go hero

Now that the pirate cove scene has some background music, go ahead and give the battlefield some music.

Adding a sound effect

Our audio engine is up and running; we already know that it works because we have played some music, and now it's time to add the sound effects.

Time for action – sound effects in the pirate cove

To add sound effects to the pirate cove scene, perform the following steps:

1. Open the PirateCove.m file.

2. Update both the onUpdateDamage and onUpdateHitpoints methods to play a sound effect, as shown in the following code:

3. -(void) onUpdateDamage: (SPEvent *) event

4. {

5. World.damage = World.damage + (int) (World.damage / 10);

6. World.gold = World.gold - _goldDamage;

7. [self updateGoldTextField];

8.

9. [[Assets sound:@"powerup.caf"] play];

10.}

11.

12.-(void) onUpdateHitpoints: (SPEvent *) event

13.{

14. World.hitpoints = World.hitpoints + (int) (World.hitpoints / 5);

15. World.gold = World.gold - _goldHitpoints;

16. [self updateGoldTextField];

17.

18. [[Assets sound:@"powerup.caf"] play];

}

19. Run the example and you will see the following output. We can now hear a sound if we successfully upgrade our pirate ship.

Time for action – sound effects in the pirate cove

What just happened?

Inside the pirate cove scene, we added a sound effect to both the onUpdateDamage and the onUpdateHitpoints methods. We got the powerup file through the asset management system and then played the sound directly. This method is useful for short sounds and at places where we don't need to keep a reference to manipulate the playback of the audio channel afterwards.

Now, when we run this example, we can hear a sound effect once we successfully upgrade our ship.

Have a go hero

Go ahead and add the following sound effects in the battlefield:

· When a ship is hit (the hit method in the Ship class)

· When a ship shoots (the shoot method in the Ship class)

· When a ship gets destroyed (hit points getter in the Ship class)

Pop quiz

Q1. AAC audio files offer hardware-assisted encoding.

1. True

2. False

Q2. If SPSound only contains the sound data, which class should be used to play an audio file?

1. AVAudioSession

2. SPSoundChannel

3. SPAudio

Q3. To play any sounds at all, we need to initialize the audio engine.

1. True

2. False

Summary

In this chapter, we learned how to load and play audio files. Specifically, we covered data formats and the basic usage of audio in Sparrow.

Now that our game has some audio, let's polish our game—which is the topic of the next chapter.