前腐后继 发表于 2006-12-13 11:23:00

openal教程

<strong><br/></strong>&nbsp;openal教程(一)<br/>简介<br/>&nbsp;&nbsp;&nbsp;欢迎来到OPENAL的世界!OPENAL一直在不断的创新,几乎没有一个API能达到<br/>她的全部潜能。一个很大的原因是因为hardware加速建立在特殊的版卡上。然而,<br/>Creative&nbsp;Labs是APENAL的主要支持者,同时也是最大声卡厂商之一。OPENAL的另<br/>一个主要支持者LOKI。<br/>&nbsp;&nbsp;&nbsp;OPENAL不是商业产品,那样做限制了她的发展。我只知道再PC游戏中用OPENAL。<br/>OPENAL有许多的潜能,有许多的声音库工作在最地层的hardware上。但OPENAL的<br/>设计者经过无数的测试使她成为一个高级的API。她的风格是自由的,不同的编码<br/>风格和hardware部件将充分运用她的功能。有OPENGL编程精练的人将很快掌握OPEN<br/>AL。OPENAL有建立3D环境音效的能力。<br/>&nbsp;&nbsp;&nbsp;OPENAL是very&nbsp;cool,她是一个非常清晰的API并且能熔入你的代码。你将做出<br/>很COOL的音效,下面让我们进入COOL&nbsp;COOL的OPENAL世界。<br/>&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;conio.h&gt;<br/>&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;stdlib.h&gt;<br/>&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;al/al.h&gt;<br/>&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;al/alc.h&gt;<br/>&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;al/alu.h&gt;<br/>&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;al/alut.h&gt;<br/>&nbsp;&nbsp;你会发现再OPENAL头和OPENGL头的定义上有许多的相似之处。除了“al.h","al<br/>u.h","alut.h"与”gl.h","glu.h","glut.h"相似,还增加了一个"alc.h".ALC(<br/>AUDIO&nbsp;LIBRARY&nbsp;CONTEXT)处理声音通过不同的平台,她也处理你在几个窗口下共<br/>享设备的环境。<br/>&nbsp;&nbsp;//&nbsp;存储声音数据<br/>ALuint&nbsp;Buffer; <p></p><p>//&nbsp;用于播放声音<br/>ALuint&nbsp;Source;<br/>&nbsp;&nbsp;这是程序处理结构的初始化。在OPENAL中三种不同的结构,所有关于声音播放和<br/>声音数据存储在一个内存中,源(source)是指向放声音的空间。明白源是非常<br/>的重要。源只播放内存中的背景声音数据。源也给出了特殊的属性如位置和速度。<br/>&nbsp;&nbsp;第三个对象是听者,用户就是那唯一的听者。听者属性属于源属性,决定如何<br/>听声音。例如,不同位置将决定声音的速度。<br/>&nbsp;&nbsp;//&nbsp;源声音的位置<br/>ALfloat&nbsp;SourcePos[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;源声音的速度<br/>ALfloat&nbsp;SourceVel[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p><br/>//&nbsp;听者的位置<br/>ALfloat&nbsp;ListenerPos[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;听者的速度<br/>ALfloat&nbsp;ListenerVel[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;听者的方向&nbsp;(first&nbsp;3&nbsp;elements&nbsp;are&nbsp;"at",&nbsp;second&nbsp;3&nbsp;are&nbsp;"up")<br/>ALfloat&nbsp;ListenerOri[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;-1.0,&nbsp;&nbsp;0.0,&nbsp;1.0,&nbsp;0.0&nbsp;};<br/>&nbsp;&nbsp;在上面的代码中,我们定义了源和听者对象的位置和速度。这些数组是基于笛<br/>卡儿坐标的矢量。你能很容易用结构或类做相同的事情。<br/>&nbsp;&nbsp;ALboolean&nbsp;LoadALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;载入变量.</p><p>&nbsp;&nbsp;&nbsp;&nbsp;ALenum&nbsp;format;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;size;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALvoid*&nbsp;data;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;freq;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALboolean&nbsp;loop;<br/>&nbsp;&nbsp;在这里我们建立一个函数用于从一个文件中载入声音数据。变量用于存储适合<br/>我们的ALUT信息。<br/>&nbsp;&nbsp;//&nbsp;载入WAV数据<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGenBuffers(1,&nbsp;&amp;Buffer);<br/>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/FancyPants.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffer,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;函数alGenBufers用于建立对象内存并把他们存储在我们定义的变量中。然后判断<br/>数据是否存储。<br/>&nbsp;&nbsp;ALUT库为我们打开文件,提供我们建立内存所需的信息,并且在我们归属所有<br/>数据到内存后,她将处理这些数据。<br/>&nbsp;&nbsp;//&nbsp;捆绑源<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGenSources(1,&nbsp;&amp;Source);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Source,&nbsp;AL_BUFFER,&nbsp;&nbsp;&nbsp;Buffer&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Source,&nbsp;AL_PITCH,&nbsp;&nbsp;&nbsp;&nbsp;1.0f&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Source,&nbsp;AL_GAIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.0f&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Source,&nbsp;AL_POSITION,&nbsp;SourcePos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Source,&nbsp;AL_VELOCITY,&nbsp;SourceVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Source,&nbsp;AL_LOOPING,&nbsp;&nbsp;loop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;我们用建立内存对象的方法建立了源对象。然后,我们定义源属性用于录放。<br/>最重要的属性是她用的内存。这告诉源用于录放。因此,我们只有捆绑她。同时,<br/>我们也告诉她我们定义的源位置和速度。<br/>&nbsp;&nbsp;//&nbsp;做错误检测并返回<br/>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;==&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_TRUE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;<br/>&nbsp;&nbsp;在函数的结尾,我们将做更多的检测,以确定她的正确。<br/>&nbsp;&nbsp;void&nbsp;SetListenervalues()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_POSITION,&nbsp;&nbsp;&nbsp;&nbsp;ListenerPos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_VELOCITY,&nbsp;&nbsp;&nbsp;&nbsp;ListenerVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_ORIENTATION,&nbsp;ListenerOri);<br/>}<br/>我们建立一个函数用于更新听者速度。<br/>&nbsp;&nbsp;void&nbsp;KillALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;alDeleteBuffers(1,&nbsp;&amp;Buffer);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alDeleteSources(1,&nbsp;&amp;Source);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutExit();<br/>}<br/>这是一个关闭函数,用于释放内存和音频设备。<br/>&nbsp;int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;*argv[])<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;初始OPENAL并清错误字节</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutInit(&amp;argc,&nbsp;argv);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGetError();<br/>&nbsp;&nbsp;函数alutInit将安装ALC需要的东西。ALUT通过ALC并设置她为当前建立OPENAL<br/>环境描述。在WINDOWS平台上初始DIRECTSOUND。然后用‘GLGETERROR’检测错误。<br/>&nbsp;&nbsp;&nbsp;//&nbsp;载入WAV数据<br/>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(LoadALData()&nbsp;==&nbsp;AL_FALSE)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;-1;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;SetListenervalues();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设置退出函数<br/>&nbsp;&nbsp;&nbsp;&nbsp;atexit(KillALData);<br/>&nbsp;&nbsp;我们将检测WAV文件是否正确载入。如果没有退出程序。<br/>&nbsp;&nbsp;正确后,更新听者参数,最后退出。<br/>&nbsp;&nbsp;ALubyte&nbsp;c&nbsp;=&nbsp;'&nbsp;';</p><p>&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(c&nbsp;!=&nbsp;'q')<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;=&nbsp;getche();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(c)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Pressing&nbsp;'p'&nbsp;will&nbsp;begin&nbsp;playing&nbsp;the&nbsp;sample.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'p':&nbsp;alSourcePlay(Source);&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Pressing&nbsp;'s'&nbsp;will&nbsp;stop&nbsp;the&nbsp;sample&nbsp;from&nbsp;playing.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'s':&nbsp;alSourceStop(Source);&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Pressing&nbsp;'h'&nbsp;will&nbsp;pause&nbsp;(hold)&nbsp;the&nbsp;sample.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'h':&nbsp;alSourcePause(Source);&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br/>&nbsp;&nbsp;&nbsp;&nbsp;}</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br/>}<br/>This&nbsp;is&nbsp;the&nbsp;interesting&nbsp;part&nbsp;of&nbsp;the&nbsp;tutorial.&nbsp;It's&nbsp;a&nbsp;very&nbsp;basic&nbsp;loop&nbsp;that&nbsp;lets&nbsp;us&nbsp;control&nbsp;the&nbsp;playback&nbsp;of&nbsp;the&nbsp;audio&nbsp;sample.&nbsp;Pressing&nbsp;'p'&nbsp;will&nbsp;replay&nbsp;the&nbsp;sample,&nbsp;pressing&nbsp;'s'&nbsp;will&nbsp;stop&nbsp;the&nbsp;sample,&nbsp;and&nbsp;pressing&nbsp;'h'&nbsp;will&nbsp;pause&nbsp;the&nbsp;sample.&nbsp;Pressing&nbsp;'q'&nbsp;will&nbsp;exit&nbsp;the&nbsp;program.</p><p>Well&nbsp;there&nbsp;it&nbsp;is.&nbsp;Your&nbsp;first&nbsp;delve&nbsp;into&nbsp;OpenAL.&nbsp;I&nbsp;hope&nbsp;it&nbsp;was&nbsp;made&nbsp;simple&nbsp;enough&nbsp;for&nbsp;you.&nbsp;It&nbsp;may&nbsp;have&nbsp;been&nbsp;a&nbsp;little&nbsp;too&nbsp;simple&nbsp;for&nbsp;the&nbsp;1337&nbsp;h4X0r,&nbsp;but&nbsp;we&nbsp;all&nbsp;got&nbsp;to&nbsp;start&nbsp;somewhere.&nbsp;Things&nbsp;will&nbsp;get&nbsp;more&nbsp;advanced&nbsp;as&nbsp;we&nbsp;go&nbsp;along.</p><p>Download&nbsp;the&nbsp;Dev-C++&nbsp;source&nbsp;and&nbsp;project&nbsp;file&nbsp;</p><p>如果大家有什么问题,请告诉我e-mail:ouyunfei12@mail.china.com.<br/></p>

