Playing backgroud music

May 9th, 2009 by Chris Leave a reply »

Related tutorials:

I’ve already told you how to play short sounds in your game / application. Now it’s time to play some music in the background. Although using one type of short sounds , doesn’t stop the iPod playback, adding the background music will turn iPod off.

In fact using AVAudioPlayer you can also play background music, so, in other words AVAudioPlayer can play longer sounds, not only those limited to 30 seconds. Here is the code again (remember to add a framework: AVFoundation.framework):

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

The above code will simply play the background music [backgroundMusic.caf]. But it will play it only once. You could use NSTimer to play it several times – call [myAVsound play].

GBMusicTrack

I would like to present you very nice class – GBMusicTrack, written by Jake Peterson (aka AnotherJake). You can find more info herePlease note, that you can play only one background music at time using this class, the second and any next track can be played, once you stopped playing the previous.

GBMusicTrack.h:

//
//  GBMusicTrack.h
//  GameBase
//
//  Created by Jake Peterson (AnotherJake) on 7/6/08.
//  Copyright 2008 Jake Peterson. All rights reserved.
//

#import <UIKit/UIKit.h> // IN ORIGINAL FILE <Cocoa/Cocoa.h>
#import <AudioToolbox/AudioQueue.h>
#import <AudioToolbox/AudioFile.h>

#define NUM_QUEUE_BUFFERS	3

@interface GBMusicTrack : NSObject
{
	AudioFileID						audioFile;
	AudioStreamBasicDescription		dataFormat;
	AudioQueueRef					queue;
	UInt64							packetIndex;
	UInt32							numPacketsToRead;
	AudioStreamPacketDescription	*packetDescs;
	BOOL							repeat;
	BOOL							trackClosed;
	AudioQueueBufferRef				buffers[NUM_QUEUE_BUFFERS];
}

- (id)initWithPath:(NSString *)path;
- (void)setGain:(Float32)gain;
- (void)setRepeat:(BOOL)yn;
- (void)play;
- (void)pause;

// close is called automatically in GBMusicTrack's dealloc method, but it is recommended
// to call close first, so that the associated Audio Queue is released immediately, instead
// of having to wait for a possible autorelease, which may cause some conflict
- (void)close;

extern NSString	*GBMusicTrackFinishedPlayingNotification;

@end

GBMusicTrack.m

//
//  GBMusicTrack.m
//  GameBase
//
//  Created by Jake Peterson (AnotherJake) on 7/6/08.
//  Copyright 2008 Jake Peterson. All rights reserved.
//

#import "GBMusicTrack.h"

static UInt32 gBufferSizeBytes = 0x10000; // 64k

NSString *GBMusicTrackFinishedPlayingNotification = @"GBMusicTrackFinishedPlayingNotification";

@interface GBMusicTrack (InternalMethods)

static void BufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef buffer);
- (void)callbackForBuffer:(AudioQueueBufferRef)buffer;
- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer;

@end

@implementation GBMusicTrack

#pragma mark -
#pragma mark GBMusicTrack

- (void)dealloc
{
	[self close];
	[super dealloc];
}

- (void)close
{
	// it is preferrable to call close first, before dealloc if there is a problem waiting for
	// an autorelease
	if (trackClosed)
		return;
	trackClosed = YES;
	AudioQueueStop(queue, YES);
	AudioQueueDispose(queue, YES);
	AudioFileClose(audioFile);
}

