Short sounds

May 5th, 2009 by Chris Leave a reply »

Related tutorials:

Sounds are very important to put some life into your application, usually the game.

What is the difference between short sounds and long sounds? Let’s say, you are making a game and there is a constantly looping (or changing the track once played) background music. This is certainly not a short sound and it will be discuss somewhere else. You can play a short sound once you press the button, hit the wall, an alert occurred, a weapon was used… This kind of sounds could also be played as a background music but there is one problem with playing few background musics on iPhone… The iPhone processor can deal only with one background music and many sounds, that’s why music played from your library on iPhone / iPod touch stops once any app starts to play background music.

Sounds cannot be longer the 30 seconds and you should convert them before adding to the project. How? Open Terminal application on your mac and use the afconvert:

/usr/bin/afconvert -f caff -d LEI16 input_file output_file

Example:

MBP-Krzysiek:~ Krzysiek$ /usr/bin/afconvert -f caff -d LEI16 /Users/Krzysiek/Desktop/samlpe\ music.mp3 /Users/Krzysiek/Desktop/samplemusic.caf
terminal
Please bear in mind that .caf aren’t like .mp3 – the lossless format, that’s why after conversion the sound file is usually bigger than original. That’s why you shouldn’t have original files in .mp3 as shown on example, but even you have .caf, convert it anyway. afconvert converts almost any sound format I know (but I don’t know many, I’m not DJ).
OK, your sound is ready to add to your project. Now in Xcode you need to write a class responsible for playing a sound. I will show you two ways: playing a sounds using:
  • SystemSound
  • AVAudioPlayer

SystemSound

SystemSound plays any sound without affecting the background music of your application or music from iPod. It doesn’t provide any volume control, user can control volume by changing the master volume of the device. Before you start to code, you need to add an AudioToolbox framework to your project (if you don’t know how: ctrl-press any existing .framework, Reveal in Finder and drag and drop the AudioToolbox.framework to the Frameworks group).

Add a new class (name it sounds) to your project, choose NSObject subclass, but in fact, it doesn’t metter, if you replace all code in header and implementation file with these provided by me:

sounds.h

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioServices.h>

@interface sounds : NSObject {
	SystemSoundID soundID;
}
-(id) initWithContentsOfFile:(NSString *)path;
-(void)play;
@end

sounds.m

#import "sounds.h"

@implementation sounds
-(id) initWithContentsOfFile:(NSString *)path {
	self = [super init];
	if (self != nil) {
		NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
		AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
	}
	return self;
}
-(void)play {
	AudioServicesPlaySystemSound(soundID);
}
-(void)dealloc {
	AudioServicesDisposeSystemSoundID(soundID);
	[super dealloc];
}
@end

Import sounds.h (#import “sounds.h”) to any class (for example game.h) that will call sounds class to play a short sound. If the sound is played many times (like in most cases) add in header the object:

	sounds *mySound;

or

	sounds *mySound1, *mySound2, *mySound3; // , *mySound4 ... *mySound(n)

or

	sounds *mySound[3];
Before any sound can be played you need to allocate it. While allocating you have to call the method initWithContentsOfFile and provide the path to the resource – sound file.
	mySound = [[sounds alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"myFunnySound" ofType:@"caf"]];
Now mySound object is ready to play myFunnySound.caf.
To play call the play method: [mySound play];. That’s all about SystemSounds.
Please note:
System Sounds can also toggle vibration, but it will be discussed in other tutorial.

AVAudioPlayer

AvAudioPlayer plays any sound also without affecting the background music of your application, but it terminates the music from iPod. It gives the user the ability to control the volume within the application (if you provide a slider or any other interface to adjust the volume), or by changing the master volume of the device. Before you can use AVAudioPlayer you need to add AVFoundation.framework to your project.

Please note:
Using AVAudioPlayer is much simpler than SystemSounds. I implemented a class to use SystemSounds, because I don’t like using such a long method names (AudioServicesPlaySystemSound) when they are called frequently. To play sound with AVAudioPlayer I need only 2-3 lines of code so writing a class to handle it is pointless and useless for me.

To prepare the sound you need to repeat almost the same steps I told in SystemSounds. Let’s add in the header file of your class an instruction to import AVAudioPlayer.h framework:

#import <AVFoundation/AVAudioPlayer.h>

And the AVAudioPlayer object with our sound:

	AVAudioPlayer *myAVsound;

To start, and assing the sound file you also need to provide a path to that resource:

	myAVsound = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"myFunnySound" ofType:@"caf"]  ] error:NULL];