前腐后继 发表于 2006-12-13 11:24:00

<p>openal教程(二)<br/>&nbsp;循环和消退<br/>&nbsp;希望你觉得上一章有用,这一章将更容易。<br/>&nbsp;&nbsp;#include&nbsp;&lt;conio.h&gt;<br/>#include&nbsp;&lt;time.h&gt;<br/>#include&nbsp;&lt;stdlib.h&gt;<br/>#include&nbsp;&lt;al/al.h&gt;<br/>#include&nbsp;&lt;al/alc.h&gt;<br/>#include&nbsp;&lt;al/alu.h&gt;<br/>#include&nbsp;&lt;al/alut.c&gt;</p><p>//&nbsp;存储声音数据.<br/>ALuint&nbsp;Buffer;</p><p>//&nbsp;用于播放声音.<br/>ALuint&nbsp;Source;</p><p>//&nbsp;&nbsp;源声音的位置.<br/>ALfloat&nbsp;SourcePos[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;源声音的速度.<br/>ALfloat&nbsp;SourceVel[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.1&nbsp;};</p><p>//&nbsp;听者的位置.<br/>ALfloat&nbsp;ListenerPos[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;听者的速度<br/>ALfloat&nbsp;ListenerVel[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;听者的方向&nbsp;(first&nbsp;3&nbsp;elements&nbsp;are&nbsp;"at",&nbsp;second&nbsp;3&nbsp;are&nbsp;"up")<br/>ALfloat&nbsp;ListenerOri[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;-1.0,&nbsp;&nbsp;0.0,&nbsp;1.0,&nbsp;0.0&nbsp;};<br/>&nbsp;这一章与上一章唯一的不同是源速度的改变,他的‘Z’现在是0.1.<br/>ALboolean&nbsp;LoadALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;载入变量<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALenum&nbsp;format;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;size;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALvoid*&nbsp;data;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;freq;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALboolean&nbsp;loop;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;载入WAV数据.</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alGenBuffers(1,&nbsp;&amp;Buffer);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/Footsteps.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffer,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;捆绑源</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alGenSources(1,&nbsp;&amp;Source);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Source,&nbsp;AL_BUFFER,&nbsp;&nbsp;&nbsp;Buffer&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Source,&nbsp;AL_PITCH,&nbsp;&nbsp;&nbsp;&nbsp;1.0f&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Source,&nbsp;AL_GAIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.0f&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Source,&nbsp;AL_POSITION,&nbsp;SourcePos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Source,&nbsp;AL_VELOCITY,&nbsp;SourceVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Source,&nbsp;AL_LOOPING,&nbsp;&nbsp;AL_TRUE&nbsp;&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;做错误检测并返回</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_TRUE;<br/>}<br/>&nbsp;在这一节中有两处改变,首先是导入“FOOTSTES。WAV”,设置源‘AL_LOOPING’<br/>为‘AL_TRUE’。这意味着源播放直到停止时结束。他将不断的循环播放。<br/>&nbsp;void&nbsp;SetListenervalues()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_POSITION,&nbsp;&nbsp;&nbsp;&nbsp;ListenerPos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_VELOCITY,&nbsp;&nbsp;&nbsp;&nbsp;ListenerVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_ORIENTATION,&nbsp;ListenerOri);<br/>}</p><p>void&nbsp;KillALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;alDeleteBuffers(1,&nbsp;&amp;Buffer);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alDeleteSources(1,&nbsp;&amp;Source);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutExit();<br/>}<br/>这里没有改变。<br/>int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;*argv[])<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;初始OPENAL并清错误字节<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutInit(NULL,0);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGetError();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;载入WAV数据.<br/>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(LoadALData()&nbsp;==&nbsp;AL_FALSE)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;SetListenervalues();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;设置退出函数.<br/>&nbsp;&nbsp;&nbsp;&nbsp;atexit(KillALData);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;开始源的播放.<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcePlay(Source);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//循环<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALint&nbsp;time&nbsp;=&nbsp;0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALint&nbsp;elapse&nbsp;=&nbsp;0;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(!kbhit())<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elapse&nbsp;+=&nbsp;clock()&nbsp;-&nbsp;time;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time&nbsp;+=&nbsp;elapse;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(elapse&nbsp;&gt;&nbsp;50)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elapse&nbsp;=&nbsp;0;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourcePos&nbsp;+=&nbsp;SourceVel;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourcePos&nbsp;+=&nbsp;SourceVel;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourcePos&nbsp;+=&nbsp;SourceVel;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Source,&nbsp;AL_POSITION,&nbsp;SourcePos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;}</p><p><br/>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br/>}<br/>&nbsp;这里唯一的改变是增加了一个循环。他将代替播放和停止按钮。<br/>&nbsp;We&nbsp;do&nbsp;this&nbsp;by&nbsp;slowly&nbsp;incrementing&nbsp;the&nbsp;position&nbsp;by&nbsp;it's&nbsp;velocity&nbsp;over<br/>&nbsp;time.&nbsp;The&nbsp;time&nbsp;is&nbsp;sampled&nbsp;by&nbsp;checking&nbsp;the&nbsp;system&nbsp;clock&nbsp;which&nbsp;gives<br/>&nbsp;us&nbsp;a&nbsp;tick&nbsp;count.&nbsp;It&nbsp;shouldn't&nbsp;be&nbsp;necessary&nbsp;to&nbsp;change&nbsp;this,&nbsp;but&nbsp;if&nbsp;the&nbsp;<br/>audio&nbsp;clip&nbsp;fades&nbsp;too&nbsp;fast&nbsp;you&nbsp;might&nbsp;want&nbsp;to&nbsp;change&nbsp;50&nbsp;to&nbsp;some&nbsp;higher&nbsp;n<br/>umber.&nbsp;Pressing&nbsp;any&nbsp;key&nbsp;will&nbsp;end&nbsp;the&nbsp;loop<br/>&nbsp;&nbsp;如果大家有什么问题,请告诉我e-mail:ouyunfei12@mail.china.com</p>

