<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Chris-Software.com &#187; the volume</title>
	<atom:link href="http://chris-software.com/index.php/tag/the-volume/feed/" rel="self" type="application/rss+xml" />
	<link>http://chris-software.com</link>
	<description>iPhone, iPod touch games, Objective-C Tutorials, krzysztofrutkowski.com</description>
	<lastBuildDate>Tue, 29 Mar 2011 09:58:11 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Playing backgroud music</title>
		<link>http://chris-software.com/index.php/2009/05/09/playing-backgroud-music/</link>
		<comments>http://chris-software.com/index.php/2009/05/09/playing-backgroud-music/#comments</comments>
		<pubDate>Sat, 09 May 2009 17:39:08 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[Obj-C Tutorials]]></category>
		<category><![CDATA[fade]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[play music]]></category>
		<category><![CDATA[Playing background music]]></category>
		<category><![CDATA[the volume]]></category>

		<guid isPermaLink="false">http://chris-software.com/?page_id=849</guid>
		<description><![CDATA[Related tutorials:

Short sounds

I&#8217;ve already told you how to play short sounds in your game / application. Now it&#8217;s time to play some music in the background. Although using one type of short sounds , doesn&#8217;t stop the iPod playback, adding the background music will turn iPod off.
In fact using AVAudioPlayer you can also play background [...]]]></description>
			<content:encoded><![CDATA[<h3>Related tutorials:</h3>
<ul>
<li><a href="http://chris-software.com/index.php/2009/05/05/short-sounds/">Short sounds</a></li>
</ul>
<p>I&#8217;ve already told you how to play short sounds in your game / application. Now it&#8217;s time to play some music in the background. Although using one type of <em>short sounds</em> , doesn&#8217;t stop the iPod playback, adding the background music will turn iPod off.</p>
<p>In fact using <strong>AVAudioPlayer</strong> you can also play background music, so, in other words <strong>AVAudioPlayer</strong> can play longer sounds, not only those limited to 30 seconds. Here is the code again (remember to add a framework: <em>AVFoundation.framework</em>):</p>
<pre><span><span>	AVAudioPlayer *</span>my</span><span>AVsound</span><span> = [[</span><span>AVAudioPlayer</span><span> </span>alloc<span>] </span>initWithContentsOfURL<span>:[</span><span>NSURL</span><span> </span>fileURLWithPath<span>:[[</span><span>NSBundle</span><span> </span>mainBundle<span>] </span>pathForResource<span>:</span><span>@"<strong>backgroundMusic</strong>"</span><span> </span>ofType<span>:</span><span>@"<strong>caf</strong>"</span><span>]  ] </span>error<span>:</span><span>NULL</span><span>];
	[myAVsound play]; </span></pre>
<p>The above code will simply play the background music [<strong>backgroundMusic.caf</strong>]. <span style="text-decoration: underline;">But it will play it only once</span>. You could use <em>NSTimer</em> to play it several times &#8211; call <em>[myAVsound play]</em>.</p>
<h3>GBMusicTrack</h3>
<p>I would like to present you very nice class &#8211; <em>GBMusicTrack,</em> written by <strong>Jake Peterson</strong> (aka A<em>notherJake</em>). You can find more info <a href="http://groups.google.com/group/cocos2d-iphone-discuss/web/background-music-track-engine---gbmusictrack">here</a>. <strong>Please note</strong>, 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.</p>
<p><strong>GBMusicTrack.h</strong>:</p>
<pre dir="ltr">//
//  GBMusicTrack.h
//  GameBase
//
//  Created by Jake Peterson (AnotherJake) on 7/6/08.
//  Copyright 2008 Jake Peterson. All rights reserved.
//

#import &lt;UIKit/UIKit.h&gt; // <strong>IN ORIGINAL FILE &lt;Cocoa/Cocoa.h&gt;</strong>
#import &lt;AudioToolbox/AudioQueue.h&gt;
#import &lt;AudioToolbox/AudioFile.h&gt;

#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</pre>
<p><strong>GBMusicTrack.m</strong></p>
<pre dir="ltr">//
//  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, &amp;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, &amp;size, &amp;dataFormat);

	// create a new playback queue using the specified data format and buffer callback
	AudioQueueNewOutput(&amp;dataFormat, BufferCallback, self, nil, nil, 0, &amp;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, &amp;size, &amp;maxPacketSize);
		if (maxPacketSize &gt; 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, &amp;size, nil);
	if (size &gt; 0)
	{
		// copy the cookie data from the file into the audio queue
		cookie = malloc(sizeof(char) * size);
		AudioFileGetProperty(audioFile, kAudioFilePropertyMagicCookieData, &amp;size, cookie);
		AudioQueueSetProperty(queue, kAudioQueueProperty_MagicCookie, cookie, size);
		free(cookie);
	}

	// allocate and prime buffers with some data
	packetIndex = 0;
	for (i = 0; i &lt; NUM_QUEUE_BUFFERS; i++)
	{
		AudioQueueAllocateBuffer(queue, gBufferSizeBytes, &amp;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, &amp;numBytes, packetDescs, packetIndex, &amp;numPackets, buffer-&gt;mAudioData);
	if (numPackets &gt; 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-&gt;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</pre>
<p>If you don&#8217;t understand what every line of this code means, don&#8217;t worry. Here is the simple instruction how to use it:</p>
<pre dir="ltr">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];</pre>
<p>Remember to import not only <strong>GBMusicTrack.h</strong> to the class with above lines of code, but also to add <strong>AudiToolbox.framework</strong>. As you see using <em>GBMusicTrack</em> class is quite simple, <em>setRepeat:YES/NO</em> method allows you to decide if you want your music to loop constantly, <em>setGain</em> to adjust the volume (remember: try to avoid setting the volume louder than 1.0) and <em>play</em> to start playing.</p>
<p><strong>Please note:</strong> compile for the version <strong>2.2</strong> or higher!</p>
<p><strong>Please note:</strong> many people complains that anything from this tutorial doesn&#8217;t work on <strong>iPhone Simulator</strong>. Don&#8217;t worry, it works on real device.</p>
<h3>Playing the next track using <em>GBMusicTrack</em>:</h3>
<p>As I told before, this class allows you to play one track at the time. To play next, you have to call the <em>close</em> method and <em>initialize</em> it again:</p>
<pre>	[backgroundMusic close];
<span><span>	</span>[</span><span>backgroundMusic</span><span> </span>initWithPath<span>:[[</span><span>NSBundle</span><span> </span>mainBundle<span>] </span>pathForResource<span>:</span><span>@"nextTrack"</span><span> </span>ofType<span>:</span><span>@"caf"</span><span>]];</span></pre>
<p>You can download my sample project: &#8211; my music controller I&#8217;ve written using the <strong>GBMusicTrack</strong>. You can fade the music in / out, play and pause and set the volume.</p>
<p style="text-align: center; "><a href="http://chris-software.com/wp-content/uploads/2009/05/musiccontrollerscreenshot.png"><img class="alignnone size-medium wp-image-851" title="musiccontrollerscreenshot" src="http://chris-software.com/wp-content/uploads/2009/05/musiccontrollerscreenshot-200x300.png" alt="musiccontrollerscreenshot" width="200" height="300" /></a></p>
<p style="text-align: center; "><a href="http://chris-software.com/wp-content/uploads/2009/05/musiccontroller.zip"><img class="size-full wp-image-564 alignnone" title="xcodeproj" src="http://chris-software.com/wp-content/uploads/2009/04/xcodeproj.png" alt="xcodeproj" width="128" height="128" /></a></p>
<p style="text-align: center; "><a href="http://chris-software.com/wp-content/uploads/2009/05/musiccontroller.zip">Download the project</a></p>
]]></content:encoded>
			<wfw:commentRss>http://chris-software.com/index.php/2009/05/09/playing-backgroud-music/feed/</wfw:commentRss>
		<slash:comments>39</slash:comments>
		</item>
	</channel>
</rss>