The method to play this sound couldn’t be simpler:

	[myAVsound play];

… and to adjust the volume:

	myAVsound.volume = 0.6;

The volume can be adjusted also during the sound is being played.

Please note:
The given volume should be a number from range <0.0,1.0>
. When the volume=0, user won’t hear the sound at all (O RLY?). You could also set the volume=2.0 or 10.0 but be careful. Instead of the louder sound you can get an unbearable to here noise (especially when the sound is saved in low quality), it can be harmful to user’s ear, if he uses headset, or can damage the device’s speaker.

BTW:
AVAudioPlayer allows you to loop the sound (myAVsound.numberOfLoops = 2;).

Please note:

I’ve heard many problems with playing the sounds with iPhone Simulator, in other words, the project cannot be compiled to run on iPhone Simulator. I personally have this problem, but as long as I participate in iPhone Developer program. I guess (but I’m not sure) that is because of computer you use. I use MacBook Pro Mid/Late 2007 (MA895) 2.2 GHz. As long as I know, this problem doesn’t occur on MacBook Pros shipped with unibody enclosure.

That’s almost everything you need to know about short sounds. You can download the sample project below.It allows you to play a sound (included in the project) via SystemSound and via AVAudio Player with slider adjusting the volume.

screenshotsounds

xcodeproj

Download the project

Advertisement

14 comments

  1. heya! do you know where I can download the gremlins theme song (mp3)?, thank you..! Mike.

  2. There are a lot of people who do not pay any attention to RAM when they buy their laptops. They may be ignorant or perhaps plain negligent on this. But when the laptop works slowly or perhaps conks off in the middle of important tasks, they wonder as to what happened suddenly.

  3. jaga says:

    how to add a sounds to buttons please give me one demo applications
    and give me how to make slide show for image pics

    • Chris says:

      Slideshow requires new tutorial, don’t have time to do it now.

      Buttons and sounds?

      -(IBAction)button1Pressed {
      [mySoundButton1 play];
      }

      Regards
      Chris

  4. Micha says:

    Great site, just what i am looking for since two months!

    SoundEngine works well on the device (Ipod touch).
    But how can I route the sound to the internal speaker?
    I have posted this question in several forums but got no satisfying answer except “its simple and easy”. Apple Dev Center didnt help either. I hope you can help me.
    Thanks in advance!

    Micha

    • Chris says:

      Internal speaker? I don’t think it’s possible…

      • Micha says:

        Hello,

        My app works perfectly with headphones. Switching the sound effects to “speaker” results in playing the mail alert on the internal speaker instead of my sounds.
        I just need the buttons ov my app to click or beep, since the app is to be used without looking. Of course I can plug in a small speaker, but the internal speaker is more elegant.
        Sometimes I think Apple doesnt want the speaker to be used …

  5. demetriusb says:

    Great code. How would you add a pause to the same button?

    • Chris says:

      Well you could use the “if”.

      add in .h: bool isPlaying

      and in .m

      -(IBAction)buttonPressed {
      (isPlaying) ? [mySound pause] : [mySound play];
      isPlaying = !isPlaying;
      }

  6. Evan says:

    What about from a purely technical standpoint? I have some sounds that are ten times smaller in wav format. Are caff files more responsive to load/play, or is wav just as good on the iPhone?

    BTW, thanks for some really awesome tutorials here!

    • Chris says:

      Sorry Evan, but I can’t really help you no matter how hard I try.

      I usually convert any sound file to caff and even if it’s already caff I convert it again using the Terminal command. I try to avoid convertion only in one case, when I want to make my app to be smaller then 10MB. But usually the apps smaller then 10MB do not use so much memory, so it’s really not a big deal if you convert them to caff or not (wav). If the application grows – above 100MB for example, in my opinion there is no difference if the application weighs 100MB (with wav files) or 120 (with caff files).

  7. Evan says:

    Is there any advantage to caff over wav files when using SystemSound?

    • Chris says:

      Well, it’s difficult for me to say. I’m programmer, I don’t create music on my own. In my opinion wav is typical for Windows, and comparing wav to caff is almost like comparing .bmp to .png, but you should ask this question to musicians I guess…

Leave a Reply