前腐后继 发表于 2006-12-13 11:25:00

<p>openal教程(三)<br/>&nbsp;&nbsp;&nbsp;多源<br/>&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;你好,在这一章中,我们将在上一章的例程中加入一些元素,使他能同时<br/>&nbsp;&nbsp;&nbsp;播放超过一种的音乐。<br/>&nbsp;&nbsp;&nbsp;通常在一个优秀的游戏中有各种不同的音夹(clip),这是怎样实现的呢?<br/>&nbsp;&nbsp;&nbsp;下面将介绍。<br/>&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;conio.h&gt;<br/>#include&nbsp;&lt;time.h&gt;<br/>#include&nbsp;&lt;stdlib.h&gt;<br/>#include&nbsp;&lt;al/al.h&gt;<br/>#include&nbsp;&lt;al/alc.h&gt;<br/>#include&nbsp;&lt;al/alu.h&gt;<br/>#include&nbsp;&lt;al/alut.c&gt; </p><p></p><p>//&nbsp;我们需要的最大的数据缓冲.<br/>#define&nbsp;NUM_BUFFERS&nbsp;3</p><p>//&nbsp;我们需要放三种声音.<br/>#define&nbsp;NUM_SOURCES&nbsp;3</p><p>//&nbsp;缓冲和源标志.<br/>#define&nbsp;BATTLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0<br/>#define&nbsp;GUN1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1<br/>#define&nbsp;GUN2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2</p><p>//&nbsp;存储声音数据.<br/>ALuint&nbsp;Buffers;</p><p>//&nbsp;用于播放声音.<br/>ALuint&nbsp;Sources;</p><p>//&nbsp;源声音的位置.<br/>ALfloat&nbsp;SourcesPos;</p><p>//&nbsp;源声音的速度.<br/>ALfloat&nbsp;SourcesVel;</p><p><br/>//&nbsp;听者的位置.<br/>ALfloat&nbsp;ListenerPos[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;听者的速度.<br/>ALfloat&nbsp;ListenerVel[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;0.0&nbsp;};</p><p>//&nbsp;听者的方向&nbsp;(first&nbsp;3&nbsp;elements&nbsp;are&nbsp;"at",&nbsp;second&nbsp;&nbsp;3&nbsp;are&nbsp;"up")<br/>ALfloat&nbsp;ListenerOri[]&nbsp;=&nbsp;{&nbsp;0.0,&nbsp;0.0,&nbsp;-1.0,&nbsp;0.0,&nbsp;1.0,&nbsp;0.0&nbsp;};<br/>&nbsp;<br/>&nbsp;在这一章中,唯一的不同是多了3种将导入Openal系统的不同的声音效果&nbsp;。<br/>&nbsp;<br/>&nbsp;ALboolean&nbsp;LoadALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;载入变量.</p><p>&nbsp;&nbsp;&nbsp;&nbsp;ALenum&nbsp;format;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;size;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALvoid*&nbsp;data;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;freq;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALboolean&nbsp;loop;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;载入WAV数据.</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alGenBuffers(NUM_BUFFERS,&nbsp;Buffers);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/Battle.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/Gun1.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/Gun2.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;捆绑源.</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alGenSources(NUM_SOURCES,&nbsp;Sources);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Sources,&nbsp;AL_BUFFER,&nbsp;&nbsp;&nbsp;Buffers&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Sources,&nbsp;AL_PITCH,&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Sources,&nbsp;AL_GAIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Sources,&nbsp;AL_POSITION,&nbsp;SourcePos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Sources,&nbsp;AL_VELOCITY,&nbsp;SourceVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Sources,&nbsp;AL_LOOPING,&nbsp;&nbsp;AL_TRUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Sources,&nbsp;AL_BUFFER,&nbsp;&nbsp;&nbsp;Buffers&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Sources,&nbsp;AL_PITCH,&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Sources,&nbsp;AL_GAIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Sources,&nbsp;AL_POSITION,&nbsp;SourcePos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Sources,&nbsp;AL_VELOCITY,&nbsp;SourceVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Sources,&nbsp;AL_LOOPING,&nbsp;&nbsp;AL_FALSE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Sources,&nbsp;AL_BUFFER,&nbsp;&nbsp;&nbsp;Buffers&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Sources,&nbsp;AL_PITCH,&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(Sources,&nbsp;AL_GAIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Sources,&nbsp;AL_POSITION,&nbsp;SourcePos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Sources,&nbsp;AL_VELOCITY,&nbsp;SourceVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(Sources,&nbsp;AL_LOOPING,&nbsp;&nbsp;AL_FALSE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;做错误检测并返回</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_TRUE;<br/>}<br/>&nbsp;首先,我们导入文件数据到3个缓冲区,然后把3个缓冲区和3个源锁在<br/>&nbsp;一起。唯一的不同是文件“battle.wav”在不停止时循环。<br/>&nbsp;void&nbsp;SetListenervalues()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_POSITION,&nbsp;&nbsp;&nbsp;&nbsp;ListenerPos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_VELOCITY,&nbsp;&nbsp;&nbsp;&nbsp;ListenerVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alListenerfv(AL_ORIENTATION,&nbsp;ListenerOri);<br/>}</p><p>void&nbsp;KillALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;alDeleteBuffers(NUM_BUFFERS,&nbsp;&amp;Buffers);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alDeleteSources(NUM_SOURCES,&nbsp;&amp;Sources);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutExit();<br/>}<br/>在这段代码中,我们没有改变。<br/>int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;*argv[])<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Initialize&nbsp;OpenAL&nbsp;and&nbsp;clear&nbsp;the&nbsp;error&nbsp;bit.<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutInit(NULL,&nbsp;0);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGetError();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Load&nbsp;the&nbsp;wav&nbsp;data.<br/>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(LoadALData()&nbsp;==&nbsp;AL_FALSE)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;SetListenervalues();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Setup&nbsp;an&nbsp;exit&nbsp;procedure.<br/>&nbsp;&nbsp;&nbsp;&nbsp;atexit(KillALData);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Begin&nbsp;the&nbsp;battle&nbsp;sample&nbsp;to&nbsp;play.<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcePlay(Sources);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Go&nbsp;through&nbsp;all&nbsp;the&nbsp;sources&nbsp;and&nbsp;check&nbsp;that&nbsp;they&nbsp;are&nbsp;playing.<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Skip&nbsp;the&nbsp;first&nbsp;source&nbsp;because&nbsp;it&nbsp;is&nbsp;looping&nbsp;anyway&nbsp;(will&nbsp;always&nbsp;be&nbsp;playing).<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALint&nbsp;play;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(!kbhit())<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;&nbsp;NUM_SOURCES;&nbsp;i++)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alGetSourcei(Sources,&nbsp;AL_SOURCE_STATE,&nbsp;&amp;play);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(play&nbsp;!=&nbsp;AL_PLAYING)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Pick&nbsp;a&nbsp;random&nbsp;position&nbsp;around&nbsp;the&nbsp;listener&nbsp;to&nbsp;play&nbsp;the&nbsp;source.</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;double&nbsp;theta&nbsp;=&nbsp;(double)&nbsp;(rand()&nbsp;%&nbsp;360)&nbsp;*&nbsp;3.14&nbsp;/&nbsp;180.0;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourcePos&nbsp;=&nbsp;-float(cos(theta));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourcePos&nbsp;=&nbsp;-float(rand()%2);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SourcePos&nbsp;=&nbsp;-float(sin(theta));</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(Sources,&nbsp;AL_POSITION,&nbsp;SourcePos&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alSourcePlay(Sourcev);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;}</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br/>}<br/>这段是这篇文章最有趣的地方。我们在这里将播放。如果他不播放,我们将<br/>在3D空间中选一个点播放(点击)。<br/>And&nbsp;bang!&nbsp;We&nbsp;are&nbsp;done.&nbsp;As&nbsp;most&nbsp;of&nbsp;you&nbsp;have&nbsp;probably&nbsp;seen,&nbsp;you&nbsp;don't&nbsp;have&nbsp;to&nbsp;do&nbsp;anything&nbsp;special&nbsp;to&nbsp;play&nbsp;more&nbsp;than&nbsp;one&nbsp;source&nbsp;at&nbsp;a&nbsp;time.&nbsp;OpenAL&nbsp;will&nbsp;handle&nbsp;all&nbsp;the&nbsp;mixing&nbsp;features&nbsp;to&nbsp;get&nbsp;the&nbsp;sounds&nbsp;right&nbsp;for&nbsp;their&nbsp;respective&nbsp;distances&nbsp;and&nbsp;velocities.&nbsp;And&nbsp;when&nbsp;it&nbsp;comes&nbsp;right&nbsp;down&nbsp;to&nbsp;it,&nbsp;isn't&nbsp;that&nbsp;the&nbsp;beauty&nbsp;of&nbsp;OpenAL?&nbsp;</p><p>You&nbsp;know&nbsp;that&nbsp;was&nbsp;a&nbsp;lot&nbsp;easier&nbsp;than&nbsp;I&nbsp;thought.&nbsp;I&nbsp;don't&nbsp;know&nbsp;why&nbsp;I&nbsp;waited&nbsp;so&nbsp;long&nbsp;to&nbsp;write&nbsp;it.&nbsp;Anyway,&nbsp;if&nbsp;anyone&nbsp;reading&nbsp;wants&nbsp;to&nbsp;see&nbsp;something&nbsp;specific&nbsp;in&nbsp;future&nbsp;tutorials&nbsp;(not&nbsp;necessarily&nbsp;pertaining&nbsp;to&nbsp;OpenAL,&nbsp;I&nbsp;have&nbsp;quite&nbsp;an&nbsp;extensive&nbsp;knowledge&nbsp;base)&nbsp;drop&nbsp;me&nbsp;a&nbsp;line&nbsp;at&nbsp;lightonthewater@hotmail.com&nbsp;I&nbsp;plan&nbsp;to&nbsp;do&nbsp;tutorials&nbsp;on&nbsp;sharing&nbsp;buffers&nbsp;and&nbsp;the&nbsp;Doppler&nbsp;effect&nbsp;in&nbsp;some&nbsp;later&nbsp;tutorial&nbsp;unless&nbsp;there&nbsp;is&nbsp;request&nbsp;for&nbsp;something&nbsp;else.&nbsp;Have&nbsp;fun&nbsp;with&nbsp;the&nbsp;code!</p><p>&nbsp;</p>

