<?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>iPhoneGeek 爱疯极客 &#187; 音频</title>
	<atom:link href="http://www.iphone-geek.cn/tag/%e9%9f%b3%e9%a2%91/feed" rel="self" type="application/rss+xml" />
	<link>http://www.iphone-geek.cn</link>
	<description>iPhone 新闻，编程，技巧与提示，代码，教程</description>
	<lastBuildDate>Sun, 25 Jul 2010 13:49:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>OpenAL同时处理大量声音</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/openal%e5%90%8c%e6%97%b6%e5%a4%84%e7%90%86%e5%a4%a7%e9%87%8f%e5%a3%b0%e9%9f%b3</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/openal%e5%90%8c%e6%97%b6%e5%a4%84%e7%90%86%e5%a4%a7%e9%87%8f%e5%a3%b0%e9%9f%b3#comments</comments>
		<pubDate>Thu, 27 May 2010 02:10:54 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[音频]]></category>
		<category><![CDATA[OpenAL]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=718</guid>
		<description><![CDATA[（注：这是我在编写MozartBrain时，参考过的一篇文章，虽然年代久远，但对于学习OpenAL编程还是具有指导意义。）

今天要讨论的话题是OpenAL同时处理大量的音效。当你使用OpenAL进行声音播放时，能够同时播放的声音有一个上限（换而言之，最大的source数目）。在iPhone上能够通过下面代码获得的最大source数目大约为32：

1alGenSources&#40;1, &#38;sourceID&#41;;

当你要求超过最大数目的source时，上面的语句将失败，但它并不产生错误。因此，不要要求超过32个source（注：这是iPhone OS 2.2上的数目，其他版本的OS可能会有些差别）

所以，这意味着什么？它意味着任何时候不管什么原因都不要同时播放超过32个音效。这确实是一个问题，如果你的目标是通过分别播放各种乐器来模拟整个交响乐团的演奏，那么你最好不要在iPhone上尝试这样做。
我以前的文章中提到建议为每个音效（音效缓存）分配一个source并在需要播放时都调用此source。这在大部分情形下都可以正常工作。但是，如果在你的应用程序中有超过32个音效时，你应该怎么做？我记得曾经提到过：你应该将未用的source移交给将要被播放的buffer。


这实际上非常简单，我将展示一下怎样实现！

首先，你需要预先创建并加载source。这并不是必须的，但我希望在我想要播放声音时，能够立刻进行，所以我必须预先准备好。

123456789101112131415161718// 注意: MAX_SOURCES 是你需要预先加载的source数目
&#160;// 应该小于32
-&#40;void&#41;preloadSources
&#160;&#123;
&#160; &#160; &#160;// lazy init of my data structure
&#160; &#160; &#160;if &#40;sources == nil&#41; sources = &#91;&#91;NSMutableArray alloc&#93; init&#93;;
&#160; &#160; &#160;// we want to allocate all the sources we will need up front
&#160; &#160; &#160;NSUInteger sourceCount = MAX_SOURCES;
&#160; &#160; &#160;NSInteger sourceIndex;
&#160; &#160; &#160;NSUInteger sourceID;

&#160; &#160; &#160;// build a [...]]]></description>
			<content:encoded><![CDATA[<p>（注：这是我在编写MozartBrain时，参考过的一篇文章，虽然年代久远，但对于学习OpenAL编程还是具有指导意义。）</p>
<p><br class="spacer_" /></p>
<p>今天要讨论的话题是OpenAL同时处理大量的音效。当你使用OpenAL进行声音播放时，能够同时播放的声音有一个上限（换而言之，最大的source数目）。在iPhone上能够通过下面代码获得的最大source数目大约为32：</p>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">alGenSources<span style="color: #002200;">&#40;</span>1, <span style="color: #002200;">&amp;</span>sourceID<span style="color: #002200;">&#41;</span>;</div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>当你要求超过最大数目的source时，上面的语句将失败，但它并不产生错误。因此，不要要求超过32个source（注：这是iPhone OS 2.2上的数目，其他版本的OS可能会有些差别）</p>
<p><br class="spacer_" /></p>
<p>所以，这意味着什么？它意味着任何时候不管什么原因都不要同时播放超过32个音效。这确实是一个问题，如果你的目标是通过分别播放各种乐器来模拟整个交响乐团的演奏，那么你最好不要在iPhone上尝试这样做。</p>
<p>我以前的文章中提到建议为每个音效（音效缓存）分配一个source并在需要播放时都调用此source。这在大部分情形下都可以正常工作。但是，如果在你的应用程序中有超过32个音效时，你应该怎么做？我记得曾经提到过：你应该将未用的source移交给将要被播放的buffer。</p>
<p><br class="spacer_" /></p>
<p><span id="more-718"></span></p>
<p>这实际上非常简单，我将展示一下怎样实现！</p>
<p><br class="spacer_" /></p>
<p>首先，你需要预先创建并加载source。这并不是必须的，但我希望在我想要播放声音时，能够立刻进行，所以我必须预先准备好。</p>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// 注意: MAX_SOURCES 是你需要预先加载的source数目</span><br />
&nbsp;<span style="color: #11740a; font-style: italic;">// 应该小于32</span><br />
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>preloadSources<br />
&nbsp;<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// lazy init of my data structure</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>sources <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> sources <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/"><span style="color: #400080;">NSMutableArray</span></a> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// we want to allocate all the sources we will need up front</span><br />
&nbsp; &nbsp; &nbsp;NSUInteger sourceCount <span style="color: #002200;">=</span> MAX_SOURCES;<br />
&nbsp; &nbsp; &nbsp;NSInteger sourceIndex;<br />
&nbsp; &nbsp; &nbsp;NSUInteger sourceID;<br />
<br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// build a bunch of sources and load them into our array.</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span>sourceIndex <span style="color: #002200;">=</span> <span style="color: #2400d9;">0</span>; sourceIndex &lt; sourceCount; sourceIndex<span style="color: #002200;">++</span><span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alGenSources<span style="color: #002200;">&#40;</span>1, <span style="color: #002200;">&amp;</span>amp;sourceID<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#91;</span>sources addObject<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithUnsignedInt<span style="color: #002200;">:</span>sourceID<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#125;</span><br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>这实际上很简单，只是让openAL创建一系列 source 并保存它们的 ID。 你可以通过向alGenSources传递所需source数目，让 openAL一次创建所有source，然后将它们存储于 C 数组中,但这里我不想调用诸如malloc/free之类的函数，所有使用的是objc-c的方法。</p>
<p><br class="spacer_" /></p>
<p>老的声音播放方法如下：</p>
<p><br class="spacer_" /></p>
<p>// 获取声音ID，然后启动声音播放</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>playSound<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>soundKey<br />
&nbsp;<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp;<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> <span style="color: #002200;">*</span> numVal <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>soundDictionary objectForKey<span style="color: #002200;">:</span>soundKey<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>numVal <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span>;<br />
&nbsp; &nbsp; &nbsp;NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp;alSourcePlay<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;<br />
&nbsp;<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>但是由于以前我们是为每个buffer都分配一个source。现在我们不再会有预先分配好的source，所以必须在声音播放时进行分配。现在的播放方法如下：</p>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>playSound<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>soundKey gain<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>ALfloat<span style="color: #002200;">&#41;</span>gain pitch<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>ALfloat<span style="color: #002200;">&#41;</span>pitch loops<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>loops<br />
&nbsp;<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp;ALenum err <span style="color: #002200;">=</span> alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>; <span style="color: #11740a; font-style: italic;">// clear error code</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// first, find the buffer we want to play</span><br />
&nbsp; &nbsp; &nbsp;<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> <span style="color: #002200;">*</span> numVal <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>soundLibrary objectForKey<span style="color: #002200;">:</span>soundKey<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>numVal <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #2400d9;">0</span>;<br />
&nbsp; &nbsp; &nbsp;NSUInteger bufferID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// now find an available source</span><br />
&nbsp; &nbsp; &nbsp;NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self _nextAvailableSource<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// make sure it is clean by resetting the source buffer to 0</span><br />
&nbsp; &nbsp; &nbsp;alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFER, 0<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// attach the buffer to the source</span><br />
&nbsp; &nbsp; &nbsp;alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFER, bufferID<span style="color: #002200;">&#41;</span>;          <span style="color: #11740a; font-style: italic;">// set the pitch and gain of the source</span><br />
&nbsp; &nbsp; &nbsp;alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_PITCH, pitch<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_GAIN, gain<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// set the looping value</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>loops<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_LOOPING, AL_TRUE<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#125;</span> <span style="color: #a61390;">else</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_LOOPING, AL_FALSE<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// check to see if there are any errors</span><br />
&nbsp; &nbsp; &nbsp;err <span style="color: #002200;">=</span> alGetError<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>err <span style="color: #002200;">!=</span> <span style="color: #2400d9;">0</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#91;</span>self _error<span style="color: #002200;">:</span>err note<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Error Playing Sound!&quot;</span><span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #a61390;">return</span> <span style="color: #2400d9;">0</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// now play!</span><br />
&nbsp; &nbsp; &nbsp;alSourcePlay<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;<span style="color: #a61390;">return</span> sourceID; <span style="color: #11740a; font-style: italic;">// return the sourceID so I can stop loops easily</span><br />
&nbsp;<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>请注意，这个新方法不再直接从soundLibrary中获取sourceID，所以我们必须保存buffer而不是source。等等，下面一行代码在做什么：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// now find an available source</span><br />
NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self _nextAvailableSource<span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>这实际上是调用我自己的方法，查找未被使用的source，然后返回，请看代码：</p>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>_nextAvailableSource <br />
<span style="color: #002200;">&#123;</span><br />
&nbsp;     NSInteger sourceState; <span style="color: #11740a; font-style: italic;">// a holder for the state of the current source</span><br />
&nbsp;     <span style="color: #11740a; font-style: italic;">// first check: find a source that is not being used at the moment.</span><br />
&nbsp;     <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> <span style="color: #002200;">*</span> sourceNumber <span style="color: #a61390;">in</span> sources<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp;         alGetSourcei<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>, AL_SOURCE_STATE, <span style="color: #002200;">&amp;</span>sourceState<span style="color: #002200;">&#41;</span>;<br />
&nbsp;         <span style="color: #11740a; font-style: italic;">// great! we found one! return it and shunt</span><br />
&nbsp;         <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>sourceState <span style="color: #002200;">!=</span> AL_PLAYING<span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>;<br />
&nbsp;     <span style="color: #002200;">&#125;</span><br />
&nbsp;     <span style="color: #11740a; font-style: italic;">// in the case that all our sources are being used, we will find the first non-looping source</span><br />
&nbsp;     <span style="color: #11740a; font-style: italic;">// and return that.</span><br />
&nbsp;     <span style="color: #11740a; font-style: italic;">// first kick out an error</span><br />
      NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;available source overrun, increase MAX_SOURCES&quot;</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp;     NSInteger looping;<br />
&nbsp;     <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> <span style="color: #002200;">*</span> sourceNumber <span style="color: #a61390;">in</span> sources<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp;         alGetSourcei<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>, AL_LOOPING, <span style="color: #002200;">&amp;</span>looping<span style="color: #002200;">&#41;</span>;<br />
&nbsp;         <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>looping<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp;             <span style="color: #11740a; font-style: italic;">// we found one that is not looping, cut it short and return it</span><br />
&nbsp;             NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>sourceNumber unsignedIntValue<span style="color: #002200;">&#93;</span>;<br />
&nbsp;             alSourceStop<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;<br />
&nbsp;             <span style="color: #a61390;">return</span> sourceID;<br />
&nbsp;         <span style="color: #002200;">&#125;</span><br />
&nbsp;     <span style="color: #002200;">&#125;</span><br />
&nbsp;     <span style="color: #11740a; font-style: italic;">// what if they are all loops? arbitrarily grab the first one and cut it short</span><br />
&nbsp;     <span style="color: #11740a; font-style: italic;">// kick out another error</span><br />
      NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;available source overrun, all used sources looping&quot;</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp;     NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>sources objectAtIndex<span style="color: #002200;">:</span>0<span style="color: #002200;">&#93;</span> unsignedIntegerValue<span style="color: #002200;">&#93;</span>;<br />
&nbsp;     alSourceStop<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>;<br />
&nbsp;     <span style="color: #a61390;">return</span> sourceID;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>在 99% 的情况下，它将在第一个循环时找到合适的source并返回。根据我的经验即使在大量使用音效的程序中，你也很少会遇到几个声音同时播放的情形（除非你的音频采样非常长），所以它将很快返回。</p>
<p><br class="spacer_" /></p>
<p>（译者注：实际上，并非完全正确，在我编写的一个未发表的吉他乐器游戏中，我的声音引擎经常遇到大量音效同时播放的情况。之所以会有这种情况发生，是由于你必须在适当的时候<strong>关闭</strong>声音。是的，播放声音非常容易，但要关闭，就有相当的学问。如果你在声音播放的中途直接关闭，那么我可以保证，你将听到爆音。我在App Store下载了许多乐器软件，有几个会产生明显的爆音，就是由于这个原因。要解决这个问题，可能有许多方法。经过我的实验，我的方法是在停止一个声音前，采用定时器逐渐减小音量或将souce移动到很远的地方，确保听不见，但不要停止声音。哪怕声音的音量只有0.00001，如果你关闭它，你仍然会听到爆音。你必须让声音采样自然结束，所以你采用的音效一定不能过长。这就是为什么有许多source会同时存在的原因。为减小source的同时使用的数量，造成source不够用的情况，还必须采用一些其他的技术，比如在将音量减小到接近0（注意不能为0，如果是0，就等同于关闭音量，会产生破音）时，将buffer中的指针指向buffer的结尾处，或采用streaming的方法，另外还可以采用source重用的技术。当然，这些不在本文讨论的范围之内了）</p>
<p><br class="spacer_" /></p>
<p>但是，如果所有source还在播放怎么办？有几个选择：容易的方法：增加max_sources直到问题解决；稍难一点的方法（仍然很容易）：实时生成新的source。</p>
<p><br class="spacer_" /></p>
<p>但是如果你用完了32个source，仍然没有适当的source可用时，最后几行代码将进行处理（译者注，如我上面注释的，这种解决方法并不完美，它很有可能会产生破音。但这只是一个简单的示例，你应根据具体情况进行处理），它假设新声音比旧声音更重要而且循环音比音效更重要：我们采用两个步骤找到需要停止的声音。</p>
<p><br class="spacer_" /></p>
<p>首先我们找到一个非循环音，停止它如何返回其source。第二种情况如果有MAX个循环音在同时播放，那么找到第一个source，停止并返回其source （译者注：其实这也是与你程序的具体情况相关的，你可能会需要采用特殊的算法来决定需要停止的source，比如最远的声音等）。</p>
<p><br class="spacer_" /></p>
<p>（译者注：实际上音效处理的算法是非常复杂，完全看你程序的具体情况。这里的代码只是简单的示例而已。还是那句话：<strong>播放声音很容易，但要正确地关闭声音，一定要仔细考虑</strong>！）</p>
<p><br class="spacer_" /></p>
<h5>原文见：<a href="http://benbritten.com/2009/05/02/lots-and-lots-of-sounds-in-openal/">Lots and Lots of sounds in openAL</a></h5>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/openal%e5%90%8c%e6%97%b6%e5%a4%84%e7%90%86%e5%a4%a7%e9%87%8f%e5%a3%b0%e9%9f%b3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>跨平台代码分享之七 &#8211; 一个简单的音效引擎</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e8%b7%a8%e5%b9%b3%e5%8f%b0%e4%bb%a3%e7%a0%81%e5%88%86%e4%ba%ab%e4%b9%8b%e4%b8%83-%e4%b8%80%e4%b8%aa%e7%ae%80%e5%8d%95%e7%9a%84%e9%9f%b3%e6%95%88%e5%bc%95%e6%93%8e</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e8%b7%a8%e5%b9%b3%e5%8f%b0%e4%bb%a3%e7%a0%81%e5%88%86%e4%ba%ab%e4%b9%8b%e4%b8%83-%e4%b8%80%e4%b8%aa%e7%ae%80%e5%8d%95%e7%9a%84%e9%9f%b3%e6%95%88%e5%bc%95%e6%93%8e#comments</comments>
		<pubDate>Wed, 06 Jan 2010 06:18:19 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[基础]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[音频]]></category>
		<category><![CDATA[跨平台]]></category>
		<category><![CDATA[OpenAL]]></category>
		<category><![CDATA[开源项目]]></category>
		<category><![CDATA[教程]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=727</guid>
		<description><![CDATA[游戏都需要一个声音引擎，一般来说，有三种类型：

播放音效。音效一般是比较简短的声音文件。
播放背景音乐。
乐器，音效模拟。

&#160;
本文介绍一个简单跨平台的音效引擎，主要针对第一种类型。实际上，也可以适用于第二种类型，但由于背景音乐文件较大，占用内存较大，所以本文介绍的方法并不是最为有效率的（特别是对于像iPhone之类内存较为紧张的平台，但仍然可用）。可以在本引擎的基础上加以改进，比如采用“流”（streaming）技术。而第三种类型，可能涉及到DSP（数字处理技术），比较复杂，另外在不同平台有一些不同的技术，如Windows下的VST/VSTi，Mac OSX下的AU等，不在本文的讨论范围。
&#160;
本文介绍的音效引擎是基于OpenAL的，并且是我在许多项目中使用的引擎的简化部分（去除错误处理及乐器模拟部分）。
&#160;
有关OpenAL的使用，网上有许多教程，比如：OpenAL编程教程等。iPhone上的OpenAL使用，本网站也有几篇文章。所以这里不再赘述。
&#160;
本引擎的目的，是简化声音播放接口。最简单的情况下可以仅仅使用两条语句，就播放一段音效。而繁复的OpenAL初始化功能等都由引擎自动完成。下例展示了怎样播放一段音效的最为典型的调用：
&#160;
123audio::CSound sound&#40;&#34;sound.wav&#34;&#41;;

sound.play&#40;&#41;;
&#160;
本引擎由三个类和一个公共函数构成。audio::CEngine是引擎的核心部分，它是一个单例类（Singleton)，负责直接与OpenAL接口，用户无需与其打交道。audio::CBuffer类对应于OpenAL中的缓存，通过audio::openAudioData函数打开音效文件，创建内部缓存，用户也无需直接使用。audio::CSound是用户直接使用的类，它提供了诸如play（），stop（），setVolume（）和setPosition（）几个接口函数。如需扩展功能，添加一些其他功能，可以直接加在此类中，并在audio::CEngine中实现。
&#160;
以上三个类可以直接使用在不同平台中。与平台相关的代码，都在audio::openAudioData()中。它的作用是打开不同的声音文件。对于Windows，我使用了一个开源项目库libsndfile，用来打开诸如wav，caf，aiff，flac，ogg等常用音效文件（注意：mp3并未包括其中。由于使用mp3的软件需要支付一定许可证费用，本人也不喜欢使用）。而对于Mac OSX（iPhone），则使用了core audio。这里大家可能会有一个疑问，既然libsndfile也是跨平台的，为什么在iPhone上不使用它呢？确实，libsndfile支持Windows，Linux，Mac OSX，Sun Solaris等平台，而iPhone并不支持ogg等格式，使用libsndfile不正好填补这个空白？是的，我也是这样想的，但是，有两点原因初始我暂时没有使用它：

没有现成的iPhone库。由于libsndfile需要使用makefile由GCC编译（我曾试过使用Xcode编译，没有成功），我也不是这方面的专家。但是，libsndfile在Mac OSX下编译没有问题，所以只需稍作修改，在为iPhone进行编译也不是没有可能的事情。
由于其许可证的限制。libsndfile是基于LGPL的，它要求使用者采用动态连接库，而众所周知，iPhone（官方）是不支持动态链接的。如果使用静态链接，则需要随软件发布源代码或目标代码。其实，这也不是无法克服的，LGPL只要求发布与libsnd相关的目标代码，所以对你的软件并无影响。对吗？

&#160;
本文给出了Windows下和iPhone下的应用。在Windows下使用需要下载OpenAL SDK和libsndfile。为方便编译好的libsndfile随示例程序给出给出。（你需要修改一下VS 项目文件中的有关OpenAL的头文件和库文件路径，另外，在OpenAL include目录中创建一个OpenAL目录，并将.h复制到其下，这样我就不需要修改#include语句了。）
&#160;
示例程序audiolib下载。（项目在test目录下）
]]></description>
			<content:encoded><![CDATA[<p>游戏都需要一个声音引擎，一般来说，有三种类型：</p>
<ol>
<li>播放音效。音效一般是比较简短的声音文件。</li>
<li>播放背景音乐。</li>
<li>乐器，音效模拟。</li>
</ol>
<p>&nbsp;</p>
<p>本文介绍一个简单跨平台的音效引擎，主要针对第一种类型。实际上，也可以适用于第二种类型，但由于背景音乐文件较大，占用内存较大，所以本文介绍的方法并不是最为有效率的（特别是对于像iPhone之类内存较为紧张的平台，但仍然可用）。可以在本引擎的基础上加以改进，比如采用“流”（streaming）技术。而第三种类型，可能涉及到DSP（数字处理技术），比较复杂，另外在不同平台有一些不同的技术，如Windows下的VST/VSTi，Mac OSX下的AU等，不在本文的讨论范围。</p>
<p>&nbsp;</p>
<p>本文介绍的音效引擎是基于OpenAL的，并且是我在许多项目中使用的引擎的简化部分（去除错误处理及乐器模拟部分）。</p>
<p>&nbsp;</p>
<p>有关OpenAL的使用，网上有许多教程，比如：<a href="http://www.devmaster.net/articles/openal-tutorials/lesson1.php">OpenAL编程教程</a>等。iPhone上的OpenAL使用，本网站也有几篇文章。所以这里不再赘述。</p>
<p>&nbsp;</p>
<p>本引擎的目的，是简化声音播放接口。最简单的情况下可以仅仅使用两条语句，就播放一段音效。而繁复的OpenAL初始化功能等都由引擎自动完成。下例展示了怎样播放一段音效的最为典型的调用：</p>
<p>&nbsp;</p>
<div class="codecolorer-container cpp mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">audio<span style="color: #008080;">::</span><span style="color: #007788;">CSound</span> sound<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;sound.wav&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
sound.<span style="color: #007788;">play</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>本引擎由三个类和一个公共函数构成。audio::CEngine是引擎的核心部分，它是一个单例类（Singleton)，负责直接与OpenAL接口，用户无需与其打交道。audio::CBuffer类对应于OpenAL中的缓存，通过audio::openAudioData函数打开音效文件，创建内部缓存，用户也无需直接使用。audio::CSound是用户直接使用的类，它提供了诸如play（），stop（），setVolume（）和setPosition（）几个接口函数。如需扩展功能，添加一些其他功能，可以直接加在此类中，并在audio::CEngine中实现。</p>
<p>&nbsp;</p>
<p>以上三个类可以直接使用在不同平台中。与平台相关的代码，都在audio::openAudioData()中。它的作用是打开不同的声音文件。对于Windows，我使用了一个开源项目库<a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a>，用来打开诸如wav，caf，aiff，flac，ogg等常用音效文件（<strong>注意：mp3并未包括其中。由于使用mp3的软件需要支付一定许可证费用，本人也不喜欢使用</strong>）。而对于Mac OSX（iPhone），则使用了core audio。这里大家可能会有一个疑问，既然libsndfile也是跨平台的，为什么在iPhone上不使用它呢？确实，libsndfile支持Windows，Linux，Mac OSX，Sun Solaris等平台，而iPhone并不支持ogg等格式，使用libsndfile不正好填补这个空白？是的，我也是这样想的，但是，有两点原因初始我暂时没有使用它：</p>
<ol>
<li>没有现成的iPhone库。由于libsndfile需要使用makefile由GCC编译（我曾试过使用Xcode编译，没有成功），我也不是这方面的专家。但是，libsndfile在Mac OSX下编译没有问题，所以只需稍作修改，在为iPhone进行编译也不是没有可能的事情。</li>
<li>由于其许可证的限制。libsndfile是基于LGPL的，它要求使用者采用动态连接库，而众所周知，iPhone（官方）是不支持动态链接的。<strong>如果使用静态链接，则需要随软件发布源代码或目标代码。</strong>其实，这也不是无法克服的，LGPL只要求发布与libsnd相关的目标代码，所以对你的软件并无影响。对吗？</li>
</ol>
<p>&nbsp;</p>
<p>本文给出了Windows下和iPhone下的应用。在Windows下使用需要下载<a href="http://connect.creativelabs.com/openal/Downloads/oalinst.zip">OpenAL SDK</a>和<a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a>。为方便编译好的libsndfile随示例程序给出给出。（你需要修改一下VS 项目文件中的有关OpenAL的头文件和库文件路径，另外，在OpenAL include目录中创建一个OpenAL目录，并将.h复制到其下，这样我就不需要修改#include语句了。）</p>
<p>&nbsp;</p>
<p>示例程序<a href="../wp-content/uploads/2010/01/audiolib.zip">audiolib</a>下载。（项目在test目录下）<a href="http://www.iphone-geek.cn/wp-content/uploads/2010/01/audiolib.zip"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e8%b7%a8%e5%b9%b3%e5%8f%b0%e4%bb%a3%e7%a0%81%e5%88%86%e4%ba%ab%e4%b9%8b%e4%b8%83-%e4%b8%80%e4%b8%aa%e7%ae%80%e5%8d%95%e7%9a%84%e9%9f%b3%e6%95%88%e5%bc%95%e6%93%8e/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenAL系列之一 &#8211; iPhone上的OpenAL音频</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/openal%e7%b3%bb%e5%88%97%e4%b9%8b%e4%b8%80-iphone%e4%b8%8a%e7%9a%84openal%e9%9f%b3%e9%a2%91</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/openal%e7%b3%bb%e5%88%97%e4%b9%8b%e4%b8%80-iphone%e4%b8%8a%e7%9a%84openal%e9%9f%b3%e9%a2%91#comments</comments>
		<pubDate>Thu, 19 Nov 2009 05:21:58 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[音频]]></category>
		<category><![CDATA[OpenAL]]></category>
		<category><![CDATA[教程]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=259</guid>
		<description><![CDATA[译者注：这是我最喜欢的iPhone OpenAL教程之一，总共有好几篇文章，我会逐步翻译。
&#160;
随着保密协议的解除，我们可以开始公开讨论iPhone的代码了。我觉得讨论一下我&#8220;入侵&#8221;iPhone世界以来遇到的问题以及我是如何修复它们的可能是一个不错的话题。
&#160;
我目前正在编写一个iPhone游戏，它完全是以openGLES为基础并采用OpenAL音频。今天我想谈谈OpenAL
&#160;

今天我只讨论不到30秒的音频以及音效和短循环音。在iPhone上播放的音频需要正确的格式（或者说audio toolbox可以处理的多种音频格式中的一种，但如果你从正确的格式声音开始，iPhone在播放时就不需要进行处理了）。
&#160;
所以，打开你的命令行终端输入：

&#160;  /usr/bin/afconvert -f caff -d LEI16@44100 inputSoundFile.aiff outputSoundFile.caf  &#160;

&#160;
你可能会问这到底是在干什么？这是将文件转换为Little-Endian（低地址低字节） 16位，采样率44，100的格式。通常存储为.caf。
&#160;
好了！我们现在有了正确格式的.caf文件，可以开始做些什么了。
&#160;
有多种方法在iPhone上播放音频，有一种&#8217;简单&#8217;的方式，还有有一些&#8217;难&#8217;的方法&#8230;&#8230;我先快速地讨论一下简单的方式，然后再讨论一下使用OpenAL的&#8217;难的方法&#8217;。
&#160;
让iPhone发声的最快（最容易）的方法是使用音频系统服务：
12345NSString* path = &#91;&#91;NSBundle mainBundle&#93; pathForResource:@&#34;soundEffect1&#34; ofType:@&#34;caf&#34;&#93;; &#160;
NSURL* afUrl = &#91;NSURL fileURLWithPath:path&#93;;
UInt32 soundID; 
AudioServicesCreateSystemSoundID&#40;&#40;CFURLRef&#41;afUrl,&#38;soundID&#41;; &#160;
AudioServicesPlaySystemSound &#40;soundID&#41;;
&#160;
这对于象点击按钮和简单UI互动之类的任务已经足够好用。但是，对于任何更复杂一点的任务（比如：游戏）而言，这简直是毫无用处。它确实会立即开始播放，但若要指定的音效与游戏的特定帧相配合的话，这种方法基本上是没有用处。（我确实曾经使用上述方法实现过我的声音引擎，然而当我将其加载到iPhone播放声音时，要么声音会晚许多帧，要么干脆整个程序会停顿，等待audio toolbox将音频加载到缓存中，实在太糟糕了）。
&#160;
为了更好地控制音频，你需要使用OpenAL，audioUnits或audioQueue。
&#160;
我决定使用OpenAL以便我的代码具有更好的跨平台能力，并且通过学习怎样使用OpenAL，我还可以将这些技术运用在iPhone外的其他平台。（而且象我这样的代码雇佣兵，我觉得具有OpenAL经验比audioQueue经验更有市场）（另外由于我已经熟悉了openGL，openAL十分类似，而audio units和audio queue的代码有那么点丑陋）。
&#160;
所以，这是个超快速的openAL教程，但绝对是实现由openAL产生静态声音的最低要求。
&#160;
OpenAL实在是十分简单，它由3个实体构成：Listener（听者），Source（音源）和Buffer（缓存）。
&#160;
 Listener就是你。任何可以被Listener&#8220;听到&#8221;的声音都是来自扬声器。openAL允许你指定Listener相对于Source的位置，但是本例中我们忽略不计。我们只是针对最基本的静态声音。但是请记住&#8220;Listener&#8221;的概念，在你处理更复杂的情况时，你可以任意移动此对象。本文中就不做过多介绍。
&#160;
Source: 本质上类似与扬声器,它将产生Listener可以&#8220;听&#8221;到的声音。像Listener一样，你可以通过移动Source来获得groovy位置效应。本文的示例也没有涉及此部分。
&#160;
Buffer: 就是我们播放的声音。它保存原始的音频数据。
&#160;
有两个很重要的对象：device（设备）和 context（环境）。Device实际上设播放声音的硬件。而Context是当前所有声音在其中播放的&#8220;会话（session）&#8221;（你可以将其想象成包括所有sources和listener的房间。或者声音通过其播放的空气，或其他&#8230;&#8230;这就是Context。）
&#160;
它们在一起是怎么运作的：（最基本）
1) 获取device
  2) 将context关联到device
  3) 将数据放入buffer
  4) 将buffer链接到一个source
  5) 播放source
&#160;
就这么简单! 假定你的openAL实现对于listener是适当的缺省状态而且你不指定listener和source位置，上述流程工作得很好（在iPhone上就是如此）。
&#160;
好了，我们看看代码:
1234567891011121314151617&#160; &#160; // define these somewhere, [...]]]></description>
			<content:encoded><![CDATA[<p>译者注：这是我最喜欢的iPhone OpenAL教程之一，总共有好几篇文章，我会逐步翻译。</p>
<p>&nbsp;</p>
<p>随着保密协议的解除，我们可以开始公开讨论iPhone的代码了。我觉得讨论一下我&ldquo;入侵&rdquo;iPhone世界以来遇到的问题以及我是如何修复它们的可能是一个不错的话题。</p>
<p>&nbsp;</p>
<p>我目前正在编写一个iPhone游戏，它完全是以openGLES为基础并采用OpenAL音频。今天我想谈谈OpenAL</p>
<p>&nbsp;</p>
<p><span id="more-259"></span></p>
<p>今天我只讨论不到30秒的音频以及音效和短循环音。在iPhone上播放的音频需要正确的格式（或者说audio toolbox可以处理的多种音频格式中的一种，但如果你从正确的格式声音开始，iPhone在播放时就不需要进行处理了）。</p>
<p>&nbsp;</p>
<p>所以，打开你的命令行终端输入：</p>
<blockquote>
<p>&nbsp;  /usr/bin/afconvert -f caff -d LEI16@44100 inputSoundFile.aiff outputSoundFile.caf  &nbsp;</p>
</blockquote>
<p>&nbsp;</p>
<p>你可能会问这到底是在干什么？这是将文件转换为Little-Endian（低地址低字节） 16位，采样率44，100的格式。通常存储为.caf。</p>
<p>&nbsp;</p>
<p>好了！我们现在有了正确格式的.caf文件，可以开始做些什么了。</p>
<p>&nbsp;</p>
<p>有多种方法在iPhone上播放音频，有一种&#8217;简单&#8217;的方式，还有有一些&#8217;难&rsquo;的方法&#8230;&#8230;我先快速地讨论一下简单的方式，然后再讨论一下使用OpenAL的&#8217;难的方法&#8217;。</p>
<p>&nbsp;</p>
<p>让iPhone发声的最快（最容易）的方法是使用音频系统服务：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span> path <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSBundle_Class/"><span style="color: #400080;">NSBundle</span></a> mainBundle<span style="color: #002200;">&#93;</span> pathForResource<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;soundEffect1&quot;</span> ofType<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;caf&quot;</span><span style="color: #002200;">&#93;</span>; &nbsp;<br />
<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a><span style="color: #002200;">*</span> afUrl <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> fileURLWithPath<span style="color: #002200;">:</span>path<span style="color: #002200;">&#93;</span>;<br />
UInt32 soundID; <br />
AudioServicesCreateSystemSoundID<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#40;</span>CFURLRef<span style="color: #002200;">&#41;</span>afUrl,<span style="color: #002200;">&amp;</span>soundID<span style="color: #002200;">&#41;</span>; &nbsp;<br />
AudioServicesPlaySystemSound <span style="color: #002200;">&#40;</span>soundID<span style="color: #002200;">&#41;</span>;</div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>这对于象点击按钮和简单UI互动之类的任务已经足够好用。但是，对于任何更复杂一点的任务（比如：游戏）而言，这简直是毫无用处。它确实会立即开始播放，但若要指定的音效与游戏的特定帧相配合的话，这种方法基本上是没有用处。（我确实曾经使用上述方法实现过我的声音引擎，然而当我将其加载到iPhone播放声音时，要么声音会晚许多帧，要么干脆整个程序会停顿，等待audio toolbox将音频加载到缓存中，实在太糟糕了）。</p>
<p>&nbsp;</p>
<p>为了更好地控制音频，你需要使用OpenAL，audioUnits或audioQueue。</p>
<p>&nbsp;</p>
<p>我决定使用OpenAL以便我的代码具有更好的跨平台能力，并且通过学习怎样使用OpenAL，我还可以将这些技术运用在iPhone外的其他平台。（而且象我这样的代码雇佣兵，我觉得具有OpenAL经验比audioQueue经验更有市场）（另外由于我已经熟悉了openGL，openAL十分类似，而audio units和audio queue的代码有那么点丑陋）。</p>
<p>&nbsp;</p>
<p>所以，这是个超快速的openAL教程，但绝对是实现由openAL产生静态声音的最低要求。</p>
<p>&nbsp;</p>
<p>OpenAL实在是十分简单，它由3个实体构成：Listener（听者），Source（音源）和Buffer（缓存）。</p>
<p>&nbsp;</p>
<p> Listener就是你。任何可以被Listener&ldquo;听到&rdquo;的声音都是来自扬声器。openAL允许你指定Listener相对于Source的位置，但是本例中我们忽略不计。我们只是针对最基本的静态声音。但是请记住&ldquo;Listener&rdquo;的概念，在你处理更复杂的情况时，你可以任意移动此对象。本文中就不做过多介绍。</p>
<p>&nbsp;</p>
<p>Source: 本质上类似与扬声器,它将产生Listener可以&ldquo;听&rdquo;到的声音。像Listener一样，你可以通过移动Source来获得groovy位置效应。本文的示例也没有涉及此部分。</p>
<p>&nbsp;</p>
<p>Buffer: 就是我们播放的声音。它保存原始的音频数据。</p>
<p>&nbsp;</p>
<p>有两个很重要的对象：device（设备）和 context（环境）。Device实际上设播放声音的硬件。而Context是当前所有声音在其中播放的&ldquo;会话（session）&rdquo;（你可以将其想象成包括所有sources和listener的房间。或者声音通过其播放的空气，或其他&#8230;&#8230;这就是Context。）</p>
<p>&nbsp;</p>
<p>它们在一起是怎么运作的：（最基本）</p>
<p>1) 获取device<br />
  2) 将context关联到device<br />
  3) 将数据放入buffer<br />
  4) 将buffer链接到一个source<br />
  5) 播放source</p>
