This is part of an ELC Tech Network

iPhone Game Programming Tutorial Part 4 – Basic Game Audio

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.

screenshot_01

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)

screenshot_02

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.

screenshot_11

Advertisement

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.

screenshot_09

Now let’s initialize our sounds objects.  Go to the viewDidLoad method and add the following code.

screenshot_12

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.

screenshot_14

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.

screenshot_15

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!

This entry was posted in iPhone Game Programming, iPhone Programming Tutorials and tagged , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

44 Comments

  1. Jason
    Posted May 4, 2009 at 7:48 pm | Permalink

    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

  2. Posted May 4, 2009 at 10:38 pm | Permalink

    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

  3. zynaps
    Posted May 5, 2009 at 12:18 am | Permalink

    Great tutorials, big thanks :)

  4. Posted May 5, 2009 at 1:36 am | Permalink

    very nice tutorial, i have spent my time with playing audio files but now i saw how to do it

    Thanks

  5. Matthijs
    Posted May 5, 2009 at 5:50 am | Permalink

    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?

  6. tippi
    Posted May 5, 2009 at 12:46 pm | Permalink

    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.

  7. Posted May 5, 2009 at 6:51 pm | Permalink

    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 ;)

  8. Sakery
    Posted May 6, 2009 at 2:26 am | Permalink

    Simply perfect, Thanks!

  9. Mads
    Posted May 6, 2009 at 8:11 pm | Permalink

    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?

  10. Posted May 6, 2009 at 8:24 pm | Permalink

    I am also not able to hear sound on the iPhone but in the simulator you can hear the sound.

  11. Sounder
    Posted May 7, 2009 at 12:09 pm | Permalink

    I cannot hear anything on the iPhone either. Works fine in simulator.

  12. Posted May 8, 2009 at 1:37 am | Permalink

    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 ;)

  13. Matthijs
    Posted May 8, 2009 at 4:09 am | Permalink

    Thanks, Tippi!

  14. mikegpitt
    Posted May 8, 2009 at 2:23 pm | Permalink

    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.

  15. Matthijs
    Posted May 11, 2009 at 7:54 am | Permalink

    Thanks, mikegpitt! I found out I can hear .wav files, but not .caf files on the iPhone – though they all play in the simulator.

  16. JayReid
    Posted May 13, 2009 at 9:46 pm | Permalink

    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!

  17. Dave Ramsey
    Posted May 18, 2009 at 5:38 pm | Permalink

    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.

  18. senthilmuthu
    Posted May 20, 2009 at 12:35 am | Permalink

    i cant hear even .wav file ,what is the reason ?
    anyone can help me……

  19. apeshake
    Posted May 21, 2009 at 9:17 am | Permalink

    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)

  20. Varut
    Posted May 26, 2009 at 11:16 am | Permalink

    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

  21. Tommi
    Posted June 9, 2009 at 9:12 am | Permalink

    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!

  22. Posted June 10, 2009 at 3:06 am | Permalink

    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.

  23. anonymous
    Posted July 17, 2009 at 11:01 am | Permalink

    @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!

  24. Posted July 24, 2009 at 5:55 pm | Permalink

    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!

  25. td
    Posted July 29, 2009 at 11:13 pm | Permalink

    Anyone know of a place to download generic sound effects?

  26. ozlbinfo
    Posted August 8, 2009 at 4:06 am | Permalink

    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.

  27. ThinkMud
    Posted August 25, 2009 at 9:56 pm | Permalink

    so is there an “official” fix for the sound not working on the device but does work in the sim?

    Awesome Tutorial again man!

  28. T
    Posted September 3, 2009 at 2:21 pm | Permalink

    the “official” fix is to make your own caf files, as the ones provided have issues.

  29. Nirav
    Posted November 7, 2009 at 5:41 pm | Permalink

    Wow.. great tutorial.. thanks a lot!

  30. Praveen
    Posted December 11, 2009 at 6:18 am | Permalink

    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.

  31. Posted January 2, 2010 at 8:37 am | Permalink

    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.

  32. Nick
    Posted January 13, 2010 at 6:23 pm | Permalink

    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

  33. Nick
    Posted January 13, 2010 at 6:37 pm | Permalink

    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”

  34. Nick
    Posted January 13, 2010 at 7:01 pm | Permalink

    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

  35. rookie
    Posted January 28, 2010 at 2:05 am | Permalink

    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

  36. Antonio
    Posted February 5, 2010 at 6:07 pm | Permalink

    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.

  37. Posted February 8, 2010 at 11:20 pm | Permalink

    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. :)

  38. Eric
    Posted February 11, 2010 at 12:51 pm | Permalink

    Thanks tons for the tutorial! It’s helped me a lot to get over the initial learning curve here…really appreciate your sharing it.

  39. Opent
    Posted February 11, 2010 at 9:38 pm | Permalink

    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?

  40. Sam
    Posted February 26, 2010 at 2:43 am | Permalink

    @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”.

  41. Michael
    Posted March 12, 2010 at 10:52 pm | Permalink

    I keep getting a “Passing argument 2 of ‘pathForResource:ofType’ from incompatible pointer type.

    Mind telling me what that’s about? O.o

  42. Michael
    Posted March 12, 2010 at 10:53 pm | Permalink

    nvm, solved it. Damn typos… :P

  43. Shubhojit
    Posted March 16, 2010 at 5:43 am | Permalink

    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

  44. Andy
    Posted March 16, 2010 at 8:24 pm | Permalink

    Great tutorials. Thanks a lot!!!!
    Also thanks to the guys writing the helpful comments.

2 Trackbacks

  1. [...] iPhone Game Programming Tutorial Part 4 – Basic Game Audio [...]

  2. By OOgtech.org » Putting a Game together 5 – Audio on December 13, 2009 at 11:45 am

    [...] I bookmark a maybe useful resource explaining how to play sounds within an iPhone application. This link from [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">