前腐后继 发表于 2006-12-13 11:25:00

Openal&nbsp;教程(四)<br/>&nbsp;ALC<br/>&nbsp;<br/>&nbsp;&nbsp;Alut一直为我们做着所有神奇的东西。例如处理音频设备。ALUT库为<br/>&nbsp;&nbsp;我们提供这些功能,但是一些机灵的程序员想知道他是怎样工作的。<br/>&nbsp;&nbsp;我们可以这样想,在一些点上直接用ALC。<br/>&nbsp;&nbsp;&nbsp;&nbsp;在这一章中,我们将讲述ALC层,并看一下他是怎样处理设备的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALCdevice*&nbsp;pDevice; <p></p><p>ALCubyte&nbsp;DeviceName[]&nbsp;=&nbsp;"DirectSound3D";</p><p>pDevice&nbsp;=&nbsp;alcOpenDevice(DeviceName);<br/>当然,ALC设备是什么?可以这样想,在共享整个系统下,OPENAL夺取了<br/>设备的句柄。在我们用DIRECTSOUND作为音频设备时,设备能完成的很好。<br/>程序从设备中夺取句柄并为程序准备着。<br/>传递NULL给‘alcOpenDevice',他将使ALC用默认设备。<br/>ALCcontext*&nbsp;pContext;</p><p>pContext&nbsp;=&nbsp;alcCreateContext(pDevice,&nbsp;NULL);</p><p>alcMakeContextCurrent(pContext);<br/>ALC文本描述是什么?&nbsp;OPENGL程序员能撤消通过不同窗口的<br/>状态管理的控制的精简文本描述。HGLRC能被挑调用建立多次,使多描述<br/>窗口成为可能。并且不同的文本描述状态可以实现。ALC文本描述工作在<br/>相同的原理下。首先,我们告诉他我们用的设备,然后我们做当前的文本<br/>描述。理论上你能为不同的窗口建立多个表达文本描述,并且设置不同的<br/>状态变量,以使他们能很好的工作。尽管“表达文本描述”用于可视表达。</p><p>你可能也注意到“alcCreateContext'中的第二个变量是NULL。OPENAL中<br/>下面的变量与他有关。<br/>ALC_FREQUENCY&nbsp;<br/>ALC_REFRESH&nbsp;<br/>ALC_SYNC&nbsp;<br/>你可以调用’alcMakeContextCurrent'替换你建立的多个文本描述。同样<br/>在'alcMakeContextCurrent'中置NULL。他将防止处理其他声音数据。要<br/>意识到当你有多个表达文本描述时,你只能在当前用一个。并且当你的程序<br/>要交换使用两个描述时,必须确定当前使用的描述是在当前。当你想不通过<br/>大的检查,知道用的哪个描述,必须用这些。<br/>ALcontext*&nbsp;pCurContext;<br/>pCurContext&nbsp;=&nbsp;alcGetCurrentContext();<br/>通过文本描述,你能获取设备。<br/>ALdevice*&nbsp;pCurDevice;<br/>pCurDevice&nbsp;=&nbsp;alcGetContextsDevice(pCurContext);<br/>在我们用文本描述时,我们必须收回用的设备。在处理文本描述时,有<br/>更COOL的方法。<br/>alcSuspendContext(pContext);<br/>//&nbsp;终止pContext.<br/>alcProcessContext(pContext);<br/>//&nbsp;重置pContext.<br/>&nbsp;当程序停止时,我们必须重置声音数据到文本描述。当程序暂停时,文本<br/>&nbsp;描述中的数据不会产生声音。在程序运行期间,源或缓冲区的‘lifetime'<br/>&nbsp;的有效是由源或缓冲器ID的合法性决定的。<br/>&nbsp;alcMakeContextCurrent(NULL);<br/>alcDestroyContext(pContext);<br/>alcCloseDevice(pDevice);<br/>最后,怎样清出他呢?当前文本描述被初始化为’NULL‘,描述释放并且<br/>设备句柄交还系统。在这里我们只讲了一些ALC的基本功能。<br/>ALenum&nbsp;alcGetError(ALvoid);</p><p>ALboolean&nbsp;alcIsExtensionPresent(ALCdevice*&nbsp;device,&nbsp;ALubyte*&nbsp;extName);</p><p>ALvoid*&nbsp;alcGetProcAddress(ALCdevice*&nbsp;device,&nbsp;ALubyte*&nbsp;funcName);</p><p>ALenum&nbsp;alcGetEnumvalue(ALCdevice*&nbsp;device,&nbsp;ALubyte*&nbsp;enumName);</p><p>ALubyte*&nbsp;alcGetString(ALCdevice*&nbsp;device,&nbsp;ALenum&nbsp;token);</p><p>ALvoid&nbsp;alcGetIntegerv(ALCdevice*&nbsp;device,&nbsp;ALenum&nbsp;token,&nbsp;ALsizei&nbsp;size,&nbsp;ALint*&nbsp;dest);<br/>这些做什么,我们肯定很清楚,首先,我们用'alcGetError'&nbsp;检测错误。<br/>下面三个功能是询问ALC的扩展。这在开始就应计划。最后alcGetInteger'<br/>将返回ALC的版本'ALC_MAJOR_VERSION'&nbsp;or&nbsp;'ALC_MINOR_VERSION'。<br/>函数'alcGetString'返回下面信息:<br/>ALC_DEFAULT_DEVICE_SPECIFIER&nbsp;<br/>ALC_DEVICE_SPECIFIER&nbsp;<br/>ALC_EXTENSIONS&nbsp;<br/>首先是OPENAL完成的设备的信息。OPENAL&nbsp;返回"DirectSound3D",&nbsp;<br/>第二个返回"DirectSound"&nbsp;;<br/>最后一个返回NULL。<br/>Well&nbsp;that's&nbsp;most&nbsp;of&nbsp;Alc&nbsp;for&nbsp;you.&nbsp;I&nbsp;hope&nbsp;it&nbsp;gave&nbsp;you&nbsp;a&nbsp;better&nbsp;understanding&nbsp;of&nbsp;how&nbsp;OpenAL&nbsp;interacts&nbsp;with&nbsp;the&nbsp;operation&nbsp;system.&nbsp;You&nbsp;might&nbsp;try&nbsp;writing&nbsp;your&nbsp;own&nbsp;initialization&nbsp;routines&nbsp;so&nbsp;you&nbsp;can&nbsp;cast&nbsp;off&nbsp;Alut&nbsp;altogether.&nbsp;Either&nbsp;way&nbsp;have&nbsp;fun&nbsp;with&nbsp;it.</p><p>See&nbsp;the&nbsp;Java&nbsp;Bindings&nbsp;for&nbsp;OpenAL&nbsp;page&nbsp;for&nbsp;the&nbsp;Java&nbsp;version&nbsp;of&nbsp;this&nbsp;tutorial&nbsp;-&nbsp;adapted&nbsp;by:&nbsp;Athomas&nbsp;Goldberg</p><p>如果大家有什么问题,请告诉我e-mail:ouyunfei12@mail.china.com.</p>

