Ok, I will be finishing up this series by showing you guys how to add basic audio to your game. Since this is a beginner tutorial, I won’t go into complex audio using OpenAL or Audio Queues. Today, we will just be playing short sounds (less than 30 seconds). This will be the easiest way to do audio if you don’t require any background music (I guess you could do a nasty hack and loop a 30 sec clip but that would be shameful
). The downfall of doing audio this way is only one audio file can be playing at a time. Ok, let’s get started… Make sure you are starting with the base code from the previous tutorial (either use yours or download a fresh copy). We will be using 2 sounds today, 1 for when the ball is hit and another for when someone scores a point.
Here are the sound files you will need to download for this tutorial:
Notice that all of the audio files have a .caf extension. This is the audio type all of your sound files must be in to be played by the iPhone. Luckily Apple has provided us a utility for converting audio to this format. You can read up on it here. It’s pretty straight forward, just open up a Terminal and type
/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}
Where {INPUT} is the path to your input audio file and {OUTPUT} is the file you want it to save it to with a .caf extension.
Adding the Audio Files To You Project
Start by downloading these files. Then drag them to your Resources Folder inside of your project. You may also want to add a subfolder called Audio to keep organized. Make sure you check the box to copy the files into your project’s directory.
Add The AudioToolbox.framework to Your Project
Since we need to call functions within this framework, we will need to add it to our project. The best way I have found to locate a framework on my mac is to search for it. Right Click on the Frameworks folder in your project and select Add -> Existing Frameworks. In the search box type AudioToolbox.framework and select the framework among the search results. (Make sure you have Computer selected to search your entire computer)
When you find it, click Add. We are now ready to start coding…
Add the Header Declarations
Open up iTennisViewController.h and add the following code.
First we see an import for the AudioServices.h. This is needed to call the functions required for us to play audio. Next, we declare 2 SystemSoundID’s. These are basically just Integers (could actually use an int instead but you’d get a warning). Next, open up iTennishViewController.m and add the following code to synthesize these variables.
Now let’s initialize our sounds objects. Go to the viewDidLoad method and add the following code.
Pretty straight forward. The first line gets the path of the audio file. The next line converts the path to a CFURLRef. Finally, we load that audio file and associate it with the given sound ID. Notice we pass &clappingFileID. This is a pass by reference and allows the AudioServicesCreateSystemSoundID method to modify this variable. We do the same thing to load the volley sound. Now, let’s play the sounds.
Playing The Sounds
It’s actually quite simple to play the sounds we have loaded. Simply call the AudioServicesPlaySystemSound method and pass it the soundID of the file you want to play. So to play the clapping sound when someone scores, add this code to your reset method.
Notice, we are passing the clappingFileID to indicate we want to play the clapping sound. Now, add the following code to gameLoop to play the racquet sound when someone hits the ball.
Pretty straight forward Right? Now click Build and Go and check out the game audio. That concludes this tutorial. If you have any questions or comments, feel free to leave them in the comments section of this post or write them to me on Twitter. You can also download the sample code here
Happy iCoding!