- (id)initWithPath:(NSString *)path
{
	UInt32		size, maxPacketSize;
	char		*cookie;
	int			i;

	if(!(self = [super init])) return nil;
	if (path == nil) return nil;

	// try to open up the file using the specified path
	if (noErr != AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:path], 0x01, kAudioFileCAFType, &audioFile))
	{
		NSLog(@"GBMusicTrack Error - initWithPath: could not open audio file. Path given was: %@", path);
		return nil;
	}

	// get the data format of the file
	size = sizeof(dataFormat);
	AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &size, &dataFormat);

	// create a new playback queue using the specified data format and buffer callback
	AudioQueueNewOutput(&dataFormat, BufferCallback, self, nil, nil, 0, &queue);

	// calculate number of packets to read and allocate space for packet descriptions if needed
	if (dataFormat.mBytesPerPacket == 0 || dataFormat.mFramesPerPacket == 0)
	{
		// since we didn't get sizes to work with, then this must be VBR data (Variable BitRate), so
		// we'll have to ask Core Audio to give us a conservative estimate of the largest packet we are
		// likely to read with kAudioFilePropertyPacketSizeUpperBound
		size = sizeof(maxPacketSize);
		AudioFileGetProperty(audioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
		if (maxPacketSize > gBufferSizeBytes)
		{
			// hmm... well, we don't want to go over our buffer size, so we'll have to limit it I guess
			maxPacketSize = gBufferSizeBytes;
			NSLog(@"GBMusicTrack Warning - initWithPath: had to limit packet size requested for file path: %@", path);
		}
		numPacketsToRead = gBufferSizeBytes / maxPacketSize;

		// will need a packet description for each packet since this is VBR data, so allocate space accordingly
		packetDescs = malloc(sizeof(AudioStreamPacketDescription) * numPacketsToRead);
	}
	else
	{
		// for CBR data (Constant BitRate), we can simply fill each buffer with as many packets as will fit
		numPacketsToRead = gBufferSizeBytes / dataFormat.mBytesPerPacket;

		// don't need packet descriptsions for CBR data
		packetDescs = nil;
	}

	// see if file uses a magic cookie (a magic cookie is meta data which some formats use)
	AudioFileGetPropertyInfo(audioFile, kAudioFilePropertyMagicCookieData, &size, nil);
	if (size > 0)
	{
		// copy the cookie data from the file into the audio queue
		cookie = malloc(sizeof(char) * size);
		AudioFileGetProperty(audioFile, kAudioFilePropertyMagicCookieData, &size, cookie);
		AudioQueueSetProperty(queue, kAudioQueueProperty_MagicCookie, cookie, size);
		free(cookie);
	}

	// allocate and prime buffers with some data
	packetIndex = 0;
	for (i = 0; i < NUM_QUEUE_BUFFERS; i++)
	{
		AudioQueueAllocateBuffer(queue, gBufferSizeBytes, &buffers[i]);
		if ([self readPacketsIntoBuffer:buffers[i]] == 0)
		{
			// this might happen if the file was so short that it needed less buffers than we planned on using
			break;
		}
	}
	repeat = NO;
	trackClosed = NO;
	return self;
}

- (void)setGain:(Float32)gain
{
	AudioQueueSetParameter(queue, kAudioQueueParam_Volume, gain);
}

- (void)setRepeat:(BOOL)yn
{
	repeat = yn;
}

- (void)play
{
	AudioQueueStart(queue, nil);
}

- (void)pause
{
	AudioQueuePause(queue);
}

#pragma mark -
#pragma mark Callback

static void BufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef buffer)
{
	// redirect back to the class to handle it there instead, so we have direct access to the instance variables
	[(GBMusicTrack *)inUserData callbackForBuffer:buffer];
}

- (void)callbackForBuffer:(AudioQueueBufferRef)buffer
{
	if ([self readPacketsIntoBuffer:buffer] == 0)
	{
		// End Of File reached, so rewind and refill the buffer using the beginning of the file instead
		packetIndex = 0;
		[self readPacketsIntoBuffer:buffer];

		// if not repeating then we'll pause it so it's ready to play again immediately if needed
		if (!repeat)
		{
			AudioQueuePause(queue);

			// we're not in the main thread during this callback, so enqueue a message on the main thread to post notification
			// that we're done, or else the notification will have to be handled in this thread, making things more difficult
			[self performSelectorOnMainThread:@selector(postTrackFinishedPlayingNotification:) withObject:nil waitUntilDone:NO];
		}
	}
}

- (void)postTrackFinishedPlayingNotification:(id)object
{
	// if we're here then we're in the main thread as specified by the callback, so now we can post notification that
	// the track is done without the notification observer(s) having to worry about thread safety and autorelease pools
	[[NSNotificationCenter defaultCenter] postNotificationName:GBMusicTrackFinishedPlayingNotification object:self];
}

- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer
{
	UInt32		numBytes, numPackets;

	// read packets into buffer from file
	numPackets = numPacketsToRead;
	AudioFileReadPackets(audioFile, NO, &numBytes, packetDescs, packetIndex, &numPackets, buffer->mAudioData);
	if (numPackets > 0)
	{
		// - End Of File has not been reached yet since we read some packets, so enqueue the buffer we just read into
		// the audio queue, to be played next
		// - (packetDescs ? numPackets : 0) means that if there are packet descriptions (which are used only for Variable
		// BitRate data (VBR)) we'll have to send one for each packet, otherwise zero
		buffer->mAudioDataByteSize = numBytes;
		AudioQueueEnqueueBuffer(queue, buffer, (packetDescs ? numPackets : 0), packetDescs);

		// move ahead to be ready for next time we need to read from the file
		packetIndex += numPackets;
	}
	return numPackets;
}

@end

If you don’t understand what every line of this code means, don’t worry. Here is the simple instruction how to use it:

GBMusicTrack *backgroundMusic = [[GBMusicTrack alloc] initWithPath:[[NSBundle mainBundle] pathForResource:@"backgroundMusic" ofType:@"caf"]];
[backgroundMusic setRepeat:YES]; // or NO if you want to play it only once
[backgroundMusic setGain:1.0]; // volume
[backgroundMusic play];

Remember to import not only GBMusicTrack.h to the class with above lines of code, but also to add AudiToolbox.framework. As you see using GBMusicTrack class is quite simple, setRepeat:YES/NO method allows you to decide if you want your music to loop constantly, setGain to adjust the volume (remember: try to avoid setting the volume louder than 1.0) and play to start playing.

Please note: compile for the version 2.2 or higher!

Please note: many people complains that anything from this tutorial doesn’t work on iPhone Simulator. Don’t worry, it works on real device.

Playing the next track using GBMusicTrack:

As I told before, this class allows you to play one track at the time. To play next, you have to call the close method and initialize it again:

	[backgroundMusic close];
	[backgroundMusic initWithPath:[[NSBundle mainBundle] pathForResource:@"nextTrack" ofType:@"caf"]];

You can download my sample project: – my music controller I’ve written using the GBMusicTrack. You can fade the music in / out, play and pause and set the volume.

musiccontrollerscreenshot

xcodeproj

Download the project

Advertisement