前腐后继 发表于 2006-12-13 11:26:00

<strong><br/><br/></strong>&nbsp;Openal教程(五)<br/>&nbsp;源共享缓冲区<br/>在这一章中,我们将讲解如何在你的缓冲区中共享多个源。这是个非常<br/>合理,自然的步筹,非常的容易。你完全可以跳过这章。但对于愿意读<br/>这一章的朋友,你将发现他非常有趣。我们将准备好ALC层以便我们能<br/>用第四章的知识。<br/>让我们开始吧,在这一章中,我们将用的矢量来自标准模板库,因此,确定<br/>你是否安装了他,最好还有一些关于他的知识。在这一章中,我不会讲<br/>STL。<br/>//&nbsp;表明缓冲区.<br/>#define&nbsp;THUNDER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0<br/>#define&nbsp;WATERDROP&nbsp;&nbsp;&nbsp;1<br/>#define&nbsp;STREAM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2<br/>#define&nbsp;RAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3<br/>#define&nbsp;CHIMES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4<br/>#define&nbsp;OCEAN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5<br/>#define&nbsp;NUM_BUFFERS&nbsp;6 <p></p><p><br/>//&nbsp;存贮声音数据.<br/>ALuint&nbsp;Buffers;</p><p>//&nbsp;播放多个声音的源的矢量表<br/>vector&lt;ALuint&gt;&nbsp;Sources;<br/>&nbsp;首先,我写出了我们用于表明缓冲区数组的一些指令。我们将用几个WAV<br/>&nbsp;文件,因此我们需要几个缓冲区。我们将用一个STL矢量代替用于存贮源<br/>&nbsp;的一个数组。我们能做这些是因为他让我们能有一个源的动态数。我们能<br/>&nbsp;一直添加源到场景,直到OPENAL脱离他们运行。<br/>&nbsp;ALboolean&nbsp;InitOpenAL()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALCdevice*&nbsp;pDevice;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALCcontext*&nbsp;pContext;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALCubyte*&nbsp;deviceSpecifier;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALCubyte&nbsp;deviceName[]&nbsp;=&nbsp;"DirectSound3D";</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;得到设备句柄&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;pDevice&nbsp;=&nbsp;alcOpenDevice(deviceName);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;得到设备说明.<br/>&nbsp;&nbsp;&nbsp;&nbsp;deviceSpecifier&nbsp;=&nbsp;alcGetString(pDevice,&nbsp;ALC_DEVICE_SPECIFIER);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;printf("Using&nbsp;device&nbsp;'%s'.\n",&nbsp;szDeviceSpecifier);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;建立声音文本描述.<br/>&nbsp;&nbsp;&nbsp;&nbsp;pContext&nbsp;=&nbsp;alcCreateContext(pDevice,&nbsp;NULL);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设置行为文本描述.<br/>&nbsp;&nbsp;&nbsp;&nbsp;alcMakeContextCurrent(pContext);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;检查错误.<br/>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alcGetError()&nbsp;!=&nbsp;ALC_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_TRUE;<br/>}<br/>这是来自上一章的代码。首先,我们得到&nbsp;"DirectSound3D"设备的句柄,<br/>然后获得用于程序的表明文本描述。<br/>这个文本描述设置当前,函数将检查在我们返回成功前,是否出错。<br/>void&nbsp;ExitOpenAL()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALCcontext*&nbsp;pCurContext;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALCdevice*&nbsp;pCurDevice;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;得到当前文本描述<br/>&nbsp;&nbsp;&nbsp;&nbsp;pCurContext&nbsp;=&nbsp;alcGetCurrentContext();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;得到用于当前文本描述的设备?<br/>&nbsp;&nbsp;&nbsp;&nbsp;pCurDevice&nbsp;=&nbsp;alcGetContextsDevice(pCurContext);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;重置当前文本描述为NULL<br/>&nbsp;&nbsp;&nbsp;&nbsp;alcMakeContextCurrent(NULL);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//释放文本描述和设备<br/>&nbsp;&nbsp;&nbsp;&nbsp;alcDestroyContext(pCurContext);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alcCloseDevice(pCurDevice);<br/>}<br/>我们用和释放的文本描述和设备将收回。另外,在OPENAL暂停程序时,设置<br/>当前文本描述为NULL。但是这些都不可预料。如果你用了多个文本描述,<br/>你也许需要更好的方法来做这些事。我将介绍一些比较好的方法。<br/>ALboolean&nbsp;LoadALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;导入的变量<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALenum&nbsp;format;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;size;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALvoid*&nbsp;data;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;freq;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALboolean&nbsp;loop;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;装载WAV文件到缓冲区<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGenBuffers(NUM_BUFFERS,&nbsp;Buffers);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/thunder.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/waterdrop.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/stream.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/rain.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/ocean.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile("wavdata/chimes.wav",&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(Buffers,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;错误检测<br/>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_FALSE;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;AL_TRUE;<br/>}<br/>在这个函数中,我将移动产生源,这是因为我们将一个一个的初始化。<br/>void&nbsp;AddSource(ALint&nbsp;type)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALuint&nbsp;source;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alGenSources(1,&nbsp;&amp;source);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(alGetError()&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("Error&nbsp;generating&nbsp;audio&nbsp;source.");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(-1);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(source,&nbsp;AL_BUFFER,&nbsp;&nbsp;&nbsp;Buffers);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(source,&nbsp;AL_PITCH,&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(source,&nbsp;AL_GAIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(source,&nbsp;AL_POSITION,&nbsp;SourcePos&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(source,&nbsp;AL_VELOCITY,&nbsp;SourceVel&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(source,&nbsp;AL_LOOPING,&nbsp;&nbsp;AL_TRUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;alSourcePlay(source);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;Sources.push_back(source);<br/>}<br/>这个函数将产生源,他将为我们载入的缓冲区中的一个产生一个源。用<br/>‘TYPE’表示缓冲区,我们文章开始建立的指令将做这些事情。然后做<br/>错误检测,确定源能播放。如果源不能将退出。<br/>void&nbsp;KillALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(vector&lt;ALuint&gt;::iterator&nbsp;iter&nbsp;=&nbsp;Sources.begin();&nbsp;iter&nbsp;!=&nbsp;Sources.end();&nbsp;++iter)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alDeleteSources(1,&nbsp;iter);<br/>&nbsp;&nbsp;&nbsp;&nbsp;Sources.clear();<br/>&nbsp;&nbsp;&nbsp;&nbsp;alDeleteBuffers(NUM_BUFFERS,&nbsp;Buffers);<br/>&nbsp;&nbsp;&nbsp;&nbsp;ExitOpenAL();<br/>}<br/>这个函数将修改STL表。我们不得不删除每个源并且清除表上的内容。<br/>ALubyte&nbsp;c&nbsp;=&nbsp;'&nbsp;';</p><p>&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(c&nbsp;!=&nbsp;'q')<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;=&nbsp;getche();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(c)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'w':&nbsp;AddSource(WATERDROP);&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'t':&nbsp;AddSource(THUNDER);&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'s':&nbsp;AddSource(STREAM);&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'r':&nbsp;AddSource(RAIN);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'o':&nbsp;AddSource(OCEAN);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'c':&nbsp;AddSource(CHIMES);&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>这是程序的主函数,他等待键盘输入,建立源,播放声音。<br/>The&nbsp;program&nbsp;can&nbsp;be&nbsp;expanded&nbsp;for&nbsp;using&nbsp;more&nbsp;wav&nbsp;files,&nbsp;and&nbsp;have&nbsp;the&nbsp;added&nbsp;feature&nbsp;of&nbsp;placing<br/>&nbsp;the&nbsp;sources&nbsp;around&nbsp;the&nbsp;scene&nbsp;in&nbsp;arbitrary&nbsp;positions.&nbsp;You&nbsp;could&nbsp;even&nbsp;allow&nbsp;for&nbsp;sources&nbsp;to&nbsp;<br/>&nbsp;play&nbsp;with&nbsp;a&nbsp;given&nbsp;frequency&nbsp;rather&nbsp;than&nbsp;have&nbsp;them&nbsp;loop.&nbsp;However&nbsp;this&nbsp;would&nbsp;require&nbsp;GUI&nbsp;routines<br/>&nbsp;&nbsp;that&nbsp;go&nbsp;beyond&nbsp;the&nbsp;scope&nbsp;of&nbsp;the&nbsp;tutorial.&nbsp;A&nbsp;full&nbsp;featured&nbsp;"Weathering&nbsp;Engine"&nbsp;would&nbsp;be&nbsp;a&nbsp;nifty&nbsp;<br/>&nbsp;&nbsp;program&nbsp;to&nbsp;make&nbsp;though.&nbsp;;)&nbsp;<br/>&nbsp;&nbsp;如果大家有什么问题,请告诉我e-mail:ouyunfei12@mail.china.com.</p>

