<?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>benbritten.com &#187; openAL</title>
	<atom:link href="http://benbritten.com/category/blog/openal/feed/" rel="self" type="application/rss+xml" />
	<link>http://benbritten.com</link>
	<description>Software should be simple.</description>
	<lastBuildDate>Tue, 30 Nov 2010 12:00:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Imitation is the sincerest form of flattery</title>
		<link>http://benbritten.com/2010/05/19/imitation-is-the-sincerest-form-of-flattery/</link>
		<comments>http://benbritten.com/2010/05/19/imitation-is-the-sincerest-form-of-flattery/#comments</comments>
		<pubDate>Wed, 19 May 2010 01:06:04 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[meta]]></category>
		<category><![CDATA[openAL]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=1019</guid>
		<description><![CDATA[Funny story for the day: Here is how this works: Step 1: write an original article on your blog about a useful thing (like OpenAL) (we will call this the 'original post' and the 'original blogger') Step 2: someone else likes your article and cuts and pastes it into their blog, they change a few [...]]]></description>
			<content:encoded><![CDATA[<p>Funny story for the day:</p>
<p>Here is how this works:</p>
<p>Step 1:  write an original article on your blog about a useful thing (like OpenAL) (we will call this the 'original post' and the 'original blogger')<br />
Step 2:  someone else likes your article and cuts and pastes it into their blog, they change a few words here and there, but mostly it is left identical (errors and everything) (let's call him 'copy blogger', and we will call this the 'copy post')<br />
Step 3:  wait a while<br />
Step 4:  somebody notices that 'copy post' is very similar to 'original post' and tells 'Copy Blogger' that someone has copied his post! Mon Dieu!<br />
Step 5:  Copy Blogger emails Original Blogger and tells him that if he is going to be copying his (plagiarised) posts then Original Blogger should have the common courtesy to provide a linkback to the 'Copy post' from the 'Original post'!<br />
Step 6: Original Blogger laughs and laughs.</p>
<p>If this is all too abstract, then I will simplify it:  I wrote a post about <a href="http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/">OpenAL on the iPhone</a> in 2008, right after the NDA was lifted.  This single article is in the top 5 for traffic for my site.  Lots of people have seen it.  Presumably there are lots of OpenAL codebases out there that have snippets of code from that article, which is great!</p>
<p>That article has a bunch of code snippets and instructions on how to build your own simple OpenAL sound player. (but does not provide a working version, you have to do that yourself :-)</p>
<p>Someone (whom shall remain nameless) took that article and copied it into his website, and claimed authorship of it.  This was in early 2009. Now to his credit, he did change a few words here and there, and he took the code snippets and put them into a single file and filled in the gaps. This is exactly what I had hoped people would do!  (with the exception of claiming authorship of my words, that is kinda dickish)</p>
<p>I actually noticed that this had happened and made a fleeting mention of it at the top of my post about <a href="http://benbritten.com/2009/05/02/lots-and-lots-of-sounds-in-openal/">'lots of sounds' in OpenAL</a>.  But to be honest, I didnt really care all that much about it.  Hey, it's the internet, people steal anything that isn't bolted down, and they sometimes steal that stuff too. </p>
<p>However, this morning, I get an email from our random internet plagiarist telling me: (and I quote)  "just want to notice that someone told me it seems your article has alot in common with my own article postet on [RADACTED]. If your article is related to that, you should post a linkback or something like that. "</p>
<p>He wasn't a dick about it, he was pretty cool.  He is probably a stand-up kinda guy. </p>
<p>To be honest, it has been a looooong time since I noticed that he had copied me, and I had basically forgotten about it.  I dutifully went to his site and had a look (because I was curious, and had forgotten about the whole thing, and frankly OpenAL isn't that complicated, and there are only so many ways to do it, so really most articles on OpenAL on the iphone could be considered 'similar' on many ways, and if his site was good, then I would link to it anyway) and when I saw my own words staring back at me I remembered the whole thing from last year and I laughed and laughed.</p>
<p>Then I sent him a kinda shitty reply, sorry about that internet plagiarist dude, I probably should have waited till I had breakfast before replying to your email.  </p>
<p>At the end of the day, I post stuff here so that people hopefully get something out of it.  If you want to copy all the code here and all the txt here and post it on your site, well, that is perfectly possible, and not illegal.  But taking ownership of my words is a bit of a douchebag move.  At least have the common courtesy to re-word it.  </p>
<p>Cheers!<br />
-Ben</p>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2010/05/19/imitation-is-the-sincerest-form-of-flattery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Streaming in OpenAL</title>
		<link>http://benbritten.com/2010/05/04/streaming-in-openal/</link>
		<comments>http://benbritten.com/2010/05/04/streaming-in-openal/#comments</comments>
		<pubDate>Tue, 04 May 2010 02:16:19 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[openAL]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=994</guid>
		<description><![CDATA[I have posted a few posts on OpenAL that have been very popular: a basic intro to OpenAL on the iPhone A rant about OpenAL and sample code how to properly handle interruptions in openAL on the iPhone how to play lots of sounds all at once in OpenAL One thing that people keep asking [...]]]></description>
			<content:encoded><![CDATA[<p>I have posted a few posts on OpenAL that have been very popular:</p>
<ul>
<li> <a href="http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/">a basic intro to OpenAL on the iPhone</a>
<li><a href="http://benbritten.com/2009/01/24/more-openal-tidbits-for-iphone/"> A rant about OpenAL and sample code</a>
<li><a href="http://benbritten.com/2009/02/02/restarting-openal-after-application-interruption-on-the-iphone/">how to properly handle interruptions in openAL on the iPhone</a>
<li><a href="http://benbritten.com/2009/05/02/lots-and-lots-of-sounds-in-openal/">how to play lots of sounds all at once in OpenAL</a>
</ul>
<p>One thing that people keep asking me is how to playback gigantic files in OpenAL.  Things like songs or audio books.  (This post has been slowly growing over the past few months and I am finally going to put the final bits in and post it!)</p>
<p>The answer to this problem (in case you didn't read the title of the post) is streaming.  </p>
<p>First off, lets define what I really mean when I say streaming.  In all of the above code samples, the sound buffers were fully resident in memory.  This works great for smaller sounds like button click sounds and swords clanging sounds for games and whatnot.  However, for big files like full quality songs and really anything over about a dozen seconds long, putting it all into memory (especially on the iPhone) becomes a bit of a problem.</p>
<p>To solve this we read the data off of the disk in chunks, filling small buffers one at a time and then playing them back one after the other.  All the while, in the background we are removing the old buffers and replacing them with new buffers so that we only ever have a few seconds of sound in memory at one time.</p>
<p>Here is a crappy diagram that I spent way too much time on, and it is still crappy:</p>
<p><a href="http://benbritten.com/wp-content/uploads/2010/05/streamingHighLevel2.png"><img src="http://benbritten.com/wp-content/uploads/2010/05/streamingHighLevel2.png" alt="" title="streamingHighLevel" width="600" height="455" class="aligncenter size-full wp-image-999" /></a></p>
<p>OK, at the top we have the 'standard' way to do thing (the way described in all those posts linked above).  Basically:</p>
<ul>
<li> Step1: Load the sound data from a file into an OpenAL Buffer
<li> Step2: Connect the OpenAL Buffer to an OpenAL source with something like: alSourcei(sourceID, AL_BUFFER, bufferID);
<li> step 3: Start source playing with with alSourcePlay(sourceID);
</ul>
<p>Pretty simple.  </p>
<p>Streaming is a bit more complicated, but still pretty simple (in concept). The first three steps are really very similar to the 'standard' way above.</p>
<ul>
<li> Step A: Load in a few chunks of the big file into all the waiting OpenAL buffers.
<li> Step B: Queue up all the newly filled buffers into a single OpenAL source via alSourceQueueBuffers(sourceID, 1, &bufferID);
<li> Step C: Start the source playing with alSourcePlay(sourceID); This will begin to consume the queued up buffers.
<li> Step D: In a background thread, check to see if there are any used buffers, and if so then load the next chunk of the sound file into the used buffer
<li> Step E: Queue up this newly filled buffer to the source with alSourceQueueBuffers(sourceID, 1, &bufferID);  As long as there are still bufferes queued up, the source will continue to play them
</ul>
<p>So there it is, five easy steps.  Lets look at them one at a time:</p>
<p><strong> Step A: Load in a few chunks of the big file into all the waiting OpenAL buffers.</strong></p>
<p>Ok first thing we need to do is to prepare a place for all this state data to live.  This will be kinda like preloading the streaming file, execept that we dont load any sound into memory just yet, we are just going to get ready to do that.</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// this queues up the specified file for streaming</span>
-<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableDictionary.html"><span style="color: #0000ff;">NSMutableDictionary</span></a>*<span style="color: #002200;">&#41;</span>initializeStreamFromFile:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>fileName format:<span style="color: #002200;">&#40;</span>ALenum<span style="color: #002200;">&#41;</span>format freq:<span style="color: #002200;">&#40;</span>ALsizei<span style="color: #002200;">&#41;</span>freq
<span style="color: #002200;">&#123;</span>
	<span style="color: #ff0000;">// first, open the file</span>
	AudioFileID fileID = <span style="color: #002200;">&#91;</span>self _openAudioFile:fileName<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// find out how big the actual audio data is</span>
	UInt32 fileSize = <span style="color: #002200;">&#91;</span>self _audioFileSize:fileID<span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>First thing, we open the file.  This doesnt load it into memory, it just gives us a handle to some data that we need.  Specifically the file size.  We will need this to calculate the number of buffers we need to play the whole file.</p>
<pre class="objc">&nbsp;
&nbsp;
	UInt32 bufferSize = OPENAL_STREAMING_BUFFER_SIZE;
	UInt32 bufferIndex = <span style="color: #0000dd;">0</span>;
&nbsp;
	<span style="color: #ff0000;">// ok, now we build a data record for this streaming file</span>
	<span style="color: #ff0000;">// before, with straight sounds this is just a soundID</span>
	<span style="color: #ff0000;">// but with the streaming sound, we need more info</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableDictionary.html"><span style="color: #0000ff;">NSMutableDictionary</span></a> * record = <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableDictionary.html"><span style="color: #0000ff;">NSMutableDictionary</span></a> dictionary<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:fileName forKey:@<span style="color: #666666;">&quot;fileName&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:fileSize<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;fileSize&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:bufferSize<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;bufferSize&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:bufferIndex<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;bufferIndex&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithInteger:format<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;format&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithInteger:freq<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;freq&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithBool:NO<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;isPlaying&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>Next we are going to make a streaming sound record.  This dictionary will hold all of the state for this stream.  </p>
<p>The OPENAL_STREAMING_BUFFER_SIZE is how many bytes of data we want in each buffer chunk.  I have had good luck with 48000, this is about a second at high quality so I have plenty of time to grab the next chunk.  </p>
<p>The bufferIndex is the current buffer that is full.  For now that is zero of course.</p>
<p>Format and Freq we will use when we eventually setup our source. and isPlaying will let us know if we need to be refilling the buffers or not.</p>
<pre class="objc">&nbsp;
&nbsp;
	<span style="color: #ff0000;">// this will hold our buffer IDs</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableArray.html"><span style="color: #0000ff;">NSMutableArray</span></a> * bufferList = <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableArray.html"><span style="color: #0000ff;">NSMutableArray</span></a> array<span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">int</span> i;
	<span style="color: #0000ff;">for</span> <span style="color: #002200;">&#40;</span>i = <span style="color: #0000dd;">0</span>; i &lt; <span style="color: #0000dd;">3</span>; i++<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		NSUInteger bufferID;
		<span style="color: #ff0000;">// grab a buffer ID from openAL</span>
		alGenBuffers<span style="color: #002200;">&#40;</span><span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
&nbsp;
		<span style="color: #002200;">&#91;</span>bufferList addObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:bufferID<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>	
&nbsp;
	<span style="color: #002200;">&#91;</span>record setObject:bufferList forKey:@<span style="color: #666666;">&quot;bufferList&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>This is where the actual buffer references will live.  In theory you can get away with just two buffers.  One to play and one to fill while the other is playing.  However If you get any stitch in your background thread, or do any heavy lifting on the processor that delays that refill, then you will get some nasty skipping.  Instead I tend to use three buffers.  This takes up more memory, but affords me a bit more robust playback.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// close the file</span>
	AudioFileClose<span style="color: #002200;">&#40;</span>fileID<span style="color: #002200;">&#41;</span>;
&nbsp;
	<span style="color: #0000ff;">return</span> record;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Finally close our audio file and return the record. Take that record returned from the above method and store it into a big NSMutableDictionary called soundLibrary with some key, like the name of the sound. (or in whatever data structure you want, that is how I do it, and that is how the sample code works)</p>
<p>We are still in Step A (well, pre step A even). We haven't loaded any buffers, but we are ready when that time comes.</p>
<p>Once you are ready to play your sound, we move to:</p>
<p><strong>Steps A, B and C in one fell swoop<br />
</strong></p>
<p>OK, lets define a play streaming sound method that does A, B and C for us. (and kick off Step D)</p>
<p>We would call this method when we want to actually begin playing the streaming sound, the key is whatever key you used to store the record into the sound library.</p>
<p>This method returns the sourceID so that the calling object can use it to stop the sound.</p>
<pre class="objc">&nbsp;
- <span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>playStream:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>soundKey gain:<span style="color: #002200;">&#40;</span>ALfloat<span style="color: #002200;">&#41;</span>gain pitch:<span style="color: #002200;">&#40;</span>ALfloat<span style="color: #002200;">&#41;</span>pitch loops:<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">BOOL</span><span style="color: #002200;">&#41;</span>loops
<span style="color: #002200;">&#123;</span>
	<span style="color: #ff0000;">// if we are not active, then dont do anything</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>!active<span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span>;
&nbsp;
	ALenum err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>; <span style="color: #ff0000;">// clear error code</span>
&nbsp;</pre>
<p>Just some housekeeping.  I have a big boolean called 'active' that shuts off all sounds. Makes it nice and easy.  Second we clear out the OpenAL errors so that anything in there will be a result of what we do in this method.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// generally the 'play sound method' whoudl be called for all sounds</span>
	<span style="color: #ff0000;">// however if someone did call this one in error, it is nice to be able to handle it</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>soundLibrary objectForKey:soundKey<span style="color: #002200;">&#93;</span> isKindOfClass:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> <span style="color: #0000ff;">class</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #0000ff;">return</span> <span style="color: #002200;">&#91;</span>self playSound:soundKey gain:<span style="color: #0000dd;">1.0</span> pitch:<span style="color: #0000dd;">1.0</span> loops:loops<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>If you followed along on the other tutorials you would know that previously I had simply stored the NSNumber value for the buffer in the soundLibrary.  This is a way to handle that if the streaming method gets called with the wrong key (ie a non-streaming sound) It just punts to the standard playSound method.  Similarly in my playsound method I check to see if the record is an NSDictionary, and if so then it calls this method.  That way  you can just use the playSounds method with either streaming sounds or regular sounds and it all works dandy.</p>
<pre class="objc">&nbsp;
&nbsp;
	<span style="color: #ff0000;">// get our keyed sound record</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableDictionary.html"><span style="color: #0000ff;">NSMutableDictionary</span></a> * record = <span style="color: #002200;">&#91;</span>soundLibrary objectForKey:soundKey<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// first off, check to see if this sound is already playing</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;isPlaying&quot;</span><span style="color: #002200;">&#93;</span> boolValue<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span>;
&nbsp;</pre>
<p>Ok, we grab the record and start to go through the state.  If the sound is already playing then we get out early.  </p>
<pre class="objc">&nbsp;
&nbsp;
	<span style="color: #ff0000;">// first, find the buffer we want to play</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSArray.html"><span style="color: #0000ff;">NSArray</span></a> * bufferList = <span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;bufferList&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// now find an available source</span>
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span>self nextAvailableSource<span style="color: #002200;">&#93;</span>;
	alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFER, <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span>;
&nbsp;
	<span style="color: #ff0000;">// reset the buffer index to 0</span>
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:<span style="color: #0000dd;">0</span><span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;bufferIndex&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>Now we are going to move into Step A proper.  Grab the buffer list, and get an available source.  the Method nextAvailableSource simply goes through a big list of premade sources and finds one that is not being used currrently.  I think I went over that in the 'lots of sounds' tutorial linked above.</p>
<p>Then we reset the bufferindex to 0.  This is basically setting the playhead to the beginning of the sound. next, we fill the buffers</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// queue up the first 3 buffers on the source</span>
	<span style="color: #0000ff;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * bufferNumber in bufferList<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		NSUInteger bufferID = <span style="color: #002200;">&#91;</span>bufferNumber unsignedIntegerValue<span style="color: #002200;">&#93;</span>;
		<span style="color: #002200;">&#91;</span>self loadNextStreamingBufferForSound:soundKey intoBuffer:bufferID<span style="color: #002200;">&#93;</span>;
		alSourceQueueBuffers<span style="color: #002200;">&#40;</span>sourceID, <span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
		err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
		<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#91;</span>self _error:err note:@<span style="color: #666666;">&quot;Error alSourceQueueBuffers!&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Ok, this is pretty simple looking but there is the one magic method: loadNextStreamingBufferForSound: intoBuffer: I will get to this in a minute, but basically it grabs a chunk of the audio file based on the bufferIndex and loads it into the buffer.  then it increments the bufferIndex so that the next time I call this method I will get the next chunk.<br />
We load a chunk into every buffer in the buffer list (which in our case will be three buffers)<br />
And here is the important part: (this would be the Step B part of the diagram)</p>
<pre class="objc">&nbsp;
alSourceQueueBuffers<span style="color: #002200;">&#40;</span>sourceID, <span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>This is the magic OpenAL function call that makes this source a streaming source instead of a single buffer source. Basically it will continue to play as long as there are buffers queued up.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// set the pitch and gain of the source</span>
	alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_PITCH, pitch<span style="color: #002200;">&#41;</span>;
	err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#91;</span>self _error:err note:@<span style="color: #666666;">&quot;Error AL_PITCH!&quot;</span><span style="color: #002200;">&#93;</span>;
	alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_GAIN, gain<span style="color: #002200;">&#41;</span>;
	err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#91;</span>self _error:err note:@<span style="color: #666666;">&quot;Error AL_GAIN!&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #ff0000;">// streams should not be looping</span>
	<span style="color: #ff0000;">// we will handle that in the buffer refill code</span>
	alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_LOOPING, AL_FALSE<span style="color: #002200;">&#41;</span>;
	err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#91;</span>self _error:err note:@<span style="color: #666666;">&quot;Error AL_LOOPING!&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>With our buffers loaded and queued on the source, we just need to set up the source with all the properties that were passed in.  This is exactly like you would do it for a single buffer sound.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// everything is queued, start the buffer playing</span>
	alSourcePlay<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;
	<span style="color: #ff0000;">// check to see if there are any errors</span>
	err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #002200;">&#91;</span>self _error:err note:@<span style="color: #666666;">&quot;Error Playing Stream!&quot;</span><span style="color: #002200;">&#93;</span>;
		<span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Ok, finally we move to Step C: and we start the source playing.  From this point on, we are on the clock to keep the buffers filled up.  </p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// set up some state</span>
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithBool:YES<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;isPlaying&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithBool:loops<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;loops&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:sourceID<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;sourceID&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// kick off the refill methods</span>
	<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSThread.html"><span style="color: #0000ff;">NSThread</span></a> detachNewThreadSelector:<span style="color: #0000ff;">@selector</span><span style="color: #002200;">&#40;</span>rotateBufferThread:<span style="color: #002200;">&#41;</span> toTarget:self withObject:soundKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">return</span> sourceID;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>This last bit sets up the state we need to keep the buffers full, and kicks off a new thread to run in the background to keep our buffers full.</p>
<p>OK, before we move onto Step D lets have a look at our buffer loader method</p>
<p><strong>loadNextStreamingBufferForSound: intoBuffer:</strong></p>
<p>This is roughly equivalent to the method that you would use to load an entire file into a buffer for standard sound playback, only we are only going to be grabbing a small bit of the file.  Luckily for us this is a pretty common thing you would want to do, so mostly all we have to worry about is keeping the state set properly.</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// this takes the stream record, figures out where we are in the file</span>
<span style="color: #ff0000;">// and loads the next chunk into the specified buffer</span>
-<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">BOOL</span><span style="color: #002200;">&#41;</span>loadNextStreamingBufferForSound:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>key intoBuffer:<span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>bufferID
<span style="color: #002200;">&#123;</span>
	<span style="color: #ff0000;">// check some escape conditions</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>soundLibrary objectForKey:key<span style="color: #002200;">&#93;</span> == <span style="color: #0000ff;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> NO;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>!<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>soundLibrary objectForKey:key<span style="color: #002200;">&#93;</span> isKindOfClass:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSDictionary.html"><span style="color: #0000ff;">NSDictionary</span></a> <span style="color: #0000ff;">class</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> NO;
&nbsp;</pre>
<p>First off just some simple checks to make sure I am not trying to load a non-existent sound file, or a non-streaming file.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// get the record</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableDictionary.html"><span style="color: #0000ff;">NSMutableDictionary</span></a> * record = <span style="color: #002200;">&#91;</span>soundLibrary objectForKey:key<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// open the file</span>
	AudioFileID fileID = <span style="color: #002200;">&#91;</span>self _openAudioFile:<span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;fileName&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// now we need to calculate where we are in the file</span>
	UInt32 fileSize = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;fileSize&quot;</span><span style="color: #002200;">&#93;</span> unsignedIntegerValue<span style="color: #002200;">&#93;</span>;
	UInt32 bufferSize = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;bufferSize&quot;</span><span style="color: #002200;">&#93;</span> unsignedIntegerValue<span style="color: #002200;">&#93;</span>;
	UInt32 bufferIndex = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;bufferIndex&quot;</span><span style="color: #002200;">&#93;</span> unsignedIntegerValue<span style="color: #002200;">&#93;</span>;;
&nbsp;</pre>
<p>Grab the record that has all of our state information, and set up all of our variables.</p>
<pre class="objc">&nbsp;
&nbsp;
	<span style="color: #ff0000;">// how many chunks does the file have total?</span>
	NSInteger totalChunks = fileSize/bufferSize;
&nbsp;
	<span style="color: #ff0000;">// are we past the end? if so get out</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>bufferIndex &gt; totalChunks<span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> NO;
&nbsp;
	<span style="color: #ff0000;">// this is where we need to start reading from the file</span>
	NSUInteger startOffset = bufferIndex * bufferSize;
&nbsp;
	<span style="color: #ff0000;">// are we in the last chunk? it might not be the same size as all the others</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>bufferIndex == totalChunks<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		NSInteger leftOverBytes = fileSize - <span style="color: #002200;">&#40;</span>bufferSize * totalChunks<span style="color: #002200;">&#41;</span>;
		bufferSize = leftOverBytes;
	<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Here we are just using our state info to figure out where in the file to look and how big of a chunk to take.  If we are at the last chunk, then it may not be a full sized chunk, so we have to take that into account and change our data size. </p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// this is where the audio data will live for the moment</span>
	<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> * outData = <a href="http://www.opengroup.org/onlinepubs/009695399/functions/malloc.html"><span style="color: #0000dd;">malloc</span></a><span style="color: #002200;">&#40;</span>bufferSize<span style="color: #002200;">&#41;</span>;
&nbsp;
	<span style="color: #ff0000;">// this where we actually get the bytes from the file and put them</span>
	<span style="color: #ff0000;">// into the data buffer</span>
	UInt32 bytesToRead = bufferSize;
	OSStatus result = noErr;
	result = AudioFileReadBytes<span style="color: #002200;">&#40;</span>fileID, <span style="color: #0000ff;">false</span>, startOffset, &amp;bytesToRead, outData<span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>result != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> NSLog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;cannot load stream: %@&quot;</span>,<span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;fileName&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
	<span style="color: #ff0000;">// if we are past the end, and no bytes were read, then no need to Q a buffer</span>
        <span style="color: #ff0000;">// this should not happen if the math above is correct, but to be sae we will add it</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>bytesToRead == <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
            <a href="http://www.opengroup.org/onlinepubs/009695399/functions/free.html"><span style="color: #0000dd;">free</span></a><span style="color: #002200;">&#40;</span>outData<span style="color: #002200;">&#41;</span>;
            <span style="color: #0000ff;">return</span> NO; <span style="color: #ff0000;">// no more file!</span>
        <span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Ok, here we do the actual meat of the method.  We alloc some memory, and then use the AudioFileReadBytes() function to grab our desired slice of data from the big file. This loads our chunk of sound data into the outData memory.  At this point we will proceed exactly like we would with a single-buffer sound.</p>
<pre class="objc">&nbsp;
&nbsp;
	ALsizei freq = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;freq&quot;</span><span style="color: #002200;">&#93;</span> intValue<span style="color: #002200;">&#93;</span>;
	ALenum format = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;format&quot;</span><span style="color: #002200;">&#93;</span> intValue<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// jam the audio data into the supplied buffer</span>
	alBufferData<span style="color: #002200;">&#40;</span>bufferID,format,outData,bytesToRead,freq<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>Load out sound into our OpenAL buffer. easy.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// clean up the buffer</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>outData<span style="color: #002200;">&#41;</span>
	<span style="color: #002200;">&#123;</span>
		<a href="http://www.opengroup.org/onlinepubs/009695399/functions/free.html"><span style="color: #0000dd;">free</span></a><span style="color: #002200;">&#40;</span>outData<span style="color: #002200;">&#41;</span>;
		outData = <span style="color: #0000ff;">NULL</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;
	AudioFileClose<span style="color: #002200;">&#40;</span>fileID<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>Do some cleanup.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// increment the index so that next time we get the next chunk</span>
	bufferIndex ++;
	<span style="color: #ff0000;">// are we looping? if so then flip back to 0</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#40;</span>bufferIndex &gt; totalChunks<span style="color: #002200;">&#41;</span> &amp;&amp; <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;loops&quot;</span><span style="color: #002200;">&#93;</span> boolValue<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		bufferIndex = <span style="color: #0000dd;">0</span>;
	<span style="color: #002200;">&#125;</span>
	<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:bufferIndex<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;bufferIndex&quot;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">return</span> YES;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Finally we increment the bufferIndex so that the net time we call this method we get the next chunk of data in the sequence. If we are looping we reset the index to 0 at the end.</p>
<p>So, that is steps A, B, C, and the beginning of D.</p>
<p>Lets look more closely at our background thread now.</p>
<p><strong>Step D (and E): The background thread to refill our buffers</strong></p>
<p>OK, you may recall, like ten pages ago, that we kicked off a thread to refill the buffers in the background.  Lets look at that:</p>
<pre class="objc">&nbsp;
-<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #002200;">&#41;</span>rotateBufferThread:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>soundKey
<span style="color: #002200;">&#123;</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSAutoreleasePool.html"><span style="color: #0000ff;">NSAutoreleasePool</span></a> * apool = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSAutoreleasePool.html"><span style="color: #0000ff;">NSAutoreleasePool</span></a> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">BOOL</span> stillPlaying = YES;
	<span style="color: #0000ff;">while</span> <span style="color: #002200;">&#40;</span>stillPlaying<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		stillPlaying = <span style="color: #002200;">&#91;</span>self rotateBufferForStreamingSound:soundKey<span style="color: #002200;">&#93;</span>;
		<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>interrupted<span style="color: #002200;">&#41;</span> 	<span style="color: #002200;">&#123;</span>
			<span style="color: #ff0000;">// slow down our thread during interruptions</span>
			<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSThread.html"><span style="color: #0000ff;">NSThread</span></a> sleepForTimeInterval:kBufferRefreshDelay * <span style="color: #0000dd;">3</span><span style="color: #002200;">&#93;</span>;
		<span style="color: #002200;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #002200;">&#123;</span>
			<span style="color: #ff0000;">// normal thread delay</span>
			<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSThread.html"><span style="color: #0000ff;">NSThread</span></a> sleepForTimeInterval:kBufferRefreshDelay<span style="color: #002200;">&#93;</span>;
		<span style="color: #002200;">&#125;</span>
	<span style="color: #002200;">&#125;</span>
	<span style="color: #002200;">&#91;</span>apool release<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>This is a pretty simple method.  Remember we are in a new thread, so we need to set up our own pool.  Once we are no longer playing, then the thread ends. We make one call basically to rotateBufferForStreamingSound:.  Finally if we are interrupted then we dont need to be refilling but our thread will still run (until we are terminated if that happens). To be good citizens we will decrease the amount of time we are checking the thread.  </p>
<p>Otherwise we just come back in kBufferRefreshDelay seconds.  Setting this number can be a bit tricky.  If you set it too close to the actual time it takes to play your individual buffers (as you would think) then if it lags at all then you will fall behind and never be able to catch up.  You want it to be more than once during every chunk, incase you need to load more than one chunk because of a slow thread.  However, run it too often and you are wasting cycles.  I have mine set to 0.25 seconds based on the 48000 byte buffer.  I dont even remember why i came to these numbers and they might be terrible. but they do work.  Feel free to tune them to your heart's desire.</p>
<p>Next up, the actual buffer rotator:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// this checks to see if there is a buffer that has been used up.</span>
<span style="color: #ff0000;">// if it finds one then it loads the next bit of the sound into that buffer</span>
<span style="color: #ff0000;">// and puts it into the back of the queue</span>
-<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">BOOL</span><span style="color: #002200;">&#41;</span>rotateBufferForStreamingSound:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>soundKey
<span style="color: #002200;">&#123;</span>
	<span style="color: #ff0000;">// make sure we arent trying to stream a normal sound</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>!<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>soundLibrary objectForKey:soundKey<span style="color: #002200;">&#93;</span> isKindOfClass:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSDictionary.html"><span style="color: #0000ff;">NSDictionary</span></a> <span style="color: #0000ff;">class</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> NO;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>interrupted<span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> YES; <span style="color: #ff0000;">// we are still 'playing' but we arent loading new buffers</span>
&nbsp;
	<span style="color: #ff0000;">// get the keyed record</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableDictionary.html"><span style="color: #0000ff;">NSMutableDictionary</span></a> * record = <span style="color: #002200;">&#91;</span>soundLibrary objectForKey:soundKey<span style="color: #002200;">&#93;</span>;
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>record objectForKey:@<span style="color: #666666;">&quot;sourceID&quot;</span><span style="color: #002200;">&#93;</span> unsignedIntegerValue<span style="color: #002200;">&#93;</span>;	
&nbsp;</pre>
<p>First some defensive programming,  if we are getting called with the wrong key then get out, if we are interrupted then we are not loading any new buffers, so get out (but return YES because we want to keep the thread alive)<br />
Then we grab our ubiquitous record and start to fill in some variables.</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// check to see if we are stopped</span>
	NSInteger sourceState;
	alGetSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_SOURCE_STATE, &amp;sourceState<span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>sourceState != AL_PLAYING<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #002200;">&#91;</span>record setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithBool:NO<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;isPlaying&quot;</span><span style="color: #002200;">&#93;</span>;
		<span style="color: #0000ff;">return</span> NO; <span style="color: #ff0000;">// we are stopped, do not load any more buffers</span>
	<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>First up: check to see if this source that we are meant to be loading buffers into is stopped.  If it is, then we dont need to load any new buffers, and we want to return NO so that the thread finishes as well.</p>
<pre class="objc">&nbsp;
&nbsp;
	<span style="color: #ff0000;">// get the processed buffer count</span>
	NSInteger buffersProcessed = <span style="color: #0000dd;">0</span>;
	alGetSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFERS_PROCESSED, &amp;buffersProcessed<span style="color: #002200;">&#41;</span>;
&nbsp;
	<span style="color: #ff0000;">// check to see if we have a buffer to deQ</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>buffersProcessed &gt; <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #ff0000;">// great! deQ a buffer and re-fill it</span>
		NSUInteger bufferID;
		<span style="color: #ff0000;">// remove the buffer form the source</span>
		alSourceUnqueueBuffers<span style="color: #002200;">&#40;</span>sourceID, <span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
		<span style="color: #ff0000;">// fill the buffer up and reQ!</span>
		<span style="color: #ff0000;">// if we cant fill it up then we are finished</span>
		<span style="color: #ff0000;">// in which case we dont need to re-Q</span>
		<span style="color: #ff0000;">// return NO if we dont have mroe buffers to Q</span>
		<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>!<span style="color: #002200;">&#91;</span>self loadNextStreamingBufferForSound:soundKey intoBuffer:bufferID<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> NO;
		<span style="color: #ff0000;">// Q the loaded buffer</span>
		alSourceQueueBuffers<span style="color: #002200;">&#40;</span>sourceID, <span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Next up, the big event: we see how many buffers the source has processed since our last check.  For every buffer that has been processed we should fill in a new one and queue it up.<br />
Before we can queue up a new buffer, we need to dequeue the old one.  We do this with a call to alSourceUnqueueBuffers().  This fills in our bufferID variable, we can use this buffer now for whatever we want.  In this case we want to fill it up with the next chunk of sound data and then put it at the end of the queue.</p>
<p>We call our loadNextStreamingBufferForSound:intoBuffer: method and if it returns NO, then we are all done and we can get out.<br />
If it returns YES then we can queue up the newly filled buffer.</p>
<pre class="objc">&nbsp;
	<span style="color: #0000ff;">return</span> YES;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Finally, if we have made it this far then it was a successful buffer load and we return a YES to keep our loop going.</p>
<p>That is about it.  The way this is all built, once you cann alSourceStop() on your streaming sound ID, everything sorta cleans itself up.  The buffers stop rotating, and the thread stops.  You still have buffers in memory tho, so if you want to clean those up too, be sure to add that code.</p>
<p><strong>To Sum Up</strong></p>
<p>OK, so there are the five-ish steps to streaming sound glory with OpenAL.  </p>
<p>Obviously I have left out all the other code you need to get this running, have a look at the articles linked at the top, they have most of the rest of it.  </p>
<p>Also I should mention that all of this code comes from an earlier, simpler version of what I generally use as my 'sound engine' nowadays. (basically I have been working on finishing this tutorial for awhile now and my working code has evolved since then :-)<br />
This is not to say the sample code here is necessarily inferior, in fact my current code does almost exactly the same things, only there is a bit more optimised state handling and some other things that make it faster/easier, but not as easy to explain in an already very long post.  So feel free to take this code and make it better in your own way :-)  (for instance, instead of using dictionaries for state, I now have some proper sound classes that hold all that state for me etc..)</p>
<p>Also, i should say that if this code crashes your machine, or bricks your phone or makes your cat lose all it's hair, it is not my fault, you have been warned.</p>
<p>Cheers!<br />
-B</p>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2010/05/04/streaming-in-openal/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>alBufferDataStatic: why you should avoid it</title>
		<link>http://benbritten.com/2009/09/20/albufferdatastatic-why-you-should-avoid-it/</link>
		<comments>http://benbritten.com/2009/09/20/albufferdatastatic-why-you-should-avoid-it/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 01:11:24 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[openAL]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=898</guid>
		<description><![CDATA[OK, So, I just got an email from Ken, a dude who surfed across this OpenAL stuff on my blog, had some troubles, and asked me for help. He is having trouble unloading buffers and then re-using them again without getting some esoteric OpenAL errors. So I went through the snippets he sent me very [...]]]></description>
			<content:encoded><![CDATA[<p>OK, So, I just got an email from Ken, a dude who surfed across this OpenAL stuff on my blog, had some troubles, and asked me for help.  He is having trouble unloading buffers and then re-using them again without getting some esoteric OpenAL errors.  </p>
<p>So I went through the snippets he sent me very quickly and threw out some advice.  Ken came back with a few more questions and I went over the code again and noticed this:</p>
<pre>&nbsp;
          // use the static buffer data API
          alBufferDataStaticProc(buffer, format, data, size, freq);
&nbsp;</pre>
<p>Ah-HA!  I said, that is probably your problem right there!  alBufferDataStatic should be avoided unless you <strong>need</strong> it.  When do you know if you will need it?  Here is a rule of thumb: If you dont know the answer to that question then you dont need it.</p>
<p>(I don't want to seem to be picking on Ken, this problem is so common that I decided I needed to do a post about it (similar to my rant about never using the sample code from Apple in a shipping app))</p>
<p>OK, so why do I think you should avoid it? I am sure you have heard that if you want the best performance then you should be using alBufferDataStatic() right?!  No.</p>
<p>Well, what is alBufferDataStatic() anyway?  alBufferDataStatic puts the onus of memory management for all your buffer data onto your code.  </p>
<p>Let me repeat that:  When using alBufferDataStatic() <strong>YOU</strong> are responsible for all the memory management.</p>
<p>That is it.  That is your big performance boost.  </p>
<p>Wait! Really? that is all it does?</p>
<p>Yes. </p>
<p>The iPhone's shared memory space and the way it handles memory and the way your app gets jettisoned if you use too much is a very unique situation.  A situation that requires that you often have to really closely handle your memory.  So!  That means that if you are trying to squeeze every single last byte of memory out of the iPhone so that your fully immersive 3d first-person-shooter can keep a consistent 30FPS then you will probably want to spend a few weeks tweaking your sound code so that you have very close control of your memory at all times.  </p>
<p>For the other %99.9999 percent of apps that might want to use OpenAL (even if you are using lots of sounds) you are just adding extra headaches to your code by using alBufferDataStatic(). Here is another rule of thumb:  If you are not employing a developer whose sole job is to handle the sound code in your app, then you don't need alBufferDataStatic().</p>
<p>Have a quick read of the <a href="http://developer.apple.com/iphone/library/technotes/tn2008/tn2199.html">technote</a> that mentions alBufferDataStatic().</p>
<p>What does this really mean?</p>
<p>It means this:  when you use alBufferData() you load your sound data into a local buffer (one that you have to malloc) then when you call alBufferData(), OpenAL copies all those bytes into it's own buffer that it deals with.  Then you free your local storage and OpenAL now owns that buffer.  The downside: for a brief moment, you have 2 copies of your sound in memory.  The upside: very very easy memory management.  </p>
<p>If you are getting jettisoned right here, during this buffer copy, then you may need alBufferDataStatic(). But more likely you have done a crap job of handling your memory elsewhere.  (also it is good to note that if you are loading big sounds into memory you are doing it wrong anyway, those big sounds should be streamed).  </p>
<p>Ok, you are absolutely, positively sure that you need to manage your own sound memory?  Maybe you should be using alBufferDataStatic(), but first: here is yet another rule of thumb: if you are reading this blog post to see if you need to use it; you don't.  go to your code right now and take it out.  Just take it out.  </p>
<p>Obviously I am being a bit hyperbolic in an attempt to make a point.  I dont know about your code, but here is a small list of the most common bugs I find in my code:</p>
<ul>
<li> Forgot to release an object properly and it leaks and eventually my app is jettisoned</li>
<li> Accidentally released an autoreleased object, causing a crash</li>
<li> Accidentally released an object owned by some other object, causing it to crash much much later</li>
<li>malloced some space and forgot to free it, causing a leak and eventual jettison</li>
<li>freed some malloced space and then tried to use it, causing my app to go batshit crazy</li>
</ul>
<p>The list goes on.  But can you see a common thread?  Memory.  Why would I want to add yet more memory management responsibilities when I dont need it? Why do developers always insist on making their own lives so much more difficult than they have to?</p>
<p>Here are a few platitudes:</p>
<ul>
<li>Less code == Less bugs.  More code == More bugs.  Therefore Less Code is always better.</li>
<li>Do not add any code you dont need right now.  (this is very common, you think to yourself: Hmm I am already here in this object, and I could see that I might need a method that does X in the future so I will just write it now so I dont have to write it then.  Wrong.  In that 'future' when you do need it, it will need to do Y, not X and you will have to re-write it.  Or, more likely you will never need a method that does X, and you just wasted a bunch of time and added more code</li>
<li>Do not prematurely optimize.  Get the code working first.  Then go back and identify the places you need to smooth out.  If you try to optimize as you go then you will end up spending all your time making that one method totally awesome (only to realize later that method only gets called once every few seconds, so really it could be the least efficient bit of code ever and nobody would ever notice.)
</li>
</ul>
<p>So, by using alBufferDataStatic() you are breaking all three of my lovely platitudes.  </p>
<p>Dont do it.  </p>
<p>You are only causing yourself grief and making your code buggy and shitty.  Use alBufferData(). It works.  It is easy.  The highly experienced engineers who work on OpenAL have made sure that there are no memory issues with alBufferData(). If you decide to port your code,  alBufferData() will still work!  alBufferData() makes your breath smell minty! alBufferData() will totally pull chicks.</p>
<p>I have put OpenAL code into about 6 apps now.  A few games and a few utilities.  And one 'sound board' style app that played 32 sounds simultaneously (which was the max at the time, probably still is) and was able to handle gigantic sounds files (via streaming) without ever using alBufferDataStatic().  Was this some herculean task of super-awesome mad coding skillzzzz? </p>
<p>No. Just the opposite actually.  I keep all my code as absolutely bare-minimum simple as I can.  </p>
<p>Keep your code simple, don't use stuff you don't need. </p>
<p>Cheers!<br />
-B</p>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2009/09/20/albufferdatastatic-why-you-should-avoid-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WWDC 2009</title>
		<link>http://benbritten.com/2009/05/18/wwdc-2009/</link>
		<comments>http://benbritten.com/2009/05/18/wwdc-2009/#comments</comments>
		<pubDate>Mon, 18 May 2009 07:36:50 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[multitouch]]></category>
		<category><![CDATA[openAL]]></category>
		<category><![CDATA[openSoundControl]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=354</guid>
		<description><![CDATA[I will be there. If you are also going to be there, and you want to meet up and get a beer, or talk about anything on my blog or anything else really, then drop me a line at support@benbritten.com, or follow my rarely updated twitter: http://twitter.com/benbritten. I plan to use it during WWDC to [...]]]></description>
			<content:encoded><![CDATA[<p>I will be there.  </p>
<p>If you are also going to be there, and you want to meet up and get a beer, or talk about anything on my blog or anything else really, then drop me a line at support@benbritten.com, or follow my rarely updated twitter: <a href="http://twitter.com/benbritten">http://twitter.com/benbritten</a>.  I plan to use it during WWDC to help people find me and to help me find people.  Otherwise I rarely use it, so dont go looking for profound wisdom from my twitter feed.</p>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2009/05/18/wwdc-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lots and Lots of sounds in openAL</title>
		<link>http://benbritten.com/2009/05/02/lots-and-lots-of-sounds-in-openal/</link>
		<comments>http://benbritten.com/2009/05/02/lots-and-lots-of-sounds-in-openal/#comments</comments>
		<pubDate>Sat, 02 May 2009 03:26:08 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[openAL]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=302</guid>
		<description><![CDATA[There has been a flurry of openAL related stuff going on in my life in the last few days, and that reminded me that I have a few half-finished posts that I keep meaning to finish.. Also, I have found at least one other blog that has copied my code (and even my blog posts!) [...]]]></description>
			<content:encoded><![CDATA[<p>There has been a flurry of openAL related stuff going on in my life in the last few days, and that reminded me that I have a few half-finished posts that I keep meaning to finish.. </p>
<p>Also, I have found at least one other blog that has copied my code (and even my blog posts!) with out even rewording the text!, so that is kinda cool i guess :-) (although I would have liked at least a courtesy link :-)</p>
<p>OK, today: lots and lots of sounds.  </p>
<p>In my older posts I mentioned that there is an upper limit to the number of simultaneous sounds you can play in openAL.  (in other words the most concurrent sources).  At some point (around  32) you can no longer get any more sources via:</p>
<pre class="objc">&nbsp;
alGenSources<span style="color: #002200;">&#40;</span><span style="color: #0000dd;">1</span>, &amp;sourceID<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>the downside is that this just quietly fails, and does not seem to raise an error.    The moral of this story: don't ask for more than 32 sources! (note: this is on iPhone OS 2.2, might be different on other OS versions and platforms)</p>
<p>So what does this mean? it means that no matter what, you cannot have more than 32 sounds playing in the same instant. This really should never be a problem.  If your goal is to simulate and entire orchestra by playing each instrument individually, then you are probably not going to want to be doing it on the iPhone. (although you can actually get past this limit by building the buffers yourself, but really, more than 32 sounds? come on!)</p>
<p>That said, you may have more than 32 sounds in your app, and if you follow my simple example from past posts, i suggested that you assign each sound buffer to a single source and just call that source when you need to play the sound. </p>
<p>This works well for lots of scenarios.  However, not so much if you have more than 32 sounds in your app. So how do we deal with that?  I mentioned it briefly in an older post: you need to have a way to hand out the sources you are not using to the buffers that need to be played.  </p>
<p>This is actually pretty simple and I will show you how!</p>
<p>First, you may want to preload your sources.  This is not strictly necessary, but I like to keep the processing to a minimum at the point I want to play the sounds, so I like to have everything ready to go up front.</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// note: MAX_SOURCES is how many source you want</span>
<span style="color: #ff0000;">// to preload.  should keep it below 32</span>
-<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #002200;">&#41;</span>preloadSources
<span style="color: #002200;">&#123;</span>
        <span style="color: #ff0000;">// lazy init of my data structure</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>sources == <span style="color: #0000ff;">nil</span><span style="color: #002200;">&#41;</span> sources = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSMutableArray.html"><span style="color: #0000ff;">NSMutableArray</span></a> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// we want to allocate all the sources we will need up front</span>
	NSUInteger sourceCount = MAX_SOURCES;
	NSInteger sourceIndex;
	NSUInteger sourceID;
	<span style="color: #ff0000;">// build a bunch of sources and load them into our array.</span>
	<span style="color: #0000ff;">for</span> <span style="color: #002200;">&#40;</span>sourceIndex = <span style="color: #0000dd;">0</span>; sourceIndex &lt; sourceCount; sourceIndex++<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		alGenSources<span style="color: #002200;">&#40;</span><span style="color: #0000dd;">1</span>, &amp;sourceID<span style="color: #002200;">&#41;</span>;
		<span style="color: #002200;">&#91;</span>sources addObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInt:sourceID<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>pretty simple really, just have openAL build a bunch of sources and store those IDs somewhere.  You can actually have openAL build all the sources at once by calling alGenSources with a number besides 1, and store them in a C-style array, but I like to keep my stuff obj-c because I am lazy and dont like to malloc/free if I dont have to.</p>
<p>Now, the old play sound method looked like so:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// the main method: grab the sound ID from the library</span>
<span style="color: #ff0000;">// and start the source playing</span>
- <span style="color: #002200;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #002200;">&#41;</span>playSound:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>soundKey
<span style="color: #002200;">&#123;</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * numVal = <span style="color: #002200;">&#91;</span>soundDictionary objectForKey:soundKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>numVal == <span style="color: #0000ff;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span>;
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>;
	alSourcePlay<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>But that was back in the olden days when we assigned a single source to a single buffer.  Now we dont have any source pre-assigned, we need to attach them at play-time.  </p>
<p>so we want something like this:</p>
<pre class="objc">&nbsp;
- <span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>playSound:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>soundKey gain:<span style="color: #002200;">&#40;</span>ALfloat<span style="color: #002200;">&#41;</span>gain pitch:<span style="color: #002200;">&#40;</span>ALfloat<span style="color: #002200;">&#41;</span>pitch loops:<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">BOOL</span><span style="color: #002200;">&#41;</span>loops
<span style="color: #002200;">&#123;</span>
	ALenum err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>; <span style="color: #ff0000;">// clear error code </span>
&nbsp;
	<span style="color: #ff0000;">// first, find the buffer we want to play</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * numVal = <span style="color: #002200;">&#91;</span>soundLibrary objectForKey:soundKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>numVal == <span style="color: #0000ff;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span>;
	NSUInteger bufferID = <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>;	
&nbsp;
	<span style="color: #ff0000;">// now find an available source</span>
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span>self _nextAvailableSource<span style="color: #002200;">&#93;</span>;	
&nbsp;
	<span style="color: #ff0000;">// make sure it is clean by resetting the source buffer to 0</span>
	alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFER, <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #ff0000;">// attach the buffer to the source</span>
	alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFER, bufferID<span style="color: #002200;">&#41;</span>; 
&nbsp;
	<span style="color: #ff0000;">// set the pitch and gain of the source</span>
	alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_PITCH, pitch<span style="color: #002200;">&#41;</span>;
	alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_GAIN, gain<span style="color: #002200;">&#41;</span>;
&nbsp;
	<span style="color: #ff0000;">// set the looping value</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>loops<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_LOOPING, AL_TRUE<span style="color: #002200;">&#41;</span>;
	<span style="color: #002200;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #002200;">&#123;</span>
		alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_LOOPING, AL_FALSE<span style="color: #002200;">&#41;</span>;
	<span style="color: #002200;">&#125;</span>
	<span style="color: #ff0000;">// check to see if there are any errors</span>
	err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #002200;">&#91;</span>self _error:err note:@<span style="color: #666666;">&quot;Error Playing Sound!&quot;</span><span style="color: #002200;">&#93;</span>;
		<span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span>;
	<span style="color: #002200;">&#125;</span>
        <span style="color: #ff0000;">// now play!</span>
	alSourcePlay<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">return</span> sourceID; <span style="color: #ff0000;">// return the sourceID so I can stop loops easily</span>
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Ok, it is important to note in this new method that we are no longer getting a sourceID out of our soundLibrary, but a buffer ID, so you will need to store the buffers instead of the sources. (I will leave that as an exercise for the reader, but if this doesnt make sense, I can post my buffer-loading code as well.  However it is really just exactly like the stuff in the earlier posts)</p>
<p>OK, so that method looks pretty easy! wait! what is this line:</p>
<pre class="objc">&nbsp;
	<span style="color: #ff0000;">// now find an available source</span>
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span>self _nextAvailableSource<span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>Ahh yes, this is where the magic happens.  It is pretty simple tho: we just step through our list of sources, find one that is not being used, and return it.</p>
<pre class="objc">&nbsp;
-<span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>_nextAvailableSource
<span style="color: #002200;">&#123;</span>
	NSInteger sourceState; <span style="color: #ff0000;">// a holder for the state of the current source</span>
&nbsp;
	<span style="color: #ff0000;">// first check: find a source that is not being used at the moment.</span>
	<span style="color: #0000ff;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * sourceNumber in sources<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		alGetSourcei<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>, AL_SOURCE_STATE, &amp;sourceState<span style="color: #002200;">&#41;</span>;
		<span style="color: #ff0000;">// great! we found one! return it and shunt</span>
		<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>sourceState != AL_PLAYING<span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span> <span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;
	<span style="color: #ff0000;">// in the case that all our sources are being used, we will find the first non-looping source</span>
	<span style="color: #ff0000;">// and return that.</span>
	<span style="color: #ff0000;">// first kick out an error</span>
       NSLog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;available source overrun, increase MAX_SOURCES&quot;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
	NSInteger looping;
	<span style="color: #0000ff;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * sourceNumber in sources<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		alGetSourcei<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>, AL_LOOPING, &amp;looping<span style="color: #002200;">&#41;</span>;
		<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>!looping<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
			<span style="color: #ff0000;">// we found one that is not looping, cut it short and return it</span>
			NSUInteger sourceID = <span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>;
			alSourceStop<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;
			<span style="color: #0000ff;">return</span> sourceID;
		<span style="color: #002200;">&#125;</span>
	<span style="color: #002200;">&#125;</span>
&nbsp;
	<span style="color: #ff0000;">// what if they are all loops? arbitrarily grab the first one and cut it short</span>
	<span style="color: #ff0000;">// kick out another error</span>
       NSLog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;available source overrun, all used sources looping&quot;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>sources objectAtIndex:<span style="color: #0000dd;">0</span><span style="color: #002200;">&#93;</span> unsignedIntegerValue<span style="color: #002200;">&#93;</span>;
	alSourceStop<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">return</span> sourceID;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>So, what is happening here?  Really, 99% of the cases will be caught in the first loop.  You just run through the array, find one that is not playing and return it.  In my experience, even in a pretty sound-intense app (like a beat-box where you are mashing on keys and playing samples) you rarely get more than a couple of sounds that are actually playing at once (unless your samples are very long) so this will return very quickly.</p>
<p>But what if everything is already playing?  You have a few options: Easy: increase you max_sources until this problem goes away, harder: (but still pretty easy) generate new sources on the fly when you run out.</p>
<p>Now if you manage to use up all 32 sources and still find yourself calling this method for another source, then the last 2 chunks of code in the above method will take care of it.  The way you handle a source overrun is really application specific.  but in the above case I am presuming that new sounds are more important than old sounds, and loops are more important than effects: so we have a 2 step process to find a sound to kill.  </p>
<p>first we look to find the first non-looping sound and we kill it (cutting it off) and return that source.  In the second case we have MAX loops running, so we just grab the first source, cut it short and return it.  </p>
<p>Now, your app might have different requirements if you run out of sources.  so you could handle that in lots of different ways.  This was probably the easiest and it works for all the apps I have done (I tend to 'tune' the MAX number until I never get an overrun, even during heavy sound usage, so these are really just worst case 'graceful failing')</p>
<p>OK, that is about it for today!<br />
Happy sound playing :-)</p>
<p>Oh! One last thing:  the code above will work fine, but it is not my production code :-)  I tend to remove all the extra error checking and stuff like that to keep the code clean and easy to read for the examples, so be sure to put error checks back into the code if you plan to use it ! </p>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2009/05/02/lots-and-lots-of-sounds-in-openal/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>restarting openAL after application interruption on the iPhone</title>
		<link>http://benbritten.com/2009/02/02/restarting-openal-after-application-interruption-on-the-iphone/</link>
		<comments>http://benbritten.com/2009/02/02/restarting-openal-after-application-interruption-on-the-iphone/#comments</comments>
		<pubDate>Sun, 01 Feb 2009 23:22:11 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[openAL]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=234</guid>
		<description><![CDATA[Hey All, I have been fiddling with openAL on the iPhone for awhile now, and have discovered a few things. If you havent already read it, (and want a basic overview of openAL on the iPhone) have a look at the openAL tutorial I posted a while back. Today I want to talk a bit [...]]]></description>
			<content:encoded><![CDATA[<p>Hey All,</p>
<p>I have been fiddling with openAL on the iPhone for awhile now, and have discovered a few things.  If you havent already read it, (and want a basic overview of openAL on the iPhone) have a look at the<a href="http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/"> openAL tutorial</a> I posted a while back.</p>
<p>Today I want to talk a bit about how the Audio Sessions system interacts with the openAL stuff on the iPhone, and how to get it all working in your app. It took me a looong time to figure this out and get all the little bits in the right place at the right time. Many thanks to the contributors at the apple iphone dev forums, couldn't have done it without them. In any case, hopefully this will save someone out there some time trying to figure this all out. </p>
<p>First off: WTF are Audio Sessions?  From the docs: </p>
<p>"Audio Session Services is a C interface for managing an application’s audio behavior in the context of other applications."</p>
<p>So basically, if you want your app to play nice with other sound making things on the iPhone, you will need to deal with Audio Sessions.  The biggest reason to do this is so that you can play your iPod music and have it mix with the sound that your app is generating. </p>
<p>So, lets get right into it.</p>
<p>First off, you need to let the Audio Session Service know that your app exists and give it a way to talk to you via a method callback:</p>
<pre class="objc">&nbsp;
OSStatus result = AudioSessionInitialize<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, interruptionListenerCallback, self<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>The first two params that I am passing as NULL specify which run loop and what run loop mode you want to use when calling the callback method.  passing NULL basically says: "Use the main run loop, and the default run mode", which for our purposes here is going to be fine.</p>
<p>the third param is the callback method pointer, more on that in a moment.</p>
<p>and lastly, the final param is the object that is the target of the callback message.</p>
<p>OK, now we have let the Audio Sessions know that our app exists, the next thing to do is tell it what kind of sound we will be generating. We do this with an audio category.</p>
<p>There are a handful of valid categories:<br />
kAudioSessionCategory_UserInterfaceSoundEffects<br />
kAudioSessionCategory_AmbientSound<br />
kAudioSessionCategory_MediaPlayback<br />
kAudioSessionCategory_LiveAudio<br />
kAudioSessionCategory_RecordAudio<br />
kAudioSessionCategory_PlayAndRecord</p>
<p>If any of these sound like your app, then look em up in the docs and double check.  I am going to talk about the two that I use for most everything: kAudioSessionCategory_AmbientSound and kAudioSessionCategory_MediaPlayback.</p>
<p>kAudioSessionCategory_AmbientSound: This one is for 'longer' sound playback, but works fine for short sounds as well.  It is what i refer to as the 'game category'; good for games. good to play longer looping background sounds (like a rockin soundtrack, or atmospheric noises) as well as short effects (like gunshots or interface clicks) This category will also allow the iPod music to mix with your app sounds.</p>
<p>kAudioSessionCategory_MediaPlayback: this is good if you have your own music and do NOT want to allow the ipod to play while your app is active.  Basically this one tells the iPhone that you want your app to be the only source of sound. Good for things that generate music, or where it doesnt make sense to allow for iPod sound.</p>
<p>OK, so how do we tell the audio session about our category?</p>
<pre class="objc">&nbsp;
UInt32 category = kAudioSessionCategory_AmbientSound;
OSStatus result = AudioSessionSetProperty<span style="color: #002200;">&#40;</span>kAudioSessionProperty_AudioCategory, <a href="http://www.opengroup.org/onlinepubs/009695399/functions/sizeof.html"><span style="color: #0000dd;">sizeof</span></a><span style="color: #002200;">&#40;</span>category<span style="color: #002200;">&#41;</span>, &amp;category<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>Pretty easy really, just set the property and you are done.  </p>
<p>OK, with just those few lines of code your app will play nice with other apps and allow (or not) iPod music to mix with your sound.</p>
<p>But there is one more thing we need to do: handle sound interruptions.  Like an alarm or phone call.  (note: if you get a phone call and answer it, then your app will be dismissed.  However if you get a phone call an ignore it, then your app will get the interruption call. Of course, on the Touch you dont get calls but you can still get alarm clock interruptions etc..)</p>
<p>OK, so we need to define a callback method.  this needs to be some ugly C code, so all you Cocoa-only types, just hold your nose and cut and paste :-)</p>
<pre class="cpp">&nbsp;
<span style="color: #0000ff;">void</span> interruptionListenerCallback <span style="color: #000000;">&#40;</span><span style="color: #0000ff;">void</span>   *inUserData, UInt32    interruptionState <span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
&nbsp;
        <span style="color: #ff0000;">// you could do this with a cast below, but I will keep it here to make it clearer</span>
	YourSoundControlObject *controller = <span style="color: #000000;">&#40;</span>YourSoundControlObject *<span style="color: #000000;">&#41;</span> inUserData;
&nbsp;
	<span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>interruptionState == kAudioSessionBeginInterruption<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
		<span style="color: #000000;">&#91;</span>controller _haltOpenALSession<span style="color: #000000;">&#93;</span>;
	<span style="color: #000000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>interruptionState == kAudioSessionEndInterruption<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
		<span style="color: #000000;">&#91;</span>controller _resumeOpenALSession<span style="color: #000000;">&#93;</span>;
	<span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;</pre>
<p>What is going on here?  Pretty simple really;  the inUserData is a pointer to your object (or whatever obejct you put in for the last param above when you called AudioSessionInitialize()), and interruption state is an enum so you know if you are being interrupted or resumed.</p>
<p>I like to get right out of the ugly C code and right back into the lovely land of Cocoa by calling some cocoa methods on my controller object. (though you could just call the openAL and audio session functions from right there, but it is ugly)</p>
<p>So, how do we halt and resume openAL?</p>
<p>first thing, let the audio sessions know that you are shutting down</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// Deactivate the current audio session</span>
AudioSessionSetActive<span style="color: #002200;">&#40;</span>NO<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>Next, shut down openAL in a nice way so you can keep your context intact:</p>
<pre lang = objc">
// set the current context to NULL will 'shutdown' openAL
alcMakeContextCurrent(NULL);
// now suspend your context to 'pause' your sound world
alcSuspendContext(mContext);
</pre>
<p>easy.</p>
<p>And to come back from the above halting?</p>
<p>Basically the same thing in reverse, but with one added twist: you have to re-register your audio session category:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// Reset audio session</span>
UInt32 category = kAudioSessionCategory_AmbientSound;
AudioSessionSetProperty <span style="color: #002200;">&#40;</span> kAudioSessionProperty_AudioCategory, <a href="http://www.opengroup.org/onlinepubs/009695399/functions/sizeof.html"><span style="color: #0000dd;">sizeof</span></a> <span style="color: #002200;">&#40;</span>category<span style="color: #002200;">&#41;</span>, &amp;category <span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// Reactivate the current audio session</span>
AudioSessionSetActive<span style="color: #002200;">&#40;</span>YES<span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// Restore open al context</span>
alcMakeContextCurrent<span style="color: #002200;">&#40;</span>mContext<span style="color: #002200;">&#41;</span>;
<span style="color: #ff0000;">// 'unpause' my context</span>
alcProcessContext<span style="color: #002200;">&#40;</span>mContext<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>And that is it.  That will allow your openAL app to play nice with the rest of the system and recover from interruptions.</p>
<p><strong>edit: </strong> renato reminds me in the comments that you should always be checking your error codes.  Otherwise openAL can choke on some small issue and it wont work until that code has been cleared. </p>
<p>I tend to put one of these after every call to openAL: like so:</p>
<pre class="objc">&nbsp;
alSourceQueueBuffers<span style="color: #002200;">&#40;</span>sourceID, <span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
ALEnum err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> NSlog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;Error Calling alSourceQueueBuffers: %d&quot;</span>,err<span style="color: #002200;">&#41;</span>;
&nbsp;
alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_PITCH, pitch<span style="color: #002200;">&#41;</span>;
err = alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>err != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> NSlog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;Error Calling alSourcef with AL_PITCH: %d&quot;</span>,err<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>and so on.  </p>
<p>Cheers!<br />
-ben</p>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2009/02/02/restarting-openal-after-application-interruption-on-the-iphone/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>More openAL tidbits for iPhone</title>
		<link>http://benbritten.com/2009/01/24/more-openal-tidbits-for-iphone/</link>
		<comments>http://benbritten.com/2009/01/24/more-openal-tidbits-for-iphone/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 22:54:45 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[openAL]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=217</guid>
		<description><![CDATA[Hey All, my last post (which was a zillion years ago it seems) was about openAL. It has gotten quite a bit of traffic in the past few months, so apparently openAL on the iPhone is something people are interested in. So i am going to post this which is a few more tidbits that [...]]]></description>
			<content:encoded><![CDATA[<p>Hey All,</p>
<p>my last post (which was a zillion years ago it seems) was about openAL.  It has gotten quite a bit of traffic in the past few months, so apparently openAL on the iPhone is something people are interested in.  So i am going to post this which is a few more tidbits that I have discovered over the intervening months about openAL.</p>
<p>First off, i have noticed that the vast majority of people are taking apple's sample code 'SoundEngine' and plopping it directly into their code, and then spending countless hours and days trying to get it to work just right for them.  </p>
<p>Here is my advice:</p>
<p>Dont.</p>
<p>Look, I love the apple engineers, I love the work they do, but sample code is just that; a sample.  It is meant to show you all the various different ways you can do something.  the SoundEngine code does way more than you should ever really need. Your best bet is to start from scratch, figure out what your sound needs are and build you own sound controller object.  If you do this you will be in a much better place to debug (because you will know how it all works) and you will be able to add only the code your app needs, and less code means less bugs.</p>
<p>What you say? What about code re-use?!  I shouldnt reinvent the wheel, I dont fall into the 'not invented here' trap!! Heresy!</p>
<p>to that I say: you are re-using code. you are re-using the openAL codebase.  but it turns out at the level that you are gluing openAL into your app, you should strive to make your own implementation geared towards what you need. </p>
<p>This is especially true for the iPhone.  If there is any code in your app that you can get rid of by pre-formatting your sounds then you should be doing that.  There is absolutely no reason that your sounds should be in more than 2 formats (ie an uncompressed format for your short sounds and a compressed format for anything longer) if you are checking the type and format of your sound files at runtime you are doing it wrong.  Pick a sample frequency and format (stereo/mono) that works with all your sounds and make them all the same.  This will simplify your code immensely and simpler code == less bugs == better performance.</p>
<p>Anyway, that was a bit of a rant.  But I see so many posts to the apple dev forums that are like: "I am using SoundEngine from the crashLanding app and i am having this problem..."</p>
<p>Really, openAL is not that hard.  I spent about 2 hours with the programmer guide and I got my simple sound controller working and wrote a <a href="http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/">tutorial</a> since i was such an expert by then.  That and the resulting code was about a tenth the size and complexity as soundEngine and I have had very few problems with it (and the problems I have had were easy to track down and debug because there just is not that much code there.</p>
<p>Anyhow, I really did mean to have some technical advice in here, and not just rant, however this is getting long, so it may have to wait until another post. :-)</p>
<p>-b</p>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2009/01/24/more-openal-tidbits-for-iphone/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>openAL sound on the iPhone</title>
		<link>http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/</link>
		<comments>http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/#comments</comments>
		<pubDate>Thu, 06 Nov 2008 02:25:05 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[openAL]]></category>

		<guid isPermaLink="false">http://benbritten.com/?p=216</guid>
		<description><![CDATA[Hey all, Now that the NDA is lifted, and we can start talking about the iPhone code out in the open, i thought it might be nice to talk about some of the problems I have encountered in my forays into the iPhone world and how I went about fixing them. Currently I am working [...]]]></description>
			<content:encoded><![CDATA[<p>Hey all,</p>
<p>Now that the NDA is lifted, and we can start talking about the iPhone code out in the open, i thought it might be nice to talk about some of the problems I have encountered in my forays into the iPhone world and how I went about fixing them.</p>
<p>Currently I am working on an iPhone game.  It is all openGLES based and uses openAL for sound. I think I am gonna talk about openAL today.</p>
<p>For now I am only going to be talking about sounds that are less than 30 seconds, so sound effects and short loops. Before you can think about playing sounds on the iPhone they need to be in the right format (or they should be in the right format, many of the audio toolbox methods will handle multiple formats, but if you put the sound in the right format to start, then the iPhone wont have to do it at play time). </p>
<p>So, pop open terminal and type this:</p>
<pre class="bash">&nbsp;
/usr/bin/afconvert -f caff -d LEI16@<span style="color: #000000;">44100</span> inputSoundFile.aiff outputSoundFile.caf
&nbsp;</pre>
<p>what the hell does that do? you ask.  it puts the file into a nice Little-Endian 16-bit 44,100 sample rate format.  (generally saved with a .caf extension)</p>
<p>OK! now we have a nice .caf file in the proper format, we are ready to do something.</p>
<p>There are lots of ways to play sound on the iPhone, there is the 'easy' way, and then there are a few 'hard ways'.. I am gonna touch on the easy way quickly and then move onto the openAL 'hard way'.</p>
<p>the quickest (and easiest) way to make the iPhone spit out some sound is to use the audio system services:</p>
<pre class="objc">&nbsp;
<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>* path = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSBundle.html"><span style="color: #0000ff;">NSBundle</span></a> mainBundle<span style="color: #002200;">&#93;</span> pathForResource:@<span style="color: #666666;">&quot;soundEffect1&quot;</span> ofType:@<span style="color: #666666;">&quot;caf&quot;</span><span style="color: #002200;">&#93;</span>;
<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSURL.html"><span style="color: #0000ff;">NSURL</span></a> * afUrl = <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSURL.html"><span style="color: #0000ff;">NSURL</span></a> fileURLWithPath:path<span style="color: #002200;">&#93;</span>;
UInt32 soundID;
AudioServicesCreateSystemSoundID<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#40;</span>CFURLRef<span style="color: #002200;">&#41;</span>afUrl,&amp;soundID<span style="color: #002200;">&#41;</span>;
AudioServicesPlaySystemSound <span style="color: #002200;">&#40;</span>soundID<span style="color: #002200;">&#41;</span>;
&nbsp;</pre>
<p>this works well for making your interface buttons click and simple UI interaction stuff. However, it is absolutely shite for anything more complicated than that (think: a game).  It doest always play right away, and if you are trying to match up specific frame of your game with specific sound effects, then this method is basically useless.  (I actually implemented my whole sound engine using the above style of code, then i got onto the phone and every time a sound played, it was either late by many frames or the whole thing would pause and wait for the audio toolbox to load the sound into the buffer, it sucked. </p>
<p>For better control of the sound, you will require either openAL or audioUnits or the audioQueue.</p>
<p>I decided to go with openAL so that my sound code could be kinda sorta portable, and by learning how to use openAL I would be able to use those skills on some other platform besides the iPhone.  (and since I am a code-mercenary, i figured that having openAL experience was more marketable than audioQueue experience) (that and I already have familiarity with openGL, and openAL is very similar, and the audio units and audio queue code is kinda ugly)</p>
<p>So, this will be a super quick tutorial on openAL and the absolute bare minimum you need to do to accomplish static sound generated from openAL.</p>
<p>OpenAL is really quite straight forward. there are 3 main entities: the Listener, the Source, and the Buffer.</p>
<p>The Listener is you. Any sound the listener can 'hear' comes out the speakers. openAL allows you to specify where the listener is in relation to the sources, but for this example we dont care, we are going to bare minimum static sound, so just keep in mind that there is a concept of 'listener' and that you could move this object around if you wanted to do more complicated stuff, but I wont go into it in this post.</p>
<p>The Source: basically this is analogous to a speaker.  it generates sound which the listener can 'hear'.  like the listener, you can move the sources around and get groovy positional effects.  However, for this example we wont be doing that.</p>
<p>The buffer: basically this is the sound that will be played.  the buffer holds the raw audio data.  </p>
<p>there are two other very important objects: the device and the context.<br />
the device is the actual bit of hardware that will be playing the sound, and the context is the current 'session' that all these sounds are going to be played in (you can think of it as the room that all the sources and the listener is in. Or it is the air that the sound is played through, or whatever.. it is the context.)</p>
<p>How does this all work: (this is the bare minimum)</p>
<p>1) get the device<br />
2) make a context with the device<br />
3) put some data into a buffer<br />
4) attach the buffer to a source<br />
5) play the source</p>
<p>that is it!  The above presumes that your implementation of openAL has decent defaults for the listener and if you dont specify any listener or source positions then this will all work dandy. (it works just dandy on the iPhone in any case)</p>
<p>so, lets look at some code:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// define these somewhere, like in your .h file</span>
ALCcontext* mContext;
ALCdevice* mDevice;
&nbsp;
<span style="color: #ff0000;">// start up openAL</span>
-<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #002200;">&#41;</span>initOpenAL
<span style="color: #002200;">&#123;</span>
	<span style="color: #ff0000;">// Initialization</span>
	mDevice = alcOpenDevice<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">NULL</span><span style="color: #002200;">&#41;</span>; <span style="color: #ff0000;">// select the &quot;preferred device&quot;</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>mDevice<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #ff0000;">// use the device to make a context</span>
		mContext=alcCreateContext<span style="color: #002200;">&#40;</span>mDevice,<span style="color: #0000ff;">NULL</span><span style="color: #002200;">&#41;</span>;
		<span style="color: #ff0000;">// set my context to the currently active one</span>
		alcMakeContextCurrent<span style="color: #002200;">&#40;</span>mContext<span style="color: #002200;">&#41;</span>;
	<span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Pretty straight forward really.  get the 'default' device. then use it to build a context! done.</p>
<p>Next: put data into a buffer, this is a bit more complicated:</p>
<p>First: you need to open the file in a nice audio-friendly way</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// get the full path of the file</span>
<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>* fileName = <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSBundle.html"><span style="color: #0000ff;">NSBundle</span></a> mainBundle<span style="color: #002200;">&#93;</span> pathForResource:@<span style="color: #666666;">&quot;neatoEffect&quot;</span> ofType:@<span style="color: #666666;">&quot;caf&quot;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #ff0000;">// first, open the file</span>
AudioFileID fileID = <span style="color: #002200;">&#91;</span>self openAudioFile:fileName<span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>wait! what is that: openAudioFile: method?<br />
here it is:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// open the audio file</span>
<span style="color: #ff0000;">// returns a big audio ID struct</span>
-<span style="color: #002200;">&#40;</span>AudioFileID<span style="color: #002200;">&#41;</span>openAudioFile:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>filePath
<span style="color: #002200;">&#123;</span>
	AudioFileID outAFID;
	<span style="color: #ff0000;">// use the NSURl instead of a cfurlref cuz it is easier</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSURL.html"><span style="color: #0000ff;">NSURL</span></a> * afUrl = <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSURL.html"><span style="color: #0000ff;">NSURL</span></a> fileURLWithPath:filePath<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// do some platform specific stuff..</span>
<span style="color: #339900;">#if TARGET_OS_IPHONE</span>
	OSStatus result = AudioFileOpenURL<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#40;</span>CFURLRef<span style="color: #002200;">&#41;</span>afUrl, kAudioFileReadPermission, <span style="color: #0000dd;">0</span>, &amp;outAFID<span style="color: #002200;">&#41;</span>;
<span style="color: #339900;">#else</span>
	OSStatus result = AudioFileOpenURL<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#40;</span>CFURLRef<span style="color: #002200;">&#41;</span>afUrl, fsRdPerm, <span style="color: #0000dd;">0</span>, &amp;outAFID<span style="color: #002200;">&#41;</span>;
<span style="color: #339900;">#endif</span>
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>result != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> NSLog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;cannot openf file: %@&quot;</span>,filePath<span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">return</span> outAFID;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>this is pretty simple: we get the file path from the main bundle, then send it off to this handy method which checks the platform and uses the audio toolkit method: AudioFileOpenURL() to generate an AudioFileID.</p>
<p>What's next? Oh yes: get the actual audio data out of the file. To do this we need to figure out how much data is in the file:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// find out how big the actual audio data is</span>
UInt32 fileSize = <span style="color: #002200;">&#91;</span>self audioFileSize:fileID<span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>another handy method is needed:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// find the audio portion of the file</span>
<span style="color: #ff0000;">// return the size in bytes</span>
-<span style="color: #002200;">&#40;</span>UInt32<span style="color: #002200;">&#41;</span>audioFileSize:<span style="color: #002200;">&#40;</span>AudioFileID<span style="color: #002200;">&#41;</span>fileDescriptor
<span style="color: #002200;">&#123;</span>
	UInt64 outDataSize = <span style="color: #0000dd;">0</span>;
	UInt32 thePropSize = <a href="http://www.opengroup.org/onlinepubs/009695399/functions/sizeof.html"><span style="color: #0000dd;">sizeof</span></a><span style="color: #002200;">&#40;</span>UInt64<span style="color: #002200;">&#41;</span>;
	OSStatus result = AudioFileGetProperty<span style="color: #002200;">&#40;</span>fileDescriptor, kAudioFilePropertyAudioDataByteCount, &amp;thePropSize, &amp;outDataSize<span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">if</span><span style="color: #002200;">&#40;</span>result != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> NSLog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;cannot find file size&quot;</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #0000ff;">return</span> <span style="color: #002200;">&#40;</span>UInt32<span style="color: #002200;">&#41;</span>outDataSize;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>This uses the esoteric method: AudioFileGetProperty() to figure out how much sound data there is in the file and jams it into the outDataSize variable.  groovy, next!</p>
<p>Now we are ready to copy the data from the file into an openAL buffer:</p>
<pre class="objc">&nbsp;
&nbsp;
<span style="color: #ff0000;">// this is where the audio data will live for the moment</span>
<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> * outData = <a href="http://www.opengroup.org/onlinepubs/009695399/functions/malloc.html"><span style="color: #0000dd;">malloc</span></a><span style="color: #002200;">&#40;</span>fileSize<span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// this where we actually get the bytes from the file and put them</span>
<span style="color: #ff0000;">// into the data buffer</span>
OSStatus result = noErr;
result = AudioFileReadBytes<span style="color: #002200;">&#40;</span>fileID, <span style="color: #0000ff;">false</span>, <span style="color: #0000dd;">0</span>, &amp;fileSize, outData<span style="color: #002200;">&#41;</span>;
AudioFileClose<span style="color: #002200;">&#40;</span>fileID<span style="color: #002200;">&#41;</span>; <span style="color: #ff0000;">//close the file</span>
&nbsp;
<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>result != <span style="color: #0000dd;">0</span><span style="color: #002200;">&#41;</span> NSLog<span style="color: #002200;">&#40;</span>@<span style="color: #666666;">&quot;cannot load effect: %@&quot;</span>,fileName<span style="color: #002200;">&#41;</span>;
&nbsp;
NSUInteger bufferID;
<span style="color: #ff0000;">// grab a buffer ID from openAL</span>
alGenBuffers<span style="color: #002200;">&#40;</span><span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// jam the audio data into the new buffer</span>
alBufferData<span style="color: #002200;">&#40;</span>bufferID,AL_FORMAT_STEREO16,outData,fileSize,<span style="color: #0000dd;">44100</span><span style="color: #002200;">&#41;</span>; 
&nbsp;
<span style="color: #ff0000;">// save the buffer so I can release it later</span>
<span style="color: #002200;">&#91;</span>bufferStorageArray addObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInteger:bufferID<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;</pre>
<p>OK, lots went on here (well, not really).  made some room for the data, used the AudioFileReadBytes() function from the audio toolkit to read the bytes from the file into the awaiting block of memory.  The next bit is slightly more interesting.  We call alGenBuffers() to make us a valid bufferID, then we call alBufferData() to load the awaiting data blob into the openAL buffer.</p>
<p>Here I have just hardcoded the format and the frequency.  If you use the afconvert command at the top of the post to generate your audio files, then you will know what their format and sample rate are.  However, if you want to be able to do any kind of audio format or frequency, then you will need to build some methods similar to audioFileSize: but using kAudioFilePropertyDataFormat to get the format, then convert it to the proper AL_FORMAT, and something even more byzantine to figure out the frequency.  I am lazy so i just make sure my files are formatted properly.</p>
<p>Next I put the number into a nice NSArray for later reference.  you can do with that ID whatever you want.</p>
<p>OK, now we have a buffer! neato. Time to hook it to the source.</p>
<pre class="objc">&nbsp;
NSUInteger sourceID;
&nbsp;
<span style="color: #ff0000;">// grab a source ID from openAL</span>
alGenSources<span style="color: #002200;">&#40;</span><span style="color: #0000dd;">1</span>, &amp;sourceID<span style="color: #002200;">&#41;</span>; 
&nbsp;
<span style="color: #ff0000;">// attach the buffer to the source</span>
alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFER, bufferID<span style="color: #002200;">&#41;</span>;
<span style="color: #ff0000;">// set some basic source prefs</span>
alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_PITCH, <span style="color: #0000dd;">1</span>.0f<span style="color: #002200;">&#41;</span>;
alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_GAIN, <span style="color: #0000dd;">1</span>.0f<span style="color: #002200;">&#41;</span>;
<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>loops<span style="color: #002200;">&#41;</span> alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_LOOPING, AL_TRUE<span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// store this for future use</span>
<span style="color: #002200;">&#91;</span>soundDictionary setObject:<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> numberWithUnsignedInt:sourceID<span style="color: #002200;">&#93;</span> forKey:@<span style="color: #666666;">&quot;neatoSound&quot;</span><span style="color: #002200;">&#93;</span>;	
&nbsp;
<span style="color: #ff0000;">// clean up the buffer</span>
<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>outData<span style="color: #002200;">&#41;</span>
<span style="color: #002200;">&#123;</span>
	<a href="http://www.opengroup.org/onlinepubs/009695399/functions/free.html"><span style="color: #0000dd;">free</span></a><span style="color: #002200;">&#40;</span>outData<span style="color: #002200;">&#41;</span>;
	outData = <span style="color: #0000ff;">NULL</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>Much like the buffer, we need to get a valid sourceID from openAL.  Once we have that we can connect the source and the buffer.  finally we will throw in a few basic buffer settings just to make sure it is all set up right.  If we want it to loop, then we need to set the AL_LOOPING to true, if not, the default is not to loop, so ignore it.  Then I store the ID into a nice dictionary do I can call it out by name.</p>
<p>lastly, clean up our temporary memory.</p>
<p>So close now! everything is all ready to go, now we just need to play the damn thing:</p>
<pre class="objc">&nbsp;
<span style="color: #ff0000;">// the main method: grab the sound ID from the library</span>
<span style="color: #ff0000;">// and start the source playing</span>
- <span style="color: #002200;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #002200;">&#41;</span>playSound:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>soundKey
<span style="color: #002200;">&#123;</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * numVal = <span style="color: #002200;">&#91;</span>soundDictionary objectForKey:soundKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>numVal == <span style="color: #0000ff;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span>;
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>;
	alSourcePlay<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>that's it.  alSourcePlay().. easy.  If the sound doesnt loop, it will stop of it's own accord when it is all done.  If it is looping, or you want to stop it early:</p>
<pre class="objc">&nbsp;
- <span style="color: #002200;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #002200;">&#41;</span>stopSound:<span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSString.html"><span style="color: #0000ff;">NSString</span></a>*<span style="color: #002200;">&#41;</span>soundKey
<span style="color: #002200;">&#123;</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * numVal = <span style="color: #002200;">&#91;</span>soundDictionary objectForKey:soundKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #0000ff;">if</span> <span style="color: #002200;">&#40;</span>numVal == <span style="color: #0000ff;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #0000ff;">return</span>;
	NSUInteger sourceID = <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>;
	alSourceStop<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>That is basically the quickest and simplest way to get sound out of the iPhone using openAL.  (that I can figure out anyway). </p>
<p>Lastly, when you are done with everything, be nice and clean up:</p>
<pre class="objc">&nbsp;
-<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #002200;">&#41;</span>cleanUpOpenAL:<span style="color: #002200;">&#40;</span><span style="color: #0000ff;">id</span><span style="color: #002200;">&#41;</span>sender
<span style="color: #002200;">&#123;</span>
	<span style="color: #ff0000;">// delete the sources</span>
	<span style="color: #0000ff;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * sourceNumber in <span style="color: #002200;">&#91;</span>soundDictionary allValues<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		NSUInteger sourceID = <span style="color: #002200;">&#91;</span>sourceNumber unsignedIntegerValue<span style="color: #002200;">&#93;</span>;
		alDeleteSources<span style="color: #002200;">&#40;</span><span style="color: #0000dd;">1</span>, &amp;sourceID<span style="color: #002200;">&#41;</span>;
	<span style="color: #002200;">&#125;</span>
	<span style="color: #002200;">&#91;</span>soundDictionary removeAllObjects<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// delete the buffers</span>
	<span style="color: #0000ff;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSNumber.html"><span style="color: #0000ff;">NSNumber</span></a> * bufferNumber in bufferStorageArray<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		NSUInteger bufferID = <span style="color: #002200;">&#91;</span>bufferNumber unsignedIntegerValue<span style="color: #002200;">&#93;</span>;
		alDeleteBuffers<span style="color: #002200;">&#40;</span><span style="color: #0000dd;">1</span>, &amp;bufferID<span style="color: #002200;">&#41;</span>;
	<span style="color: #002200;">&#125;</span>
	<span style="color: #002200;">&#91;</span>bufferStorageArray removeAllObjects<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #ff0000;">// destroy the context</span>
	alcDestroyContext<span style="color: #002200;">&#40;</span>mContext<span style="color: #002200;">&#41;</span>;
	<span style="color: #ff0000;">// close the device</span>
	alcCloseDevice<span style="color: #002200;">&#40;</span>mDevice<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;</pre>
<p>One note: in a real implementation you will probably have more than one source (I have a source for each buffer, but I only have about 8 sounds, so this is not a problem). There is an upper limit on the number of sources you can have.  I dont know the actual number on the iphone, but it is probably something like 16 or 32.  The way to deal with this is to load all your buffers, then dynamically assign those buffers the the next available source that isnt already playing something else. </p>
<p>Groovy, hopefully this will be helpful to someone.  I had a bit of a hard time finding a good basic sample to get myself started so I made this one by going through the <a href="http://connect.creativelabs.com/openal/Documentation/OpenAL_Programmers_Guide.pdf">openAL programmers guide</a> and just doing the very minimum.  </p>
<p>Cheers!<br />
-b</p>
<p>EDIT: clever reader Nathan points out that I forgot to include:<br />
AudioFileClose(fileID);<br />
in my sample code! Whoops! good catch, it is now fixed in the tutorial :-)</p>
<p>EDIT: this page continues to be the most visited page on my site, so: yay!  Unfortunately, if you get here via google, then it can be hard to find other good articles about OpenAL on my site. So, to be servicey, if you read this article, you might also like:</p>
<ul>
<li><a href="http://benbritten.com/2009/01/24/more-openal-tidbits-for-iphone/">More OpenAL tidbits for iPhone</a></li>
<li><a href="http://benbritten.com/2009/02/02/restarting-openal-after-application-interruption-on-the-iphone/">restarting openAL after application interruption on the iPhone</a></li>
<li>
<a href="http://benbritten.com/2009/05/02/lots-and-lots-of-sounds-in-openal/">Lots and Lots of sounds in openAL</a>
</li>
<li><a href="http://benbritten.com/2009/09/20/albufferdatastatic-why-you-should-avoid-it/">alBufferDataStatic: why you should avoid it</a></li>
<li><a href="http://benbritten.com/2010/05/04/streaming-in-openal/">Streaming in OpenAL</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/feed/</wfw:commentRss>
		<slash:comments>51</slash:comments>
		</item>
	</channel>
</rss>