41 comments

  1. Phony Hairpiece http://synthetic-wigs.dolabuy.com/ Net their wide selection of name Fake Pelt Wigs, Big Synthetic Wigs, Price Man made Hairpieces, Swift Fake Wigs, Flip False Hairpiece but more

  2. mbtfroorzsoj says:

    Three young women were arrested in connection with the attack in the early hours of December 30 but police say they are still hunting suspects for five earlier incidents.
    [url=http://www.christianboutique.net]christian louboutin pas cher[/url]
    This means that once a year my mum, stepmother (we have a super cosy situation), sister and I get into an over-excited, over-fake-tanned flap about attending the White Tie and Tiara ball.
    " So which exercises should we be doing instead? All the trainers advise picking those which use a wider range of muscle groups.
    [url=http://www.christianlouboutinstivali.org/jimmy-choo-c-11.html]Jimmy Choo[/url]
    Housing and constructionTo help first-time buyers, a mortgage indemnity scheme is aimed at helping up to 100,000 buyers of new homes with a 5% deposit.
    The Office of Fair Trading estimates a third of the UK’s water, telecoms, energy and transport networks are now foreign-owned.
    http://www.occhialidasoleitalia.com
    "Ms Munro, 30, a single mother, hid for hours in a doorway shielding Cam’ron’s eyes as the rioters rampaged around them and the fire destroyed almost all their possessions.

  3. OmiceabileVam says:

    [url=http://www.nikefreerunsdk.com]nike free run[/url]

    http://www.nikefreedansk.com

  4. HeerGraiple says:

    [url=http://www.botasuggmadrid.eu]ugg el corte ingles[/url]

    http://www.botasuggmadrid.eu

  5. porn watch says:

    teen porn watch ğ

  6. porn watch says:

    teen porn watch zz

  7. Nick says:

    Thanks a lot for sharing this. I have never thought that surfing online can be so much beneficial and entertained in a good shape. I feel really happy and grateful for providing me with such priceless sound track. All are good here simply best. I want such article again and again http://www.charmhandbags.com

  8. Yuc says:

    Hi,
    Hope someone can reply on this thread, I found quite useful this piece of code, very interesting but I need to go a little bit further manipulating the raw data of the audio file.
    So my question is, In which line of code of the GBMusicTrack.m can I manipulate the raw data of the audio file?
    I need to do that because im using this code as part of a parametric filter graph program for the iphone.

    Hope someone can help me on this.

  9. Nick says:

    Resources much like the one anyone reveal here are going to be very cooperative in my opinion! I will certainly post one of the links to this page on our blog. More than likely my guests will quickly realize that quite significant.
    http://www.backpackunion.com

  10. Hi there, just wanted to mention, I loved this blog post. It was funny. Keep on posting!||

  11. Highly useful information. Thanks

  12. Great post it is surely. I have been waiting for this information.

  13. Very interesting entry, I look forward to the next! Thx for share

  14. This article was helpful but, more details would be great.

  15. And alright, Aol. was radical even by my standards but maybe it ai notall undesirable. There may be some type of unique signature there. The vital debate about Wolff Olins credibility stays a mystery to me even though. I have continually admired their get the job done. Wonderful occupation Fresh! See you inside new year!

  16. Andy K says:

    It is really a great and useful piece of info. I am satisfied that you simply shared this helpful information with us. Please keep us up to date like this. Thank you for sharing.

  17. 3 Days Diet says:

    I know this if off topic but I’m looking into starting my own blog and was wondering what all is required to get setup? I’m assuming having a blog like yours would cost a pretty penny? I’m not very web smart so I’m not 100% positive. Any tips or advice would be greatly appreciated. Many thanks

  18. With havin so much content and articles do you ever run into any problems of plagorism or copyright infringement? My blog has a lot of unique content I’ve either written myself or outsourced but it looks like a lot of it is popping it up all over the web without my agreement. Do you know any methods to help reduce content from being ripped off? I’d definitely appreciate it.

  19. Hmm is anyone else having problems with the pictures on this blog loading? I’m trying to figure out if its a problem on my end or if it’s the blog. Any feed-back would be greatly appreciated.

  20. Please let me know if you’re looking for a writer for your site. You have some really great posts and I think I would be a good asset. If you ever want to take some of the load off, I’d absolutely love to write some content for your blog in exchange for a link back to mine. Please blast me an email if interested. Regards!

  21. Do you mind if I quote a couple of your articles as long as I provide credit and sources back to your weblog? My blog is in the exact same area of interest as yours and my users would truly benefit from some of the information you present here. Please let me know if this alright with you. Many thanks!

  22. sport tv net says:

    Great website you have here but I was wondering if you knew of any community forums that cover the same topics discussed in this article? I’d really love to be a part of online community where I can get advice from other experienced individuals that share the same interest. If you have any suggestions, please let me know. Bless you!

  23. I have been following your website for four days now and I should tell you I get tons advantages from your article. and now how I can get news replace out of your website?

  24. its really nice to read ha see about the play bagraund music
    i hope that you will keep it up

  25. Lue Bannett says:

    Always looking for new ideas to encourage my knowledge learning. I dare say I have quite some way to go after going through your article.

  26. Evana says:

    I can play background sound only for 1 second
    I did whatever u said.
    can u tell me wheres the fault.

  27. Yasir says:

    hello , thanks for this great tutorial ….
    i want to play ipod library music in background using this code , is it possible to do it , if so , then please tell me…..

    • Chris says:

      You certainly have access to iPod music since 3.0, but so far I’ve never need to implement it, as long as I’m not using it anywhere in my code.

      But I guess in some time, I will publish it, because I’m planning to create Bluetooth application to send music.

  28. Karl says:

    To make it loop forever, do this:

    myAVsound.numberOfLoops = -1;

    If you want it to be ready to play instantly, do this (note: this will reserve the audio hardware):

    [myAVsound prepareToPlay];

    AVAudioPlayer also supports volume control, audio level metering, streaming from any URL, and supports all file formats that the iPod player supports.

  29. monk says:

    Hi, whenever I use GBMusic, I seem to get a memory leak. Have you tried using Instrument to see what happens when you play a music using GBMusic? Any idea as to how I can solve this?

    Really stuck…

    Thx!

    • Chris says:

      Hi, I’ve never checked, but Apple has not rejected my app because of it so I guess it’s very small leak, moreover you can only use one gbmusic object so the leaks caused by this class don’t grow.

      If you don’t like it try to use AVAudio Player on your own instead.

      Regards, Chris

  30. Malcolm Langille says:

    Getting the following errors when i download and build your project. Trying to run under iphone – simulator 2.2.1

    Building target “MusicController” of project “MusicController” with configuration “Debug” — (14 errors)
    cd /Users/malcolmlangille/Documents/iphone/MusicController
    setenv MACOSX_DEPLOYMENT_TARGET 10.5
    setenv PATH “/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin”
    /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.0 -arch i386 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.2.1.sdk -L/Users/malcolmlangille/Documents/iphone/MusicController/build/Debug-iphonesimulator -F/Users/malcolmlangille/Documents/iphone/MusicController/build/Debug-iphonesimulator -F/Users/malcolmlangille/Documents/iphone/MusicController -filelist /Users/malcolmlangille/Documents/iphone/MusicController/build/MusicController.build/Debug-iphonesimulator/MusicController.build/Objects-normal/i386/MusicController.LinkFileList -mmacosx-version-min=10.5 -framework Foundation -framework UIKit -framework CoreGraphics -framework AudioToolbox -o /Users/malcolmlangille/Documents/iphone/MusicController/build/Debug-iphonesimulator/MusicController.app/MusicController
    ld warning: in /Users/malcolmlangille/Documents/iphone/MusicController/AudioToolbox.framework/AudioToolbox, file is not of required architecture
    Undefined symbols:
    “_AudioQueuePause”, referenced from:
    -[GBMusicTrack pause] in GBMusicTrack.o
    -[GBMusicTrack callbackForBuffer:] in GBMusicTrack.o
    “_AudioFileGetPropertyInfo”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioFileOpenURL”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioFileGetProperty”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioQueueEnqueueBuffer”, referenced from:
    -[GBMusicTrack readPacketsIntoBuffer:] in GBMusicTrack.o
    “_AudioQueueSetParameter”, referenced from:
    -[GBMusicTrack setGain:] in GBMusicTrack.o
    “_AudioQueueNewOutput”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioQueueSetProperty”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioFileClose”, referenced from:
    -[GBMusicTrack close] in GBMusicTrack.o
    “_AudioQueueDispose”, referenced from:
    -[GBMusicTrack close] in GBMusicTrack.o
    “_AudioFileReadPackets”, referenced from:
    -[GBMusicTrack readPacketsIntoBuffer:] in GBMusicTrack.o
    “_AudioQueueStart”, referenced from:
    -[GBMusicTrack play] in GBMusicTrack.o
    “_AudioQueueAllocateBuffer”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioQueueStop”, referenced from:
    -[GBMusicTrack close] in GBMusicTrack.o
    ld: symbol(s) not found
    collect2: ld returned 1 exit status
    “_AudioQueuePause”, referenced from:
    -[GBMusicTrack pause] in GBMusicTrack.o
    -[GBMusicTrack callbackForBuffer:] in GBMusicTrack.o
    “_AudioFileGetPropertyInfo”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioFileOpenURL”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioFileGetProperty”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioQueueEnqueueBuffer”, referenced from:
    -[GBMusicTrack readPacketsIntoBuffer:] in GBMusicTrack.o
    “_AudioQueueSetParameter”, referenced from:
    -[GBMusicTrack setGain:] in GBMusicTrack.o
    “_AudioQueueNewOutput”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioQueueSetProperty”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioFileClose”, referenced from:
    -[GBMusicTrack close] in GBMusicTrack.o
    “_AudioQueueDispose”, referenced from:
    -[GBMusicTrack close] in GBMusicTrack.o
    “_AudioFileReadPackets”, referenced from:
    -[GBMusicTrack readPacketsIntoBuffer:] in GBMusicTrack.o
    “_AudioQueueStart”, referenced from:
    -[GBMusicTrack play] in GBMusicTrack.o
    “_AudioQueueAllocateBuffer”, referenced from:
    -[GBMusicTrack initWithPath:] in GBMusicTrack.o
    “_AudioQueueStop”, referenced from:
    -[GBMusicTrack close] in GBMusicTrack.o
    ld: symbol(s) not found
    collect2: ld returned 1 exit status

Leave a Reply