前腐后继 发表于 2006-12-13 11:26:00

Openal教程(六)<br/>高级导入和错误处理<br/>虽然现在,我们能做出一些漂亮的东西,但是这些都没有要求我们精确<br/>的处理他们。原因是我们写的代码是为了便于学习。因此,我们将移进<br/>一些高级的东西。最重要的是我们将学习更高级的处理错误的方法。我们<br/>也将重新改写载入声音数据的方法。<br/>我们首先考虑这些函数将做什么。<br/>string&nbsp;GetALErrorString(ALenum&nbsp;err);<br/>/*<br/>&nbsp;*&nbsp;1)&nbsp;识别错误代码<br/>&nbsp;*&nbsp;2)返回错误<br/>&nbsp;*/ <p></p><p><br/>ALuint&nbsp;LoadALBuffer(string&nbsp;path);<br/>/*<br/>&nbsp;*&nbsp;1)&nbsp;建立缓冲区<br/>&nbsp;*&nbsp;2)&nbsp;导入WAV文件<br/>&nbsp;*&nbsp;3)&nbsp;返回缓冲区ID<br/>&nbsp;*/</p><p>ALuint&nbsp;GetLoadedALBuffer(string&nbsp;path);<br/>/*<br/>&nbsp;*&nbsp;1)&nbsp;检测文件是否载入<br/>&nbsp;*&nbsp;2)&nbsp;如果载入,返回缓冲区ID<br/>&nbsp;*&nbsp;3)&nbsp;如果失败,重新载入并返回缓冲区ID&nbsp;<br/>&nbsp;*/</p><p>ALuint&nbsp;LoadALSample(string&nbsp;path,&nbsp;bool&nbsp;loop);<br/>/*<br/>&nbsp;*&nbsp;1)&nbsp;建立源<br/>&nbsp;*&nbsp;2)&nbsp;调用‘GtLoadedALBuffer'&nbsp;中的’PATH‘加载文件?<br/>&nbsp;*&nbsp;3)返回源ID<br/>&nbsp;*/</p><p>void&nbsp;KillALLoadedData();<br/>/*<br/>&nbsp;*&nbsp;1)释放数据?<br/>&nbsp;*/</p><p>bool&nbsp;LoadALData();<br/>/*<br/>&nbsp;*&nbsp;1)&nbsp;载入所有的源和缓冲区<br/>&nbsp;*/</p><p>void&nbsp;KillALData();<br/>/*<br/>&nbsp;*&nbsp;1)&nbsp;释放所有的缓冲区<br/>&nbsp;*&nbsp;2)&nbsp;释放所有的源<br/>&nbsp;*/</p><p>vector&lt;string&gt;&nbsp;LoadedFiles;&nbsp;//&nbsp;文件路径<br/>vector&lt;ALuint&gt;&nbsp;Buffers;&nbsp;//&nbsp;缓冲区.<br/>vector&lt;ALuint&gt;&nbsp;Sources;&nbsp;//&nbsp;源.</p><p>看一下这个函数,想一下他做什么。我们试着建立一个关于缓冲区和源<br/>的系统。我们能调用来自文件的源并且系统能处理缓冲区的建立,因此,<br/>我们不用复制缓冲区。系统将处理缓冲区并且将有效的处理资源。</p><p>string&nbsp;GetALErrorString(ALenum&nbsp;err)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;switch(err)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;AL_NO_ERROR:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("AL_NO_ERROR");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;AL_INVALID_NAME:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("AL_INVALID_NAME");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;AL_INVALID_ENUM:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("AL_INVALID_ENUM");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;AL_INVALID_value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("AL_INVALID_value");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;AL_INVALID_OPERATION:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("AL_INVALID_OPERATION");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;AL_OUT_OF_MEMORY:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("AL_OUT_OF_MEMORY");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;};<br/>}<br/>函数的功能是转换错误代码为字符。OPENAL&nbsp;SDK说返回'AL_OUT_OF_MEMORY'&nbsp;<br/>是错误的,我们应认真对待所有错误,使我们的代码用最新的版本处理<br/>数据。<br/>string&nbsp;GetALCErrorString(ALenum&nbsp;err)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;switch(err)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;ALC_NO_ERROR:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("AL_NO_ERROR");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;ALC_INVALID_DEVICE:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("ALC_INVALID_DEVICE");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;ALC_INVALID_CONTEXT:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("ALC_INVALID_CONTEXT");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;ALC_INVALID_ENUM:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("ALC_INVALID_ENUM");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;ALC_INVALID_value:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("ALC_INVALID_value");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;ALC_OUT_OF_MEMORY:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("ALC_OUT_OF_MEMORY");<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;};<br/>}<br/>这个函数的功能是说明ALC错误。OPENAL和ALC共享ID,但是他们在一些功能上<br/>不相等。<br/>函数&nbsp;'alGetError'应注意:OPENAL&nbsp;SDK定义一次只能得到一个错误。<br/>当函数被调用时,他返回他得到的第一个错误,并且清错误为'AL_NO_ERROR'<br/>ALuint&nbsp;LoadALBuffer(string&nbsp;path)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Variables&nbsp;to&nbsp;store&nbsp;data&nbsp;which&nbsp;defines&nbsp;the&nbsp;buffer.<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALenum&nbsp;format;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;size;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALvoid*&nbsp;data;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALsizei&nbsp;freq;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALboolean&nbsp;loop;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;缓冲区ID和错误检测变量<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALuint&nbsp;buffer;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALenum&nbsp;result;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;产生缓冲区,看他是否成功建立.<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGenBuffers(1,&nbsp;&amp;buffer);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((result&nbsp;=&nbsp;alGetError())&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;GetALErrorString(result);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;读WAV数据,检测是否成功。<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutLoadWAVFile(szFilePath,&nbsp;&amp;format,&nbsp;&amp;data,&nbsp;&amp;size,&nbsp;&amp;freq,&nbsp;&amp;loop);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((result&nbsp;=&nbsp;alGetError())&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;GetALErrorString(result);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;装载WAV数据,检测是否成功<br/>&nbsp;&nbsp;&nbsp;&nbsp;alBufferData(buffer,&nbsp;format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((result&nbsp;=&nbsp;alGetError())&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;GetALErrorString(result);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;出去临时数据<br/>&nbsp;&nbsp;&nbsp;&nbsp;alutUnloadWAV(format,&nbsp;data,&nbsp;size,&nbsp;freq);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((result&nbsp;=&nbsp;alGetError())&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;GetALErrorString(result);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//返回缓冲区ID<br/>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;buffer;<br/>}</p><p>在导入数据时,我们做了错误检测。没有任何错误将通过。当数据导入时,<br/>没有足够的内存,WAV文件可能不退出,或者OPENAL函数中的错误数据<br/>将产生错误。<br/>ALuint&nbsp;GetLoadedALBuffer(string&nbsp;path)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;count&nbsp;=&nbsp;0;&nbsp;//&nbsp;'count'&nbsp;表明缓冲区列表</p><p>&nbsp;&nbsp;&nbsp;&nbsp;ALuint&nbsp;buffer;&nbsp;//&nbsp;用于导入缓冲区的缓冲区ID</p><p><br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;重复列表中的每个文件<br/>&nbsp;&nbsp;&nbsp;&nbsp;for(vector&lt;string&gt;::iterator&nbsp;iter&nbsp;=&nbsp;LoadedFiles.begin();&nbsp;iter&nbsp;!=&nbsp;LoadedFiles.end();&nbsp;++iter,&nbsp;count++)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果文件已经导入,返回他的缓冲区ID.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(*iter&nbsp;==&nbsp;path)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Buffers;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果文件是新的,我们将为他建立缓冲区.<br/>&nbsp;&nbsp;&nbsp;&nbsp;buffer&nbsp;=&nbsp;LoadALBuffer(path);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;添加缓冲区到列表,记录他已添加.<br/>&nbsp;&nbsp;&nbsp;&nbsp;Buffers.push_back(buffer);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;LoadedFiles.push_back(path);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;buffer;<br/>}<br/>人们的麻烦通常在这里,但他确实不是很复杂。我们通过包含文件路径的列表<br/>来检索。如果其中一个符合要求,我们直接返回他的ID到缓冲区。我们通过<br/>这个函数导入我们的文件,这样就避免了复制时的浪费。每个文件应该保证<br/>在自己的列表中。'Buffers'表类士于'LoadedFiles'表。<br/>ALuint&nbsp;LoadALSample(string&nbsp;path,&nbsp;bool&nbsp;loop)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALuint&nbsp;source;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALuint&nbsp;buffer;<br/>&nbsp;&nbsp;&nbsp;&nbsp;ALenum&nbsp;result;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;得到文件缓冲区ID&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;buffer&nbsp;=&nbsp;GetLoadedALBuffer(path);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;产生源.<br/>&nbsp;&nbsp;&nbsp;&nbsp;alGenSources(1&nbsp;&amp;source);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((result&nbsp;=&nbsp;alGetError())&nbsp;!=&nbsp;AL_NO_ERROR)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;GetALErrorString(result);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设置源属性.<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(source,&nbsp;AL_BUFFER,&nbsp;&nbsp;&nbsp;buffer&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(source,&nbsp;AL_PITCH,&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcef&nbsp;(source,&nbsp;AL_GAIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(source,&nbsp;AL_POSITION,&nbsp;SourcePos);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcefv(source,&nbsp;AL_VELOCITY,&nbsp;SourceVel);<br/>&nbsp;&nbsp;&nbsp;&nbsp;alSourcei&nbsp;(source,&nbsp;AL_LOOPING,&nbsp;&nbsp;loop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保存源ID.<br/>&nbsp;&nbsp;&nbsp;&nbsp;Sources.push_back(source);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;返回源ID.<br/>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;source;<br/>}<br/>&nbsp;<br/>现在我们已经建立处理缓冲区的系统,我们需要得到源的伸展。在这里,我们<br/>得到了导入文件的缓冲区ID。这个缓冲区是一个新源,我们保存他并返回。<br/>void&nbsp;KillALLoadedData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;LoadedFiles.clear();<br/>}<br/>'gLoadedFilesv'存储在导入缓冲区的WAV文件的路径下,我们要处理他。<br/>//&nbsp;源ID's.</p><p>ALuint&nbsp;phaser1;<br/>ALuint&nbsp;phaser2;</p><p>void&nbsp;LoadALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;你的应用在这里,不用担心缓冲区。&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;phaser1&nbsp;=&nbsp;LoadALSample("wavdata/phaser.wav",&nbsp;false);<br/>&nbsp;&nbsp;&nbsp;&nbsp;phaser2&nbsp;=&nbsp;LoadALSample("wavdata/phaser.wav",&nbsp;true);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;KillLoadedALData();<br/>}<br/>他表示用于程序的所有的WAV应用的程序。我们能调用导入相同的WAV文件到不同的源,<br/>'phaser.wav'&nbsp;的缓冲区建立了一次,'gPhaser1'&nbsp;and&nbsp;'gPhaser2'&nbsp;用于背景<br/>音乐的缓冲区。不用处理缓冲区因为系统会自动处理。<br/>void&nbsp;KillALData()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;释放所有的缓冲区数据.<br/>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(vector&lt;ALuint&gt;::iterator&nbsp;iter&nbsp;=&nbsp;Buffers.begin();&nbsp;iter&nbsp;!=&nbsp;Buffers.end();&nbsp;++iter)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alDeleteBuffers(1,&nbsp;iter);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;释放所有的源数据.<br/>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(vector&lt;ALuint&gt;::iterator&nbsp;iter&nbsp;=&nbsp;Sources.begin();&nbsp;iter&nbsp;!=&nbsp;Sources.end();&nbsp;++iter)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alDeleteBuffers(1,&nbsp;iter);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;清除列表.<br/>&nbsp;&nbsp;&nbsp;&nbsp;Buffers.clear();<br/>&nbsp;&nbsp;&nbsp;&nbsp;Sources.clear();<br/>}<br/>&nbsp;我们已完成了前述的工作。然后就是释放他们。<br/>&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InitOpenAL();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoadALData();<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;catch(string&nbsp;err)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;"OpenAL&nbsp;error:&nbsp;"&nbsp;&lt;&lt;&nbsp;err.c_str()&nbsp;&lt;&lt;&nbsp;endl;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>如果导入源时出错,我们将改正他。这将借助程序返回的报告。<br/>That's&nbsp;it.&nbsp;A&nbsp;more&nbsp;advanced&nbsp;way&nbsp;of&nbsp;reporting&nbsp;errors,&nbsp;and&nbsp;a&nbsp;more&nbsp;robust&nbsp;way&nbsp;of&nbsp;loading&nbsp;your&nbsp;wav&nbsp;files.&nbsp;We&nbsp;may&nbsp;find&nbsp;we&nbsp;need&nbsp;to&nbsp;do&nbsp;some&nbsp;modifications&nbsp;in&nbsp;the&nbsp;future&nbsp;to&nbsp;allow&nbsp;for&nbsp;more&nbsp;flexibility,&nbsp;but&nbsp;for&nbsp;now&nbsp;we&nbsp;will&nbsp;be&nbsp;using&nbsp;this&nbsp;source&nbsp;for&nbsp;basic&nbsp;file&nbsp;loading&nbsp;in&nbsp;future&nbsp;tutorials.&nbsp;Expect&nbsp;future&nbsp;tutorials&nbsp;to&nbsp;expand&nbsp;on&nbsp;this&nbsp;code.</p><p>See&nbsp;the&nbsp;Java&nbsp;Bindings&nbsp;for&nbsp;OpenAL&nbsp;page&nbsp;for&nbsp;the&nbsp;Java&nbsp;version&nbsp;of&nbsp;this&nbsp;tutorial&nbsp;(adapted&nbsp;by:&nbsp;Athomas&nbsp;Goldberg)<br/>&nbsp;如果大家有什么问题,请告诉我e-mail:ouyunfei12@mail.china.com.<br/></p>

劝劝 发表于 2007-1-5 12:14:00

thank you to suply

hellowing 发表于 2007-1-5 23:27:00

<p>个人慣用DirectSound和DirectMusic的,學OpenAL也不錯,最起碼是Cross Platform的說,收下慢慢硏究硏究,頂一个.</p>
页: [1]
查看完整版本: openal教程