44 Comments
What is the difference between audioservices system sounds and avaudioplayers?
I have just recently started adding sounds and have been using avaudioplayers. What are the advantages and disadvantages of both
Brandon, great finish to the series! You are doing an awesome thing for the iPhone community! I really enjoy the professional content that your publishing! Keep up the good work.
Plus I’ve found some good ads on your posts and have clicked through a few of them. I recomend other people click on your ads too
Take care,
Erik
Great tutorials, big thanks
very nice tutorial, i have spent my time with playing audio files but now i saw how to do it
Thanks
First of all, thank you SO much for doing these tutorials! They´ve been extremely helpful. Wonderful work!
I´m having trouble with part 4 here. It compiles and runs – and crashes (showing a Mac error message) before the splash screen is shown. I´m not sure what I´m doing wrong. I´m very new to this, but does it matter which of the AudioToolbox frameworks I use?
Hey, great tutorial!!
@Matthijs: I don’t think it matters to much which framework you choose. The reason I guess why your game is crashing is because you need to change the filename of the sounds. I guess yours is named something like “tennis-volley-01.caf”. It should be “Tennis Volley 01.caf”. Just as it is in the viewDidLoad method.
Simply outstanding……….. last night I was thinking of including audio in my game, and early today I saw your post…………..thanx
Though I have not implemented it, but still thanx in advance
Simply perfect, Thanks!
I cannot get sound on my iPhone, in the simulator it works perfectly.
My iPhone is on 2.2.1, I have tried compiling for several fw <= 2.2.1 but to no avail.
Anyone have similar problems?
I am also not able to hear sound on the iPhone but in the simulator you can hear the sound.
I cannot hear anything on the iPhone either. Works fine in simulator.
WOW, I came back to post the same issue, that I am not getting sound in iPhone, looks like am a little late, but not late for the solution……………….
Please help us out……….. Thanking in advance
Thanks, Tippi!
Great tutorial… I’ve been following the others in your series.
Just an FYI – You can play other types of sounds on an iPhone besides *.caf. I believe it handles *.wav and *.au as well. You just need to specify ofType:@”wav” for example.
Thanks, mikegpitt! I found out I can hear .wav files, but not .caf files on the iPhone – though they all play in the simulator.
Great tutorial!
I’m trying to add a settings view to my game so the user can have the ability to turn off sound and/or set difficulty level. This is something I’ve been able to do with other apps but with the splash screen, I find it difficult to do.
How can I add a subview to iTennisViewController?
Thanks in advance…perhaps this can be another tutorial!
I could not get the sound to play at all. No errors, no crashes, just silence from both the simulator and the device.
Additional reading on the topic led me try converting the files to AIFFs, and using those. This worked on the device, but not the simulator.
Anyone have any guidance they can offer? Thanks.
i cant hear even .wav file ,what is the reason ?
anyone can help me……
great tutorial thanks – i’ve been trying to add some of my own sounds – they’re 16bit caf format (i found 24bit doesn’t work) but only the shortest ones will play – does anyone know the limit of the length/filesize or even the total number of sounds goes?
i also found when changing the sounds around i could not fully replace old sounds without using new filenames (and therefore having to edit the code relating to them) – it would somehow be playing older versions of the sounds even though i thought i’d completely deleted them from my project and my hard drive
senthilmuthu;
can you play the wav file in the finder? – it might just be something to do with your system audio prefs, or otherwise the file itself (check the waveform in an audio editor)
hey,
i’m current working on an application and needed to put append text to label while user click buttons. That is for example, i have 3 buttons named 1, 2, and 3. If i click button 1, the label would display as 1. If i click label 2, then the label would display 12 (instead of only 2). And if i click 3, then it would display me 123. Or instead if i start with 2, then 3, then 1, then the label would finally (on the 3rd click) display 231. Is there anyway to do it? I’v been struggling with this for 3 days already.
Also, I have another problem where I have a pointer that i set the label as label.text = thisPointer. Is there anyway to make this pointer to an integer as i needed to compare its value to another integer. Please help me
Thanks alot,
Varut
Thank you so much for these tutorials! It is especially useful that you use the same program for all of them giving the reader a sense of continuum.
I’m actually still waiting for my mac from Apple Store to get started with iPhone programming, but your tutorials have given me lots of confidence and energy. I hope you can write even more parts, maybe on programming the 3D-version of iTennis. Just letting you know that people read and appreciate you work!
I was also having a similar issue with the sounds not playing. A couple of changes I made and things worked:
1) Make sure audio files are in a subdirectory of the Resources folder: Resources/Audio/ (this is how the downloaded code has the files saved.)
2) I couldn’t get the .caf files to work, so I tried a couple of my own .aiff files. You’ll need to change the ofType:@”caf” –> ofType:@”aiff”
Thanks icodeblog for the tutorial! The clear examples really helps.
@Jason, I personally think that AVAudioPlayer is much much better because it allows for much longer sound files, it allows you to start stop and pause the sound, it calls delegate methods when the sound is interrupted by the system, it allows you to play multiple sounds simultaneously and control the relative level of the sounds, you can tell in code if the sound is playing, and so on and so forth. The only downside to it is that is only works with 2.2 and later.
@JayReid, make a subclass of UIViewController and add a subview to it that is from an IBOutlet. Then show it using presentModalViewController: animated:
@Dave Ramsey, I had this same problem. Look in the console when the program runs and it should be giving an error message that has a file path in some quicktime folder (somewhere in Library). Temporarily remove this file from that folder and it should work. For me the problem file was livetype.component or something like that.
For the people who are having the problem with the sound playing in the simulator but not on the device, it is probably because you didn’t check off “Copy Items to Destination’s Group Folder (if needed)” when you added the sound files to the project. FYI – do not check this off when adding frameworks to the project! It will severely mess it up and it will take forever to find the problem!
Hi,
I’m trying to add a preferences window to iTennis to set game speed and enable/disable sounds, but I’m not sure if I should be loading the new view from the iTennis App Delegate or the iTennisViewController. It seems I need to do this through the delegate so that I can have the window display the view above everything else. Is the delegate the proper way to do this?
Thanks!
Anyone know of a place to download generic sound effects?
The issue of sound on the real device is still present and i actually found the problem; for some reason all project caf files are not playable on real device; i replace with other caf files and it works perfectly.
so is there an “official” fix for the sound not working on the device but does work in the sim?
Awesome Tutorial again man!
the “official” fix is to make your own caf files, as the ones provided have issues.
Wow.. great tutorial.. thanks a lot!
Hi, this is an excellent tutorial, but i just wanna ask a doubt which i hav can i use a slider to control the volume of the effects as played. I mean here its AudioServices is being used to play the effect, using the same can i control its volume. Is there a option in AudioServices to control the volume played by it.
Please help me to solve my doubt i hav one trouble in doing so.
Thanks, short, effective tutorial.
Maybe you could insert the Audiotoolbox.framework’s path on your computer. I found it in two different place on my MacBook.
This my code my images disappear and I don’t know what to do yeah I’m a noob
//
// iTennisViewController.m
// iTennis
//
// Created by Warren Shen on 1/12/10.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//
#import “iTennisViewController.h”
#define kScoreToWin 5
#define kCompMoveSpeed 10
#define kGameStateRunning 1
#define kGameStatePaused 2
#define kBallSpeedX 10
#define kBallSpeedY 15
@implementation iTennisViewController
@synthesize ball,racquet_yellow,racquet_green,player_score,computer_score,gameState,ballVelocity,tapToBegin;
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.gameState =kGameStatePaused;
ballVelocity =CGPointMake(kBallSpeedX,kBallSpeedY);
[NSTimer scheduledTimerWithInterval:0.05 target:self selector:@selector(gameLoop) userInfo:nil repeats:YES;
}
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(gameState == kGameStatePaused) {
tapToBegin.hidden = YES;
gameState = kGameStateRunning;
}else if(gameState == kGameStateRunning) {
[self touchesMoved:touches withEvent:event];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
CGPoint xLocation = CGPointMake(location.x,racquet_yellow.center.y);
racquet_yellow.center = xLocation;
}
//Begin Simple AI
if(ball.center.y<= selff.view.center.y) {
if(bal.center.x racquet_green.center.x) {
CGPoint compLocation = CGPointMake(racquet_green.center.x + kGameMoveSpeed, racquet_green.center.y);
racquet_green.center = compLocation;
}
}
//Begin scoring Game Logic
if(ball.center.y =kScoreToWin)];
}
if(ball.center.y > self.view.bounds.size.height) {
computer_score_value++;
[self reset:(computer_score_value >=kScoreToWin)];
}
-(void)reset:(BOOL) newGame {
self.gameState = kGameStatePaused;
ball.center =self.view.center;
if(newGame) {
if(computer_score_value >player_score_value) {
tapToBegin.text = @”Computer Wins!”;
} else {
tapToBegin.text =@”Player Wins!”;
}
computer_score_value=0;
player_score_value=0;
} else {
tapToBegin.text = @”Tap to Begin”;
}
player_score.text = [NSString stringWithFormat:@"%d",player_score_value];
computer_score.text = [NSString stringWithFormat:@"%d",computer_score_value];
}
-(void) gameLoop {
if(gameState ==kGameStateRunning) {
ball.center = CGPointMake(ball.center.x + ballVelocity.x , ball.center.y + ballVelocity.y);
if(ball.center.x > self.view.bounds.size.width || ball.center.x self.view.bounds.size.height || ball.center.y <0) {
ballVelocity.y = -ballVelocity.y;
}
} else {
if(tapToBegin.hidden) {
tapToBegin.hidden = NO;
}
}
}
if(CGRectIntersectsRect(ball.frame,racquet_yellow.frame)) {
if(ball.center.y racquet_green.center.y) {
ballVelocity.y = -ballVelocity.y;
}
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn’t have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren’t in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[ball release];
[racquet_green release];
[racquet_yellow release];
[player_score release];
[tapToBegin release];
}
@end
nvm that ^
but in viewcontroller.m i keep having an error that says ” expected specifier-qualifier-list before ‘IBoutlet’ pls help its says that right under import “itennisviewcontroller”
nvm all of it I fixed up the code but now my iTennis.app folder is red and when I run the thing it closes unexpectedly
Hey guys short of creating your own new caf files, I found a quick way to get this tutorial working on my device(3gs) and simulator. Not sure why it works but I ran the files through the afconvert again and then everything was good. I am also on snow leopard. Once I hear back that this works for others we should be able to call it official.
same format as his example; note that LEI is a capital i.
afconvert -f caff -d LEI16 clapping-crowd-studio-01.caf clapping-crowd-studio-02.caf
Hi, excuse, my english is poor…
i havent the “iphone device 2.2″ , i have the iphone device 2.2.1, the 3.0, the 3.1 and the 3.1.2 .
My error message is :
Code Sign error: The identity ‘iPhone Developer’ doesn’t match any valid certificate/private key pair in the default keychain
i had tried to change the iphone device to all combinations in my possibilities (2.2.1 , 3.0, 3.1, 3.1.2 ) but the error persists.
ok, so i was killing myself trying to figure out why my sounds play on simulator, but not on my iPhone, and guess what, my phone was in vibrate mode. so, make sure your phone is not in vibrate mode.
Thanks tons for the tutorial! It’s helped me a lot to get over the initial learning curve here…really appreciate your sharing it.
for some reason after i hit build and run it just stops loading and wont run the game and the problem is my
NSString *clapPath = [[NSBundle mainBundle] pathForResource:@”Clapping Crowd Studio 01″ ofType:@”caf”];
CFURLRef clapURL = (CFURLRef ) [NSURL fileURLWithPath:clapPath];
AudioServicesCreateSystemSoundID (clapURL, &clappingFileID);
NSString *volleyPath = [[NSBundle mainBundle] pathForResource:@”Tennis Volley 01″ ofType:@”caf”];
CFURLRef volleyURL = (CFURLRef ) [NSURL fileURLWithPath:volleyPath];
AudioServicesCreateSystemSoundID (volleyURL, &volleyFileID);
part because if i make it a comment it finishes loading and runs the game as usual but when its not a comment it just stops dunno why can some1 help?
@Opent – read tippis post about making sure the file name actually matches the reference that you use. So the file name of the volley sound should be “Tennis Volley 01.caf” not tennis-volley-01.caf”.
I keep getting a “Passing argument 2 of ‘pathForResource:ofType’ from incompatible pointer type.
Mind telling me what that’s about? O.o
nvm, solved it. Damn typos…
I only had elementary knowledge C this tutorial helped in to proceed further and learn objective – C. It was good. And it all worked thanks so much
Great tutorials. Thanks a lot!!!!
Also thanks to the guys writing the helpful comments.
2 Trackbacks
[...] iPhone Game Programming Tutorial Part 4 – Basic Game Audio [...]
[...] I bookmark a maybe useful resource explaining how to play sounds within an iPhone application. This link from [...]