<p>&nbsp;</p>
<p>就这么简单! 假定你的openAL实现对于listener是适当的缺省状态而且你不指定listener和source位置，上述流程工作得很好（在iPhone上就是如此）。</p>
<p>&nbsp;</p>
<p>好了，我们看看代码:</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// define these somewhere, like in your .h file &nbsp;</span><br />
&nbsp; &nbsp; ALCcontext<span style="color: #002200;">*</span> mContext; &nbsp;ALCdevice<span style="color: #002200;">*</span> mDevice; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// start up openAL &nbsp;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>initOpenAL &nbsp;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Initialization &nbsp; </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mDevice <span style="color: #002200;">=</span> alcOpenDevice<span style="color: #002200;">&#40;</span><span style="color: #a61390;">NULL</span><span style="color: #002200;">&#41;</span>; <br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// select the &quot;preferred device&quot; &nbsp;&nbsp; </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>mDevice<span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#123;</span> &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// use the device to make a context &nbsp; &nbsp; &nbsp; &nbsp; </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mContext<span style="color: #002200;">=</span>alcCreateContext<span style="color: #002200;">&#40;</span>mDevice,<span style="color: #a61390;">NULL</span><span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// set my context to the currently active one &nbsp; &nbsp; &nbsp; </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; alcMakeContextCurrent<span style="color: #002200;">&#40;</span>mContext<span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#125;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>很容易理解吧。获得&ldquo;缺省&rdquo;device，然后用它建立一个Context！完成。</p>
<p>&nbsp;</p>
<p>下一步：将数据放入buffer， 这有一点复杂:</p>
<p>&nbsp;</p>
<p>首先：打开音频文件</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #11740a; font-style: italic;">// get the full path of the file &nbsp;</span><br />
&nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span> fileName <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSBundle_Class/"><span style="color: #400080;">NSBundle</span></a> mainBundle<span style="color: #002200;">&#93;</span> pathForResource<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;neatoEffect&quot;</span> ofType<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;caf&quot;</span><span style="color: #002200;">&#93;</span>; &nbsp;<br />
&nbsp; <span style="color: #11740a; font-style: italic;">// first, open the file &nbsp;</span><br />
&nbsp; AudioFileID fileID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self openAudioFile<span style="color: #002200;">:</span>fileName<span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>等一下！什么是openAudioFile: 方法？</p>
<p>&nbsp;</p>
<p>  这里就是:</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// open the audio file &nbsp;</span><br />
<span style="color: #11740a; font-style: italic;">// returns a big audio ID struct &nbsp;</span><br />
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>AudioFileID<span style="color: #002200;">&#41;</span>openAudioFile<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>filePath &nbsp;<br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; AudioFileID outAFID; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// use the NSURl instead of a cfurlref cuz it is easier &nbsp; &nbsp; </span><br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> <span style="color: #002200;">*</span> afUrl <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> fileURLWithPath<span style="color: #002200;">:</span>filePath<span style="color: #002200;">&#93;</span>; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// do some platform specific stuff.. &nbsp;</span><br />
<span style="color: #6e371a;">#if TARGET_OS_IPHONE &nbsp;&nbsp; </span><br />
&nbsp; &nbsp; OSStatus result <span style="color: #002200;">=</span> AudioFileOpenURL<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#40;</span>CFURLRef<span style="color: #002200;">&#41;</span>afUrl, kAudioFileReadPermission, 0, <span style="color: #002200;">&amp;</span>outAFID<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #6e371a;">#else &nbsp; </span><br />
&nbsp; &nbsp; OSStatus result <span style="color: #002200;">=</span> AudioFileOpenURL<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#40;</span>CFURLRef<span style="color: #002200;">&#41;</span>afUrl, fsRdPerm, 0, <span style="color: #002200;">&amp;</span>outAFID<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #6e371a;">#endif &nbsp;&nbsp; &nbsp; </span><br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>result <span style="color: #002200;">!=</span> <span style="color: #2400d9;">0</span><span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;cannot openf file: %@&quot;</span>,filePath<span style="color: #002200;">&#41;</span>; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> outAFID; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>这很简单：我们从主资源包获得文件路径，然后将其传递给本方法，本方法检查运行的平台并使用audio toolkit的方法AudioFileOpenURL()来产生一个AudioFileID。</p>
<p>&nbsp;</p>
<p>下面做什么？对，从文件中获取实际音频数据。我们要先计算出有多少数据在文件中：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// find out how big the actual audio data is &nbsp;</span><br />
&nbsp; &nbsp; UInt32 fileSize <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self audioFileSize<span style="color: #002200;">:</span>fileID<span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div>
<p>我们需要用到的另一个很实用的方法：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// find the audio portion of the file &nbsp;</span><br />
<span style="color: #11740a; font-style: italic;">// return the size in bytes &nbsp;</span><br />
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>UInt32<span style="color: #002200;">&#41;</span>audioFileSize<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>AudioFileID<span style="color: #002200;">&#41;</span>fileDescriptor &nbsp;<br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; UInt64 outDataSize <span style="color: #002200;">=</span> <span style="color: #2400d9;">0</span>; &nbsp; &nbsp; <br />
&nbsp; &nbsp; UInt32 thePropSize <span style="color: #002200;">=</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/sizeof.html"><span style="color: #a61390;">sizeof</span></a><span style="color: #002200;">&#40;</span>UInt64<span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; OSStatus result <span style="color: #002200;">=</span> AudioFileGetProperty<span style="color: #002200;">&#40;</span>fileDescriptor, kAudioFilePropertyAudioDataByteCount, <span style="color: #002200;">&amp;</span>thePropSize, <span style="color: #002200;">&amp;</span>outDataSize<span style="color: #002200;">&#41;</span>; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span>result <span style="color: #002200;">!=</span> <span style="color: #2400d9;">0</span><span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;cannot find file size&quot;</span><span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> <span style="color: #002200;">&#40;</span>UInt32<span style="color: #002200;">&#41;</span>outDataSize; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>它使用了一个神秘的方法AudioFileGetProperty()来计算出文件中有多少数据并将其放入outDataSize变量。太棒了, 下一步！</p>
<p>&nbsp;</p>
<p>现在我们已准备好将数据从文件复制到openAL缓存中：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// this is where the audio data will live for the moment &nbsp;</span><br />
<span style="color: #a61390;">unsigned</span> <span style="color: #a61390;">char</span> <span style="color: #002200;">*</span> outData <span style="color: #002200;">=</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/malloc.html"><span style="color: #a61390;">malloc</span></a><span style="color: #002200;">&#40;</span>fileSize<span style="color: #002200;">&#41;</span>;<br />
<span style="color: #11740a; font-style: italic;">// this where we actually get the bytes from the file and put them &nbsp;</span><br />
<span style="color: #11740a; font-style: italic;">// into the data buffer &nbsp;</span><br />
OSStatus result <span style="color: #002200;">=</span> noErr; &nbsp;<br />
result <span style="color: #002200;">=</span> AudioFileReadBytes<span style="color: #002200;">&#40;</span>fileID, <span style="color: #a61390;">false</span>, 0, <span style="color: #002200;">&amp;</span>fileSize, outData<span style="color: #002200;">&#41;</span>; &nbsp;<br />
AudioFileClose<span style="color: #002200;">&#40;</span>fileID<span style="color: #002200;">&#41;</span>; &nbsp; <span style="color: #11740a; font-style: italic;">//close the file </span><br />
<br />
<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>result <span style="color: #002200;">!=</span> <span style="color: #2400d9;">0</span><span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;cannot load effect: %@&quot;</span>,fileName<span style="color: #002200;">&#41;</span>; &nbsp;<br />
&nbsp; &nbsp; <br />
NSUInteger bufferID; &nbsp;<br />
<span style="color: #11740a; font-style: italic;">// grab a buffer ID from openAL &nbsp;</span><br />
alGenBuffers<span style="color: #002200;">&#40;</span>1, <span style="color: #002200;">&amp;</span>bufferID<span style="color: #002200;">&#41;</span>; &nbsp; <br />
<span style="color: #11740a; font-style: italic;">// jam the audio data into the new buffer &nbsp;</span><br />
alBufferData<span style="color: #002200;">&#40;</span>bufferID,AL_FORMAT_STEREO16,outData,fileSize,44100<span style="color: #002200;">&#41;</span>; &nbsp; &nbsp;<span style="color: #11740a; font-style: italic;">// save the buffer so I can release it later &nbsp;</span><br />
<span style="color: #002200;">&#91;</span>bufferStorageArray addObject<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithUnsignedInteger<span style="color: #002200;">:</span>bufferID<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>好了，上面我们做了很多事情（实际上，并不多）。分配一下空间给数据，使用audio toolkit中的AudioFileReadBytes()函数从文件中读取字节到分配好的内存块中。然后调用alGenBuffers()产生一个有效的bufferID，再调用alBufferData()加载数据块到openAL buffer的缓存中。</p>
<p>&nbsp;</p>
<p>这里我硬编码了格式和频率等数据。如果你是像文章开始介绍的那样使用afconvert命令生成的音频文件，那么你已经知道它们的格式和采样率了。然而，如果你想要支持各种音频格式和频率， 你最好要构建一个类似于audioFileSize:的方法，但使用kAudioFilePropertyDataFormat获取格式然后转换为适当的AL_FORMAT,，而获得频率可能更复杂些（译者注：常用的频率无非就是22050，44100，48000几种了）。我太懒了所以只确定我使用的文件格式正确就可以了。</p>
<p>下面我将此ID放入一个NSArray以备参考，你可以以后随时使用。</p>
<p>&nbsp;</p>
<p>好，我们现在准备好了缓存区。是将它连到source的时候了。</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">NSUInteger sourceID; &nbsp; <br />
<span style="color: #11740a; font-style: italic;">// grab a source ID from openAL &nbsp;</span><br />
alGenSources<span style="color: #002200;">&#40;</span>1, <span style="color: #002200;">&amp;</span>sourceID<span style="color: #002200;">&#41;</span>; &nbsp; <br />
<span style="color: #11740a; font-style: italic;">// attach the buffer to the source &nbsp;</span><br />
alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_BUFFER, bufferID<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #11740a; font-style: italic;">// set some basic source prefs &nbsp;</span><br />
alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_PITCH, 1.0f<span style="color: #002200;">&#41;</span>; &nbsp;<br />
alSourcef<span style="color: #002200;">&#40;</span>sourceID, AL_GAIN, 1.0f<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>loops<span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; alSourcei<span style="color: #002200;">&#40;</span>sourceID, AL_LOOPING, AL_TRUE<span style="color: #002200;">&#41;</span>; &nbsp;<br />
&nbsp;<br />
<span style="color: #11740a; font-style: italic;">// store this for future use &nbsp;</span><br />
<span style="color: #002200;">&#91;</span>soundDictionary setObject<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithUnsignedInt<span style="color: #002200;">:</span>sourceID<span style="color: #002200;">&#93;</span> forKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;neatoSound&quot;</span><span style="color: #002200;">&#93;</span>; &nbsp; <br />
<span style="color: #11740a; font-style: italic;">// clean up the buffer &nbsp;if (outData) &nbsp;</span><br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/free.html"><span style="color: #a61390;">free</span></a><span style="color: #002200;">&#40;</span>outData<span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; outData <span style="color: #002200;">=</span> <span style="color: #a61390;">NULL</span>; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>像缓存一样，我们也需要从openAL获取一个有效的sourceID。一旦我们获得了sourceID我们就可以将source和缓存联系起来了。最后我们还要进行一些缓存基本设定。如果我们想循环播放，还要设定AL_LOOPING为true。 缺省时，播放是不循环的，所以忽略它就好。然后我将此ID存入到字典数据结构中，以便可以根据名称查找ID。</p>
<p>&nbsp;</p>
<p>最后，清除临时内存。</p>
<p>&nbsp;</p>
<p>大功即将告成！现在我们只剩下播放功能了：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// the main method: grab the sound ID from the library &nbsp;</span><br />
<span style="color: #11740a; font-style: italic;">// and start the source playing &nbsp;</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>playSound<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>soundKey &nbsp;<br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a><span style="color: #002200;">*</span> numVal <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>soundDictionary objectForKey<span style="color: #002200;">:</span>soundKey<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>numVal <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">return</span>; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; alSourcePlay<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>就是它了， alSourcePlay()&#8230;&#8230; 很简单吧。如果声音不循环，那么它将会自然停止。如果是循环的，你可能需要停止它：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>stopSound<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>soundKey &nbsp;<br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a><span style="color: #002200;">*</span> numVal <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>soundDictionary objectForKey<span style="color: #002200;">:</span>soundKey<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>numVal <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">return</span>; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>numVal unsignedIntValue<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; alSourceStop<span style="color: #002200;">&#40;</span>sourceID<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>以上基本上就是使用openAL在iPhone播放声音的最快速和简单的方法（至少我是这样认为的）。</p>
<p>&nbsp;</p>
<p>最后，我们要做些清理工作：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>cleanUpOpenAL<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender &nbsp;<br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// delete the sources &nbsp; </span><br />
&nbsp; &nbsp; <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a><span style="color: #002200;">*</span> sourceNumber <span style="color: #a61390;">in</span> <span style="color: #002200;">&#91;</span>soundDictionary allValues<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span> &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; NSUInteger sourceID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>sourceNumber unsignedIntegerValue<span style="color: #002200;">&#93;</span>; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; alDeleteSources<span style="color: #002200;">&#40;</span>1, <span style="color: #002200;">&amp;</span>sourceID<span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span> &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>soundDictionary removeAllObjects<span style="color: #002200;">&#93;</span>; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// delete the buffers &nbsp; </span><br />
&nbsp; &nbsp; <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a><span style="color: #002200;">*</span> bufferNumber <span style="color: #a61390;">in</span> bufferStorageArray<span style="color: #002200;">&#41;</span> <br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span> &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; NSUInteger bufferID <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>bufferNumber unsignedIntegerValue<span style="color: #002200;">&#93;</span>; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; alDeleteBuffers<span style="color: #002200;">&#40;</span>1, <span style="color: #002200;">&amp;</span>bufferID<span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span> &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>bufferStorageArray removeAllObjects<span style="color: #002200;">&#93;</span>; &nbsp;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// destroy the context &nbsp;&nbsp; &nbsp; </span><br />
&nbsp; &nbsp; alcDestroyContext<span style="color: #002200;">&#40;</span>mContext<span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// close the device &nbsp; &nbsp; </span><br />
&nbsp; &nbsp; alcCloseDevice<span style="color: #002200;">&#40;</span>mDevice<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>注意：在实际应用中你可能有不只一个source（我的每个buffer都有一个source，但我只有8组声音所以不会有什么问题）。而可以使用的source数目是有上限的。我不知道iPhone上的实际数字，但可能是16或32之类。（译者注：我有一个应用程序使用了30个source，没有什么问题）。处理此类问题的方法是加载你的缓存，然后动态分配给下一个可用的source（即没有正在进行播放的source）。</p>
<p>&nbsp;</p>
<p>参考资料： <a href="http://connect.creativelabs.com/openal/Documentation/OpenAL_Programmers_Guide.pdf" onclick="javascript:pageTracker._trackPageview('/outbound/article/http://connect.creativelabs.com/openal/Documentation/OpenAL_Programmers_Guide.pdf');">openAL programmers guide</a>。</p>
<p>&nbsp;</p>
<h5>原文见：<a title="Permanent Link to openAL sound on the iPhone" href="http://benbritten.com/2008/11/06/openal-sound-on-the-iphone/" rel="bookmark">openAL sound on the iPhone</a> 作者：Ben Britten Smith</h5>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/openal%e7%b3%bb%e5%88%97%e4%b9%8b%e4%b8%80-iphone%e4%b8%8a%e7%9a%84openal%e9%9f%b3%e9%a2%91/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>检测用户向麦克吹气</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e6%a3%80%e6%b5%8b%e7%94%a8%e6%88%b7%e5%90%91%e9%ba%a6%e5%85%8b%e5%90%b9%e6%b0%94</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e6%a3%80%e6%b5%8b%e7%94%a8%e6%88%b7%e5%90%91%e9%ba%a6%e5%85%8b%e5%90%b9%e6%b0%94#comments</comments>
		<pubDate>Mon, 16 Nov 2009 07:04:41 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[音频]]></category>
		<category><![CDATA[教程]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=246</guid>
		<description><![CDATA[
&#160;
如果几年前你告诉我人们可以通过晃动手机或向麦克吹气使手机有所动作，我一定会大笑不止。但现在这已经是事实了。
&#160;
检查晃动动作是很直接的，所有这些在3.0“motion event”（动作事件)中都有介绍。
&#160;
检测向麦克吹气困难一点。本教程将建立一个简单的单视图程序，它将在用户向麦克吹气时向控制台写入记录信息。
&#160;

源代码/Github
&#160;
教程源代码可从GitHub获得。 你可以克隆软件仓库或直接下载zip文件。
&#160;
概述
&#160;
检测向麦克吹气的工作可分为两部分：(1) 获取麦克输入 (2) “听”吹气的声音。 
&#160;
我们将使用3.0中新的AVAudioRecorder类来捕获麦克输入。使用AVAudioRecorder可以让我们使用Objective-C，而不需像其他方法一样使用C。
&#160;
向麦克吹气的噪声/声音是由低频声音组成的。我们将使用low pass filter（低频滤波） 来降低来自麦克的高频声音；当滤波信号的电平等级突然增大时，我们就知道有人向麦克吹气了。
&#160;
创建项目
&#160;
启动Xcode创建一个View-Based iPhone程序，叫MicBlow：


使用Xcode菜单File &#62; New Project&#8230; 创建一个新项目
从 iPhone OS &#62; Application 选择View-based Applications然后按Choose&#8230;
将项目命名为MicBlow，按Save


&#160;
添加AVFoundation Framework
&#160;
为使用AVAudioRecorder类，我们需要向项目添加AVFoundation framework：


在项目Groups &#38; Files面板上展开Targets
按Control-点击或右击MicBlow
选择Add &#62; Existing Frameworks&#8230;
按下Linked Libraries左下角的+按钮
选择AVFoundation.framework并按下Add
AVFoundation.framework出现在Linked Libraries下。关闭窗口


&#160;
然后，我们在view controller接口中引入AVFoundation头文件并设置AVAudioRecorder实例变量：


展开项目Groups &#38; Files面板下的MicBlow
展开Classes文件夹
选择MicBlowViewController.h进行编辑
更新文件。修改见如下2，3，7行：


123456789#import &#60;UIKit/UIKit.h&#62; &#160;
#import &#60;AVFoundation/AVFoundation.h&#62; &#160;
#import &#60;CoreAudio/CoreAudioTypes.h&#62;

@interface MicBlowViewController : UIViewController 
&#123; &#160; 
&#160; &#160; AVAudioRecorder *recorder; &#160;
&#125; &#160; &#160;
@end
&#160;
引入CoreAudioTypes头文件实际上是下一步需要的工作。我们还需要在设置AVAudioRecorder定义更多的常量。
&#160;
获取麦克输入
&#160;
我们在ViewDidLoad进行设置并开始“听“取麦克：


解除样本ViewDidLoad方法注释
更新如下。见4-18行:


12345678910111213141516171819- &#40;void&#41;viewDidLoad 
&#123; &#160; 
&#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.mobileorchard.com/wp-content/uploads/2009/08/blow1.jpg" alt="" width="110"></p>
<p>&nbsp;</p>
<p>如果几年前你告诉我人们可以通过晃动手机或向麦克吹气使手机有所动作，我一定会大笑不止。但现在这已经是事实了。</p>
<p>&nbsp;</p>
<p>检查晃动动作是很直接的，所有这些在3.0“motion event”（动作事件)中都有介绍。</p>
<p>&nbsp;</p>
<p>检测向麦克吹气困难一点。本教程将建立一个简单的单视图程序，它将在用户向麦克吹气时向控制台写入记录信息。</p>
<p>&nbsp;</p>
<p><span id="more-246"></span></p>
<h2>源代码/Github</h2>
<p>&nbsp;</p>
<p><a href="http://github.com/dcgrigsby/MicBlow">教程源代码</a>可从GitHub获得。 你可以克隆软件仓库或直接下载<a href="http://github.com/dcgrigsby/MicBlow/zipball/master">zip文件</a>。</p>
<p>&nbsp;</p>
<h2>概述</h2>
<p>&nbsp;</p>
<p>检测向麦克吹气的工作可分为两部分：(1) 获取麦克输入 (2) “听”吹气的声音。 </p>
<p>&nbsp;</p>
<p>我们将使用3.0中新的AVAudioRecorder类来捕获麦克输入。使用AVAudioRecorder可以让我们使用Objective-C，而不需像其他方法一样使用C。</p>
<p>&nbsp;</p>
<p>向麦克吹气的噪声/声音是由低频声音组成的。我们将使用<a href="http://en.wikipedia.org/wiki/Low-pass_filter">low pass filter（低频滤波）</a> 来降低来自麦克的高频声音；当滤波信号的电平等级突然增大时，我们就知道有人向麦克吹气了。</p>
<p>&nbsp;</p>
<h2>创建项目</h2>
<p>&nbsp;</p>
<p>启动Xcode创建一个View-Based iPhone程序，叫MicBlow：</p>
<blockquote>
<ol>
<li>使用Xcode菜单<em>File &gt; New Project&hellip;</em> 创建一个新项目</li>
<li>从 <em>iPhone OS &gt; Application</em> 选择<em>View-based Application</em>s然后按<em>Choose&hellip;</em></li>
<li>将项目命名为<em>MicBlow，</em>按<em>Save</em></li>
</ol>
</blockquote>
<p>&nbsp;</p>
<h2>添加AVFoundation Framework</h2>
<p>&nbsp;</p>
<p>为使用AVAudioRecorder类，我们需要向项目添加AVFoundation framework：</p>
<blockquote>
<ol>
<li>在项目<em>Groups &amp; Files</em>面板上展开<em>Targets</em></li>
<li>按Control-点击或右击<em>MicBlow</em></li>
<li>选择<em>Add &gt; Existing Frameworks&hellip;</em></li>
<li>按下<em>Linked Libraries</em>左下角的<em>+</em>按钮</li>
<li>选择<em>AVFoundation.framework</em>并按下<em>Add</em></li>
<li><em>AVFoundation.framework</em>出现在<em>Linked Libraries</em>下。关闭窗口</li>
</ol>
</blockquote>
<p>&nbsp;</p>
<p>然后，我们在view controller接口中引入AVFoundation头文件并设置AVAudioRecorder实例变量：</p>
<blockquote>
<ol>
<li>展开项目<em>Groups &amp; Files</em>面板下的<em>MicBlow</em></li>
<li>展开<em>Classes</em>文件夹</li>
<li>选择<em>MicBlowViewController.h</em>进行编辑</li>
<li>更新文件。修改见如下2，3，7行：</li>
</ol>
</blockquote>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #6e371a;">#import &lt;UIKit/UIKit.h&gt; &nbsp;</span><br />
<span style="color: #6e371a;">#import &lt;AVFoundation/AVFoundation.h&gt; &nbsp;</span><br />
<span style="color: #6e371a;">#import &lt;CoreAudio/CoreAudioTypes.h&gt;</span><br />
<br />
<span style="color: #a61390;">@interface</span> MicBlowViewController <span style="color: #002200;">:</span> UIViewController <br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; AVAudioRecorder <span style="color: #002200;">*</span>recorder; &nbsp;<br />
<span style="color: #002200;">&#125;</span> &nbsp; &nbsp;<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>引入CoreAudioTypes头文件实际上是下一步需要的工作。我们还需要在设置AVAudioRecorder定义更多的常量。</p>
<p>&nbsp;</p>
<h2>获取麦克输入</h2>
<p>&nbsp;</p>
<p>我们在ViewDidLoad进行设置并开始“听“取麦克：</p>
<blockquote>
<ol>
<li>解除样本<em>ViewDidLoad</em>方法注释</li>
<li>更新如下。见4-18行:</li>
</ol>
</blockquote>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>viewDidLoad <br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>super viewDidLoad<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> <span style="color: #002200;">*</span>url <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> fileURLWithPath<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;/dev/null&quot;</span><span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span style="color: #400080;">NSDictionary</span></a> <span style="color: #002200;">*</span>settings <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span style="color: #400080;">NSDictionary</span></a> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithFloat<span style="color: #002200;">:</span> 44100.0<span style="color: #002200;">&#93;</span>, AVSampleRateKey,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithInt<span style="color: #002200;">:</span> kAudioFormatAppleLossless<span style="color: #002200;">&#93;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; AVFormatIDKey, <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithInt<span style="color: #002200;">:</span> 1<span style="color: #002200;">&#93;</span>, AVNumberOfChannelsKey,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithInt<span style="color: #002200;">:</span> AVAudioQualityMax<span style="color: #002200;">&#93;</span>, AVEncoderAudioQualityKey, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span style="color: #400080;">NSError</span></a> <span style="color: #002200;">*</span>error; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; recorder <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>AVAudioRecorder alloc<span style="color: #002200;">&#93;</span> initWithURL<span style="color: #002200;">:</span>url settings<span style="color: #002200;">:</span>settings error<span style="color: #002200;">:&amp;</span>amp;error<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>recorder<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder prepareToRecord<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; recorder.meteringEnabled <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder record<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span> <span style="color: #a61390;">else</span> &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>error description<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>; &nbsp; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>AVAudioRecorder的主要功能就像前名字暗示的那样进行音频录制。其第二个功能是提供音频电平等级信息。所以，这里我们只是将音频输入指向<em>/dev/null</em>位 &#8211; 我没有找到任何文档支持我的观点，但一致意见是就像在任何Unix下一样，/dev/null将打开音频计量表。</p>
<p>&nbsp;</p>
<p>注意: 如果你准备采用上述代码，记住在设置meteringEnabled属性或音频计量开始工作前，要调用prepareToRecord (或者record)。</p>
<p>&nbsp;</p>
<p>记住在dealloc中释放recorder。 见第三行：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc <br />
&nbsp; <span style="color: #002200;">&#123;</span> &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder release<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>; &nbsp;<br />
&nbsp; <span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<h2>音频采样</h2>
<p>&nbsp;</p>
<p>我们将使用定时器每秒30次检查一次音频电平等级。NSTimer实例变量以及其回调函数在MicBlowViewController.h中定义。修改见7，10行：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #6e371a;">#import &lt;UIKit/UIKit.h&gt; &nbsp;</span><br />
<span style="color: #6e371a;">#import &lt;AVFoundation/AVFoundation.h&gt; &nbsp;</span><br />
<span style="color: #6e371a;">#import &lt;CoreAudio/CoreAudioTypes.h&gt; &nbsp; &nbsp;</span><br />
<br />
<span style="color: #a61390;">@interface</span> MicBlowViewController <span style="color: #002200;">:</span> UIViewController <span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; AVAudioRecorder <span style="color: #002200;">*</span>recorder; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/"><span style="color: #400080;">NSTimer</span></a> <span style="color: #002200;">*</span>levelTimer; &nbsp;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>levelTimerCallback<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/"><span style="color: #400080;">NSTimer</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>timer;<br />
<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>更新.m文件中ViewDidLoad启用定时器。修改见16，17行：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>viewDidLoad <span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>super viewDidLoad<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> <span style="color: #002200;">*</span>url <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> fileURLWithPath<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;/dev/null&quot;</span><span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span style="color: #400080;">NSDictionary</span></a> <span style="color: #002200;">*</span>settings <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span style="color: #400080;">NSDictionary</span></a> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span> &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithFloat<span style="color: #002200;">:</span> 44100.0<span style="color: #002200;">&#93;</span>,AVSampleRateKey,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithInt<span style="color: #002200;">:</span> kAudioFormatAppleLossless<span style="color: #002200;">&#93;</span>, AVFormatIDKey,<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithInt<span style="color: #002200;">:</span> 1<span style="color: #002200;">&#93;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; AVNumberOfChannelsKey,<span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithInt<span style="color: #002200;">:</span> AVAudioQualityMax<span style="color: #002200;">&#93;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; AVEncoderAudioQualityKey, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span style="color: #400080;">NSError</span></a> <span style="color: #002200;">*</span>error; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; recorder <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>AVAudioRecorder alloc<span style="color: #002200;">&#93;</span> initWithURL<span style="color: #002200;">:</span>url settings<span style="color: #002200;">:</span>settings error<span style="color: #002200;">:&amp;</span>amp;error<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>recorder<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder prepareToRecord<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; recorder.meteringEnabled <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder record<span style="color: #002200;">&#93;</span>; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; levelTimer <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/"><span style="color: #400080;">NSTimer</span></a> scheduledTimerWithTimeInterval<span style="color: #002200;">:</span> 0.03 target<span style="color: #002200;">:</span> self <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selector<span style="color: #002200;">:</span> <span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>levelTimerCallback<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span> userInfo<span style="color: #002200;">:</span> <span style="color: #a61390;">nil</span> repeats<span style="color: #002200;">:</span> <span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span> <span style="color: #a61390;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>error description<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>; &nbsp; &nbsp;<br />
&nbsp;<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>现在，我们只是直接进行音频采样而未使用滤波。在.m文件中添加levelTimerCallback：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>levelTimerCallback<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/"><span style="color: #400080;">NSTimer</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>timer <span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder updateMeters<span style="color: #002200;">&#93;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Average input: %f Peak input: %f&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder averagePowerForChannel<span style="color: #002200;">:</span>0<span style="color: #002200;">&#93;</span>, <span style="color: #002200;">&#91;</span>recorder peakPowerForChannel<span style="color: #002200;">:</span>0<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>发送updateMeters消息来刷新平均和峰值功率。此计数是以对数刻度计量的，-160表示完全安静，0表示最大输入值。</p>
<p>&nbsp;</p>
<p>不要忘记在dealloc中释放定时器。修改见第三行：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc <br />
<span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; &lt;strong&gt;<span style="color: #002200;">&#91;</span>levelTimer release<span style="color: #002200;">&#93;</span>;&lt;<span style="color: #002200;">/</span>strong&gt;<br />
&nbsp; &nbsp;<span style="color: #002200;">&#91;</span>recorder release<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp;<span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<h2>”聆听“吹气声</h2>
<p>&nbsp;</p>
<p>正如概述中提到的那样，我们要使用低通滤波来消除高频声音对电平带来的影响。该算法建立了一系列将过去的每个采样输入合成而得到的结果。我们需要一个实例变量来保存此结果。更新.h文件。修改见第八行： </p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #6e371a;">#import &lt;UIKit/UIKit.h&gt; &nbsp;</span><br />
<span style="color: #6e371a;">#import &lt;AVFoundation/AVFoundation.h&gt; &nbsp;</span><br />
<span style="color: #6e371a;">#import &lt;CoreAudio/CoreAudioTypes.h&gt; &nbsp; &nbsp;</span><br />
<br />
<span style="color: #a61390;">@interface</span> MicBlowViewController <span style="color: #002200;">:</span> UIViewController <span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; AVAudioRecorder <span style="color: #002200;">*</span>recorder; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/"><span style="color: #400080;">NSTimer</span></a> <span style="color: #002200;">*</span>levelTimer; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">double</span> lowPassResults; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>替换levelTimerCallback:方法来实现此算法：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>levelTimerCallback<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/"><span style="color: #400080;">NSTimer</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>timer <span style="color: #002200;">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder updateMeters<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">const</span> <span style="color: #a61390;">double</span> ALPHA <span style="color: #002200;">=</span> <span style="color: #2400d9;">0.05</span>; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">double</span> peakPowerForChannel <span style="color: #002200;">=</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/pow.html"><span style="color: #a61390;">pow</span></a><span style="color: #002200;">&#40;</span>10, <span style="color: #002200;">&#40;</span>0.05 <span style="color: #002200;">*</span> <span style="color: #002200;">&#91;</span>recorder peakPowerForChannel<span style="color: #002200;">:</span>0<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; lowPassResults <span style="color: #002200;">=</span> ALPHA <span style="color: #002200;">*</span> peakPowerForChannel <span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span>1.0 <span style="color: #002200;">-</span> ALPHA<span style="color: #002200;">&#41;</span> <span style="color: #002200;">*</span> lowPassResults;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Average input: %f Peak input: %f Low pass results: %f&quot;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder averagePowerForChannel<span style="color: #002200;">:</span>0<span style="color: #002200;">&#93;</span>, <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder peakPowerForChannel<span style="color: #002200;">:</span>0<span style="color: #002200;">&#93;</span>, lowPassResults<span style="color: #002200;">&#41;</span>; &nbsp;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>我们在每次定时器回调时重新计算一次lowPassResults变量。为方便，我们将其转换为0-1，0代表完全安静，1代表最大音量。</p>
<p>&nbsp;</p>
<p>但低通滤波值超过一定门槛范围时，我们就可以判断有人向麦克吹了气。门槛范围值的设定是一种技巧。它设定太小，则太容易被触发，如果设定太高，则必须长时间用尽力气吹气才会有效果。在我们的程序中，我将其设为0.95。我们要改变一下log的条件，见第6，7行：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>listenForBlow<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/"><span style="color: #400080;">NSTimer</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>timer <span style="color: #002200;">&#123;</span> &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>recorder updateMeters<span style="color: #002200;">&#93;</span>; &nbsp; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">const</span> <span style="color: #a61390;">double</span> ALPHA <span style="color: #002200;">=</span> <span style="color: #2400d9;">0.05</span>; &nbsp;&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">double</span> peakPowerForChannel <span style="color: #002200;">=</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/pow.html"><span style="color: #a61390;">pow</span></a><span style="color: #002200;">&#40;</span>10, <span style="color: #002200;">&#40;</span>0.05 <span style="color: #002200;">*</span> <span style="color: #002200;">&#91;</span>recorder peakPowerForChannel<span style="color: #002200;">:</span>0<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>; &nbsp;&nbsp; <br />
&nbsp; &nbsp; lowPassResults <span style="color: #002200;">=</span> ALPHA <span style="color: #002200;">*</span> peakPowerForChannel <span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span>1.0 <span style="color: #002200;">-</span> ALPHA<span style="color: #002200;">&#41;</span> <span style="color: #002200;">*</span> lowPassResults; &nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>lowPassResults &gt; <span style="color: #2400d9;">0.95</span><span style="color: #002200;">&#41;</span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Mic blow detected&quot;</span><span style="color: #002200;">&#41;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>好了！你可以检测是否有人吹了麦克了。</p>
<p>&nbsp;</p>
<h2>鸣谢及说明</h2>
<p>&nbsp;</p>
<p>此方法在大部分情况下工作良好，但并非任何情况都正确。我是在飞行中写的这篇文章，飞机的引擎声经常触发我的算法。类似地，在一个噪声很大的房间内足够多的低频声也会触发我的算法。</p>
<p>&nbsp;</p>
<p>算法节选自<a href="http://stackoverflow.com/questions/795968/detecting-blowing-on-the-iphone-microphone">this Stack Overflow post</a>。上面帖子使用的是<a href="http://github.com/stephencelis/sc_listener">SCListener</a>库来进行音频电平检测。SCListener比AVAudioRecorder更早出现；它是用来隐藏C语言细节的获取音频电平代码。而无疑AVAudioRecorder更容易使用。</p>
<p>&nbsp;</p>
<p>最后，此方法确实可以在模拟器中正常工作。但你要找到Mac上的麦克。出乎我的意料，第一代Macbook上的麦克处于摄像头左方的小孔中。</p>
<p>&nbsp;</p>
<h5>原文见：<a href="http://www.mobileorchard.com/tutorial-detecting-when-a-user-blows-into-the-mic">Tutorial: Detecting When A User </p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e6%a3%80%e6%b5%8b%e7%94%a8%e6%88%b7%e5%90%91%e9%ba%a6%e5%85%8b%e5%90%b9%e6%b0%94/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>iPhone游戏编程教程之四-游戏简单音频</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iphone%e6%b8%b8%e6%88%8f%e7%bc%96%e7%a8%8b%e6%95%99%e7%a8%8b%e4%b9%8b%e5%9b%9b-%e6%b8%b8%e6%88%8f%e7%ae%80%e5%8d%95%e9%9f%b3%e9%a2%91</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iphone%e6%b8%b8%e6%88%8f%e7%bc%96%e7%a8%8b%e6%95%99%e7%a8%8b%e4%b9%8b%e5%9b%9b-%e6%b8%b8%e6%88%8f%e7%ae%80%e5%8d%95%e9%9f%b3%e9%a2%91#comments</comments>
		<pubDate>Fri, 13 Nov 2009 10:42:33 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[音频]]></category>
		<category><![CDATA[教程]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=235</guid>
		<description><![CDATA[本教程系列的最后一讲将介绍怎样为你的游戏加上声音。由于这是针对初学者的教程，所以我不会讨论复杂的音频技术，如OpenGL和Audio Queue。今天的主题是播放一段短的声音（少于30秒）。如果你不要求任何背景音乐，这将是最容易的播放音频的方式了。这种方式的缺点是一次只能播放一个音频文件。好，我们开始吧&#8230;&#8230;先从上次教程的代码开始。我们今天将使用两种声音，一个是击打球的声音，另一个是得分的声音。

&#160;

下面是你需要下载的音频文件：

clapping-crowd-studio-01
tennis-volley-01

&#160;
注意文件的格式是.caf。你所有音频文件格式必须符合在iPhone上播放的要求。Apple提供了一个工具将音频转换成这种格式。这里是参考。很简单，打开终端输入：
&#160;
/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}
&#160;
 {INPUT}是输入音频文件路径，{OUTPUT} 是你想要存放的.caf文件路径。
&#160;
将音频文件添加到项目中
&#160;
将下载好的音频文件拖放到项目下的Resources文件夹。如果你还希望 安排得更为有序些的话，你还可以建立一个Audio子文件夹。请确定在“copy the  files into your project’s directory”检查框上打勾。

&#160;
添加AudioToolbox.framework到项目
&#160;
由于我们要用到此框架的一些函数，所以我们必须将此框架加入项目中。右击项目中的Frameworks文件夹选择Add -&#62; Existing Frameworks。在搜索框内输入AudioToolbox.framework 然后选择搜索结果中的框架。（请确定点取了Computer 以搜索整个电脑）。

&#160;
找到所需框架后，按Add。现在我们已经准备好写代码了&#8230;&#8230;
&#160;
头文件声明
&#160;
打开 iTennisViewController.h 加入下列代码：

&#160;
首先我们看到代码引入AudioServices.h，我们需要使用其中一些函数来播放音频。接下来定义了两个SystemSoundID。它们都是Integers（整数型，也可以使用int，但会引起许多警告信息）。然后打开iTennishViewController.m加入下面代码：

&#160;
现在我们来初始化声音对象。找到viewDidLoad方法加入下列代码：

&#160;
很简单吧。第一行是获取音频文件路径。下一行是将路径转换为CFURLRef。最后，加载音频文件并与指定soundID联系起来。注意我们传递的&#38;clappingFileID参数，  这是通过参考地址传递的，因此它允许AudioServicesCreateSystemSoundID方法对其进行修改。我们用同样方法处理击球声。下面，我们可以开始播放了。
&#160;
声音播放
&#160;
播放加载好的声音实际上很简单。只需将需要播放文件的soundID传递给AudioServicesPlaySystemSound方法即可。所以播放得分时的鼓掌声只需在reset方法中加入下列代码：

&#160;
请注意，我们传递的clappingFileID说明我们是要播放鼓掌声。加在gameLoop中加入下列代码将播放球拍击球的声音：

&#160;
很容易吧？按“Build and Go”试玩我们的游戏吧。源代码下载 。
&#160;
原文见：iPhone Game Programming Tutorial Part 4 – Basic Game Audio  
]]></description>
			<content:encoded><![CDATA[<p>本教程系列的最后一讲将介绍怎样为你的游戏加上声音。由于这是针对初学者的教程，所以我不会讨论复杂的音频技术，如OpenGL和Audio Queue。今天的主题是播放一段短的声音（少于30秒）。如果你不要求任何背景音乐，这将是最容易的播放音频的方式了。这种方式的缺点是一次只能播放一个音频文件。好，我们开始吧&#8230;&#8230;先从上次教程的代码开始。我们今天将使用两种声音，一个是击打球的声音，另一个是得分的声音。
</p>
<p>&nbsp;</p>
<p><span id="more-235"></span></p>
<p>下面是你需要下载的音频文件：</p>
<ul>
<li><a href="http://icodeblog.com/wp-content/uploads/2009/05/clapping-crowd-studio-01.caf">clapping-crowd-studio-01</a></li>
<li><a href="http://icodeblog.com/wp-content/uploads/2009/05/tennis-volley-01.caf">tennis-volley-01</a></li>
</ul>
<p>&nbsp;</p>
<p>注意文件的格式是.caf。你所有音频文件格式必须符合在iPhone上播放的要求。Apple提供了一个工具将音频转换成这种格式。这里是<a href="CONVERT_AN_AUDIO_FILE_TO_THE_PREFERRED_FORMAT_FOR_IPHONE_OS">参考</a>。很简单，打开终端输入：</p>
<p>&nbsp;</p>
<p><strong>/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}</strong></p>
<p>&nbsp;</p>
<p> {INPUT}是输入音频文件路径，{OUTPUT} 是你想要存放的.caf文件路径。</p>
<p>&nbsp;</p>
<h2>将音频文件添加到项目中</h2>
<p>&nbsp;</p>
<p>将下载好的音频文件拖放到项目下的Resources文件夹。如果你还希望 安排得更为有序些的话，你还可以建立一个Audio子文件夹。请确定在“copy the  files into your project’s directory”检查框上打勾。</p>
<p><a href="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_01.png"><img title="screenshot_01" src="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_01.png" alt="screenshot_01" width="232" height="240"></a></p>
<p>&nbsp;</p>
<h2>添加AudioToolbox.framework到项目</h2>
<p>&nbsp;</p>
<p>由于我们要用到此框架的一些函数，所以我们必须将此框架加入项目中。右击项目中的<strong>Frameworks</strong>文件夹选择<strong>Add -&gt; Existing Frameworks</strong>。在搜索框内输入<strong>AudioToolbox.framework </strong>然后选择搜索结果中的框架。（请确定点取了<strong>Computer</strong> 以搜索整个电脑）。</p>
<p><a href="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_02.png"><img title="screenshot_02" src="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_02.png" alt="screenshot_02" width="532" height="427"></a></p>
<p>&nbsp;</p>
<p>找到所需框架后，按<strong>Add</strong>。现在我们已经准备好写代码了&#8230;&#8230;</p>
<p>&nbsp;</p>
<h2>头文件声明</h2>
<p>&nbsp;</p>
<p>打开 <strong>iTennisViewController.h</strong> 加入下列代码：</p>
<p><a href="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_11.png"><img title="screenshot_11" src="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_11.png" alt="screenshot_11" width="325" height="356"></a></p>
<p>&nbsp;</p>
<p>首先我们看到代码引入AudioServices.h，我们需要使用其中一些函数来播放音频。接下来定义了两个SystemSoundID。它们都是Integers（整数型，也可以使用int，但会引起许多警告信息）。然后打开<strong>iTennishViewController.m</strong>加入下面代码：</p>
<p><a href="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_09.png"><img title="screenshot_09" src="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_09.png" alt="screenshot_09" width="258" height="27"></a></p>
<p>&nbsp;</p>
<p>现在我们来初始化声音对象。找到viewDidLoad方法加入下列代码：</p>
<p><a href="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_12.png"><img title="screenshot_12" src="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_12.png" alt="screenshot_12" width="709" height="223"></a></p>
<p>&nbsp;</p>
<p>很简单吧。第一行是获取音频文件路径。下一行是将路径转换为CFURLRef。最后，加载音频文件并与指定soundID联系起来。注意我们传递的&amp;clappingFileID参数，  这是通过参考地址传递的，因此它允许AudioServicesCreateSystemSoundID方法对其进行修改。我们用同样方法处理击球声。下面，我们可以开始播放了。</p>
<p>&nbsp;</p>
<h2>声音播放</h2>
<p>&nbsp;</p>
<p>播放加载好的声音实际上很简单。只需将需要播放文件的soundID传递给AudioServicesPlaySystemSound方法即可。所以播放得分时的鼓掌声只需在reset方法中加入下列代码：</p>
<p><a href="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_14.png"><img title="screenshot_14" src="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_14.png" alt="screenshot_14" width="322" height="52"></a></p>
<p>&nbsp;</p>
<p>请注意，我们传递的clappingFileID说明我们是要播放鼓掌声。加在gameLoop中加入下列代码将播放球拍击球的声音：</p>
<p><a href="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_15.png"><img title="screenshot_15" src="http://icodeblog.com/wp-content/uploads/2009/05/screenshot_15.png" alt="screenshot_15" width="381" height="209"></a></p>
<p>&nbsp;</p>
<p>很容易吧？按“Build and Go”试玩我们的游戏吧。源代码<a href="http://icodeblog.com/wp-content/uploads/2009/05/itennis-4.zip">下载</a> 。</p>
<p>&nbsp;</p>
<h5>原文见：<a href="http://icodeblog.com/2009/05/04/iphone-game-programming-tutorial-part-4-basic-game-audio/" rel="bookmark" title="Permanent Link to iPhone Game Programming Tutorial Part 4 – Basic Game Audio">iPhone Game Programming Tutorial Part 4 – Basic Game Audio </a> </h5>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iphone%e6%b8%b8%e6%88%8f%e7%bc%96%e7%a8%8b%e6%95%99%e7%a8%8b%e4%b9%8b%e5%9b%9b-%e6%b8%b8%e6%88%8f%e7%ae%80%e5%8d%95%e9%9f%b3%e9%a2%91/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>使用AVAudioPlayer轻松搞定音频播放</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bd%bf%e7%94%a8avaudioplayer%e8%bd%bb%e6%9d%be%e6%90%9e%e5%ae%9a%e9%9f%b3%e9%a2%91%e6%92%ad%e6%94%be</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bd%bf%e7%94%a8avaudioplayer%e8%bd%bb%e6%9d%be%e6%90%9e%e5%ae%9a%e9%9f%b3%e9%a2%91%e6%92%ad%e6%94%be#comments</comments>
		<pubDate>Tue, 11 Aug 2009 05:35:07 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[音频]]></category>

		<guid isPermaLink="false">http://iphonegeek.zuesitech.com/?p=141</guid>
		<description><![CDATA[  
  iPhone SDK中的AVFoundation框架包括的AVAudioPlayer是一个容易使用而且功能强大，基于object-c的播放音频文件播放器。
&#160;
本教程展示了怎样使用AVAudioPlayer。本教程将建立一个简单的程序，它能够循环播放一段mp3音频文件。 

&#160;
源代码/Guithub
&#160;

  教程的源代码在GitHub上。你可以从仓库中克隆或直接下载zip文件。 
&#160;
 创建项目 
&#160;

  Launch Xcode and create a new View-Based iPhone  application called AudioPlayer:
  启动Xcode并创建一个&#8220;View-Based iPhone application&#8221;项目，取名为AudioPlayer:
&#160;
&#160;&#160;&#160;&#160;1.从Xcode菜单选择&#8220;File &#62;  New Project &#8230;&#8221;
&#160;&#160;&#160;&#160;2.从&#8220;iPhone OS &#62; Application&#8221;部分选择&#8220;View-based Application&#8221;，然后按&#8220;Choose&#8230;&#8221;
&#160;&#160;&#160;&#160;3.将项目命名为&#8220;AudioPlayer&#8221;并按&#8220;Save&#8221;
&#160;

  添加AVFoundation框架 
&#160;

为使用SDK的AVAudioPlayer类，我们需要将AVFoundation框架加入项目： 
&#160;
&#160;&#160;&#160;&#160;1.在项目的&#8220;Groups &#38; Files&#8221;面板上，展开&#8220;Targets&#8221;
&#160;&#160;&#160;&#160;2.Control+点击或右击AudioPlayer
&#160;&#160;&#160;&#160;3.选择&#8220;Add &#62; Existing Frameworks&#8230;&#8221;
&#160;&#160;&#160;&#160;4.点击Linked Libraries下左下方的+按钮 
&#160;&#160;&#160;&#160;5.选择&#8220;AVFoundation Framework&#8220;并按Add
&#160;&#160;&#160;&#160;6.&#8220;AVFoundation framewoks&#8221;将出现在&#8220;Linked Libraries&#8221;下，关闭窗口
&#160;

  下面，我们将引入AVFoundation的头文件 
&#160;
&#160;&#160;&#160;&#160;1.展开项目&#8220;Group [...]]]></description>
			<content:encoded><![CDATA[<p> <img border="0" width="200" height="136" src="http://www.mobileorchard.com/wp-content/uploads/2009/08/reel.jpg" alt="reel.jpg"> </p>
<p align="left">  iPhone SDK中的AVFoundation框架包括的AVAudioPlayer是一个容易使用而且功能强大，基于object-c的播放音频文件播放器。</p>
<p>&nbsp;</p>
<p>本教程展示了怎样使用AVAudioPlayer。本教程将建立一个简单的程序，它能够循环播放一段mp3音频文件。 </p>
<p><span id="more-141"></span></p>
<p>&nbsp;</p>
<h2 align="left"><strong>源代码/Guithub</strong></h2>
<p>&nbsp;</p>
<p align="left">
  <a href="http://github.com/dcgrigsby/AudioPlayer">教程的源代码</a>在GitHub上。你可以从仓库中克隆或直接下载<a href="http://github.com/dcgrigsby/AudioPlayer/zipball/master">zip</a>文件。 </p>
<p>&nbsp;</p>
<h3 align="left"> <strong>创建项目 </strong></h3>
<p>&nbsp;</p>
<p align="left">
  Launch Xcode and create a new View-Based iPhone  application called AudioPlayer:<br />
  启动Xcode并创建一个&ldquo;View-Based iPhone application&rdquo;项目，取名为AudioPlayer:</p>
<p>&nbsp;</p>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;1.从Xcode菜单选择&ldquo;File &gt;  New Project &#8230;&rdquo;</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;2.从&ldquo;iPhone OS &gt; Application&rdquo;部分选择&ldquo;View-based Application&rdquo;，然后按&ldquo;Choose&#8230;&rdquo;</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;3.将项目命名为&ldquo;AudioPlayer&rdquo;并按&ldquo;Save&rdquo;</h5>
<p>&nbsp;</p>
<h3 align="left">
  <strong>添加AVFoundation框架 </strong></h3>
<p>&nbsp;</p>
<p align="left">
为使用SDK的AVAudioPlayer类，我们需要将AVFoundation框架加入项目： </p>
<p>&nbsp;</p>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;1.在项目的&ldquo;Groups &amp; Files&rdquo;面板上，展开&ldquo;Targets&rdquo;</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;2.Control+点击或右击AudioPlayer</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;3.选择&ldquo;Add &gt; Existing Frameworks&#8230;&rdquo;</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;4.点击Linked Libraries下左下方的+按钮 </h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;5.选择&ldquo;AVFoundation Framework&ldquo;并按Add</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;6.&ldquo;AVFoundation framewoks&rdquo;将出现在&ldquo;Linked Libraries&rdquo;下，关闭窗口</h5>
<p>&nbsp;</p>
<p align="left">
  下面，我们将引入AVFoundation的头文件 </p>
<p>&nbsp;</p>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;1.展开项目&ldquo;Group &amp; Files&rdquo;面板下AudioPlayer项目</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;2.打开Classes文件夹</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;3.选取<em>AudioPlayerViewController.h</em>进行编辑</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;4.更改文件。更改以下粗体字部分：</h5>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #6e371a;">#import &lt;UIKit/UIKit.h&gt;</span><br />
<span style="color: #6e371a;">#import &lt;AVFoundation/AVFoundation.h&gt;</span><br />
<br />
<span style="color: #a61390;">@interface</span> AudioPlayerViewController <span style="color: #002200;">:</span> &nbsp;UIViewController <br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; AVAudioPlayer &nbsp;<span style="color: #002200;">*</span>audioPlayer;<br />
<span style="color: #002200;">&#125;</span><br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<h3 align="left"><strong>添加音频文件</strong></h3>
<p>&nbsp;</p>
<p align="left">
  我们需要一段音频文件来进行播放。文件为audiofie.mp3。我们将其加入项目中：</p>
<p>&nbsp;</p>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;1.按Control再左击或右击项目的&ldquo;Group &amp; Files&rdquo;面板中的&ldquo;Resources&rdquo;文件夹</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;2.从上下文菜单中选取&ldquo;<em>Add &gt; Existing Files&hellip;</em>&rdquo;</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;3.找到并选择要导入的音频文件，按&ldquo;Add&rdquo;</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;4.（有必要的话）选定&ldquo;<em>Copy items into destination  group&rsquo;s folder&rdquo;</em>方框并按&ldquo;Add&rdquo;</h5>
<p>&nbsp;</p>
<h3 align="left"><strong>开始播放音频</strong></h3>
<p>&nbsp;</p>
<p align="left">
  我们在ViewDidLoad中启动音频播放:</p>
<p>&nbsp;</p>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;1.解除ViewDidLoad方法的注解</h5>
<h5>&nbsp;&nbsp;&nbsp;&nbsp;2.更改如下，见粗体部分：</h5>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>viewDidLoad<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>super &nbsp;viewDidLoad<span style="color: #002200;">&#93;</span>;<br />
<br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> &nbsp;<span style="color: #002200;">*</span>url <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> fileURLWithPath<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a> &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@/audiofile.mp3&quot;</span>, &nbsp;<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSBundle_Class/"><span style="color: #400080;">NSBundle</span></a> mainBundle<span style="color: #002200;">&#93;</span> &nbsp;resourcePath<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span style="color: #400080;">NSError</span></a> &nbsp;<span style="color: #002200;">*</span>error;<br />
&nbsp; &nbsp; audioPlayer &nbsp;<span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>AVAudioPlayer alloc<span style="color: #002200;">&#93;</span> initWithContentsOfURL<span style="color: #002200;">:</span>url error<span style="color: #002200;">:&amp;</span>error<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; audioPlayer.numberOfLoops &nbsp;<span style="color: #002200;">=</span> <span style="color: #002200;">-</span><span style="color: #2400d9;">1</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> &nbsp;<span style="color: #002200;">&#40;</span>audioPlayer <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>error &nbsp;description<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #002200;">&#91;</span>audioPlayer &nbsp;play<span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p align="left">
  AVAudioPlayer是通过URL初始化的，所以我们首先要创立一个指向资源文件夹中音频文件的URL。将音频播放器的numberOfLoops属性设为负数使得播放无限循环。配置好音频播放器后，我们向播放器对象发送播放消息来启动播放。</p>
<p>&nbsp;</p>
<p align="left">
  记住在dealloc方法中释放audioPlayer。改变见粗体部分：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc <br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>audioPlayer &nbsp;release<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>super &nbsp;dealloc<span style="color: #002200;">&#93;</span>;<br />
&nbsp; <span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<h3 align="left">
  <strong>更多功能</strong></h3>
<p>&nbsp;</p>
<p align="left">
你可以调节播放器音量，查看/设定播放的时间，暂停或停止播放：</p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; audioPlayer.volume <span style="color: #002200;">=</span> <span style="color: #2400d9;">0.5</span>; <span style="color: #11740a; font-style: italic;">// 0.0 - no &nbsp;volume; 1.0 full volume</span><br />
&nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%f seconds played so &nbsp;far&quot;</span>, audioPlayer.currentTime<span style="color: #002200;">&#41;</span>;<br />
&nbsp; audioPlayer.currentTime <span style="color: #002200;">=</span> <span style="color: #2400d9;">10</span>; <span style="color: #11740a; font-style: italic;">// jump to &nbsp;the 10 second mark</span><br />
&nbsp; <span style="color: #002200;">&#91;</span>audioPlayer pause<span style="color: #002200;">&#93;</span>;<br />
&nbsp; <span style="color: #002200;">&#91;</span>audioPlayer stop<span style="color: #002200;">&#93;</span>; <span style="color: #11740a; font-style: italic;">// Does not reset &nbsp;currentTime; sending play resumes</span></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p align="left">
  最后，你还可以实现AVAudioPlayerDelegate协议,比如说，在音频播放结束时得到通知，这样你有可能移动到播放列表的下一首歌。</p>
<p>&nbsp;</p>
<h5 align="left"><strong>原文出自：</strong><a href="http://www.mobileorchard.com/easy-audio-playback-with-avaudioplayer/"><strong>Tutorial: Easy Audio Playback With AVAudioPlayer</strong></a></h5>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bd%bf%e7%94%a8avaudioplayer%e8%bd%bb%e6%9d%be%e6%90%9e%e5%ae%9a%e9%9f%b3%e9%a2%91%e6%92%ad%e6%94%be/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>将音频转换成CAF格式</title>
		<link>http://www.iphone-geek.cn/%e6%8a%80%e5%b7%a7%e4%b8%8e%e6%8f%90%e7%a4%ba/%e5%b0%86%e9%9f%b3%e9%a2%91%e8%bd%ac%e6%8d%a2%e6%88%90caf%e6%a0%bc%e5%bc%8f</link>
		<comments>http://www.iphone-geek.cn/%e6%8a%80%e5%b7%a7%e4%b8%8e%e6%8f%90%e7%a4%ba/%e5%b0%86%e9%9f%b3%e9%a2%91%e8%bd%ac%e6%8d%a2%e6%88%90caf%e6%a0%bc%e5%bc%8f#comments</comments>
		<pubDate>Thu, 12 Mar 2009 12:48:50 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[技巧与提示]]></category>
		<category><![CDATA[音频]]></category>

		<guid isPermaLink="false">http://iphonegeekbeta.zuesitech.com/?p=100</guid>
		<description><![CDATA[
在mac上使用afconvert命令可以将音频文件转换成caf文件。

  

afconvert -f caff -d LEI16@44100 -c 1 in.wav out.caf



-f 指定文件格式
-d 数据格式，@44100指采样率
-c 通道数
]]></description>
			<content:encoded><![CDATA[<p>
在mac上使用afconvert命令可以将音频文件转换成caf文件。</p>
<p>
  </p>
<div class="sourcecode">
afconvert -f caff -d LEI16@44100 -c 1 in.wav out.caf
</div>
</p>
<p>
-f 指定文件格式</p>
<p>-d 数据格式，@44100指采样率</p>
<p>-c 通道数</p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e6%8a%80%e5%b7%a7%e4%b8%8e%e6%8f%90%e7%a4%ba/%e5%b0%86%e9%9f%b3%e9%a2%91%e8%bd%ac%e6%8d%a2%e6%88%90caf%e6%a0%bc%e5%bc%8f/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
