📄 openal教程.txt
字号:
// 源声音的位置.
ALfloat SourcesPos[NUM_SOURCES][3];
// 源声音的速度.
ALfloat SourcesVel[NUM_SOURCES][3];
// 听者的位置.
ALfloat ListenerPos[] = { 0.0, 0.0, 0.0 };
// 听者的速度.
ALfloat ListenerVel[] = { 0.0, 0.0, 0.0 };
// 听者的方向 (first 3 elements are "at", second 3 are "up")
ALfloat ListenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
在这一章中,唯一的不同是多了3种将导入Openal系统的不同的声音效果 。
ALboolean LoadALData()
{
// 载入变量.
ALenum format;
ALsizei size;
ALvoid* data;
ALsizei freq;
ALboolean loop;
// 载入WAV数据.
alGenBuffers(NUM_BUFFERS, Buffers);
if (alGetError() != AL_NO_ERROR)
return AL_FALSE;
alutLoadWAVFile("wavdata/Battle.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[BATTLE], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
alutLoadWAVFile("wavdata/Gun1.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[GUN1], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
alutLoadWAVFile("wavdata/Gun2.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[GUN2], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
// 捆绑源.
alGenSources(NUM_SOURCES, Sources);
if (alGetError() != AL_NO_ERROR)
return AL_FALSE;
alSourcei (Sources[BATTLE], AL_BUFFER, Buffers[BATTLE] );
alSourcef (Sources[BATTLE], AL_PITCH, 1.0 );
alSourcef (Sources[BATTLE], AL_GAIN, 1.0 );
alSourcefv(Sources[BATTLE], AL_POSITION, SourcePos[BATTLE]);
alSourcefv(Sources[BATTLE], AL_VELOCITY, SourceVel[BATTLE]);
alSourcei (Sources[BATTLE], AL_LOOPING, AL_TRUE );
alSourcei (Sources[GUN1], AL_BUFFER, Buffers[GUN1] );
alSourcef (Sources[GUN1], AL_PITCH, 1.0 );
alSourcef (Sources[GUN1], AL_GAIN, 1.0 );
alSourcefv(Sources[GUN1], AL_POSITION, SourcePos[GUN1]);
alSourcefv(Sources[GUN1], AL_VELOCITY, SourceVel[GUN1]);
alSourcei (Sources[GUN1], AL_LOOPING, AL_FALSE );
alSourcei (Sources[GUN2], AL_BUFFER, Buffers[GUN2] );
alSourcef (Sources[GUN2], AL_PITCH, 1.0 );
alSourcef (Sources[GUN2], AL_GAIN, 1.0 );
alSourcefv(Sources[GUN2], AL_POSITION, SourcePos[GUN2]);
alSourcefv(Sources[GUN2], AL_VELOCITY, SourceVel[GUN2]);
alSourcei (Sources[GUN2], AL_LOOPING, AL_FALSE );
// 做错误检测并返回
if( alGetError() != AL_NO_ERROR)
return AL_FALSE;
return AL_TRUE;
}
首先,我们导入文件数据到3个缓冲区,然后把3个缓冲区和3个源锁在
一起。唯一的不同是文件“battle.wav”在不停止时循环。
void SetListenervalues()
{
alListenerfv(AL_POSITION, ListenerPos);
alListenerfv(AL_VELOCITY, ListenerVel);
alListenerfv(AL_ORIENTATION, ListenerOri);
}
void KillALData()
{
alDeleteBuffers(NUM_BUFFERS, &Buffers[0]);
alDeleteSources(NUM_SOURCES, &Sources[0]);
alutExit();
}
在这段代码中,我们没有改变。
int main(int argc, char *argv[])
{
// Initialize OpenAL and clear the error bit.
alutInit(NULL, 0);
alGetError();
// Load the wav data.
if (LoadALData() == AL_FALSE)
return 0;
SetListenervalues();
// Setup an exit procedure.
atexit(KillALData);
// Begin the battle sample to play.
alSourcePlay(Sources[BATTLE]);
// Go through all the sources and check that they are playing.
// Skip the first source because it is looping anyway (will always be playing).
ALint play;
while (!kbhit())
{
for (int i = 1; i < NUM_SOURCES; i++)
{
alGetSourcei(Sources, AL_SOURCE_STATE, &play);
if (play != AL_PLAYING)
{
// Pick a random position around the listener to play the source.
double theta = (double) (rand() % 360) * 3.14 / 180.0;
SourcePos[0] = -float(cos(theta));
SourcePos[1] = -float(rand()%2);
SourcePos[2] = -float(sin(theta));
alSourcefv(Sources, AL_POSITION, SourcePos );
alSourcePlay(Sourcev);
}
}
}
return 0;
}
这段是这篇文章最有趣的地方。我们在这里将播放。如果他不播放,我们将
在3D空间中选一个点播放(点击)。
And bang! We are done. As most of you have probably seen, you don't have to do anything special to play more than one source at a time. OpenAL will handle all the mixing features to get the sounds right for their respective distances and velocities. And when it comes right down to it, isn't that the beauty of OpenAL?
You know that was a lot easier than I thought. I don't know why I waited so long to write it. Anyway, if anyone reading wants to see something specific in future tutorials (not necessarily pertaining to OpenAL, I have quite an extensive knowledge base) drop me a line at lightonthewater@hotmail.com I plan to do tutorials on sharing buffers and the Doppler effect in some later tutorial unless there is request for something else. Have fun with the code!
Openal 教程(四)
ALC
Alut一直为我们做着所有神奇的东西。例如处理音频设备。ALUT库为
我们提供这些功能,但是一些机灵的程序员想知道他是怎样工作的。
我们可以这样想,在一些点上直接用ALC。
在这一章中,我们将讲述ALC层,并看一下他是怎样处理设备的。
ALCdevice* pDevice;
ALCubyte DeviceName[] = "DirectSound3D";
pDevice = alcOpenDevice(DeviceName);
当然,ALC设备是什么?可以这样想,在共享整个系统下,OPENAL夺取了
设备的句柄。在我们用DIRECTSOUND作为音频设备时,设备能完成的很好。
程序从设备中夺取句柄并为程序准备着。
传递NULL给‘alcOpenDevice',他将使ALC用默认设备。
ALCcontext* pContext;
pContext = alcCreateContext(pDevice, NULL);
alcMakeContextCurrent(pContext);
ALC文本描述是什么? OPENGL程序员能撤消通过不同窗口的
状态管理的控制的精简文本描述。HGLRC能被挑调用建立多次,使多描述
窗口成为可能。并且不同的文本描述状态可以实现。ALC文本描述工作在
相同的原理下。首先,我们告诉他我们用的设备,然后我们做当前的文本
描述。理论上你能为不同的窗口建立多个表达文本描述,并且设置不同的
状态变量,以使他们能很好的工作。尽管“表达文本描述”用于可视表达。
你可能也注意到“alcCreateContext'中的第二个变量是NULL。OPENAL中
下面的变量与他有关。
ALC_FREQUENCY
ALC_REFRESH
ALC_SYNC
你可以调用’alcMakeContextCurrent'替换你建立的多个文本描述。同样
在'alcMakeContextCurrent'中置NULL。他将防止处理其他声音数据。要
意识到当你有多个表达文本描述时,你只能在当前用一个。并且当你的程序
要交换使用两个描述时,必须确定当前使用的描述是在当前。当你想不通过
大的检查,知道用的哪个描述,必须用这些。
ALcontext* pCurContext;
pCurContext = alcGetCurrentContext();
通过文本描述,你能获取设备。
ALdevice* pCurDevice;
pCurDevice = alcGetContextsDevice(pCurContext);
在我们用文本描述时,我们必须收回用的设备。在处理文本描述时,有
更COOL的方法。
alcSuspendContext(pContext);
// 终止pContext.
alcProcessContext(pContext);
// 重置pContext.
当程序停止时,我们必须重置声音数据到文本描述。当程序暂停时,文本
描述中的数据不会产生声音。在程序运行期间,源或缓冲区的‘lifetime'
的有效是由源或缓冲器ID的合法性决定的。
alcMakeContextCurrent(NULL);
alcDestroyContext(pContext);
alcCloseDevice(pDevice);
最后,怎样清出他呢?当前文本描述被初始化为’NULL‘,描述释放并且
设备句柄交还系统。在这里我们只讲了一些ALC的基本功能。
ALenum alcGetError(ALvoid);
ALboolean alcIsExtensionPresent(ALCdevice* device, ALubyte* extName);
ALvoid* alcGetProcAddress(ALCdevice* device, ALubyte* funcName);
ALenum alcGetEnumvalue(ALCdevice* device, ALubyte* enumName);
ALubyte* alcGetString(ALCdevice* device, ALenum token);
ALvoid alcGetIntegerv(ALCdevice* device, ALenum token, ALsizei size, ALint* dest);
这些做什么,我们肯定很清楚,首先,我们用'alcGetError' 检测错误。
下面三个功能是询问ALC的扩展。这在开始就应计划。最后alcGetInteger'
将返回ALC的版本'ALC_MAJOR_VERSION' or 'ALC_MINOR_VERSION'。
函数'alcGetString'返回下面信息:
ALC_DEFAULT_DEVICE_SPECIFIER
ALC_DEVICE_SPECIFIER
ALC_EXTENSIONS
首先是OPENAL完成的设备的信息。OPENAL 返回"DirectSound3D",
第二个返回"DirectSound" ;
最后一个返回NULL。
Well that's most of Alc for you. I hope it gave you a better understanding of how OpenAL interacts with the operation system. You might try writing your own initialization routines so you can cast off Alut altogether. Either way have fun with it.
See the Java Bindings for OpenAL page for the Java version of this tutorial - adapted by: Athomas Goldberg
如果大家有什么问题,请告诉我e-mail:ouyunfei12@mail.china.com.
Openal教程(五)
源共享缓冲区
在这一章中,我们将讲解如何在你的缓冲区中共享多个源。这是个非常
合理,自然的步筹,非常的容易。你完全可以跳过这章。但对于愿意读
这一章的朋友,你将发现他非常有趣。我们将准备好ALC层以便我们能
用第四章的知识。
让我们开始吧,在这一章中,我们将用的矢量来自标准模板库,因此,确定
你是否安装了他,最好还有一些关于他的知识。在这一章中,我不会讲
STL。
// 表明缓冲区.
#define THUNDER 0
#define WATERDROP 1
#define STREAM 2
#define RAIN 3
#define CHIMES 4
#define OCEAN 5
#define NUM_BUFFERS 6
// 存贮声音数据.
ALuint Buffers[NUM_BUFFERS];
// 播放多个声音的源的矢量表
vector<ALuint> Sources;
首先,我写出了我们用于表明缓冲区数组的一些指令。我们将用几个WAV
文件,因此我们需要几个缓冲区。我们将用一个STL矢量代替用于存贮源
的一个数组。我们能做这些是因为他让我们能有一个源的动态数。我们能
一直添加源到场景,直到OPENAL脱离他们运行。
ALboolean InitOpenAL()
{
ALCdevice* pDevice;
ALCcontext* pContext;
ALCubyte* deviceSpecifier;
ALCubyte deviceName[] = "DirectSound3D";
// 得到设备句柄
pDevice = alcOpenDevice(deviceName);
// 得到设备说明.
deviceSpecifier = alcGetString(pDevice, ALC_DEVICE_SPECIFIER);
printf("Using device '%s'.\n", szDeviceSpecifier);
// 建立声音文本描述.
pContext = alcCreateContext(pDevice, NULL);
// 设置行为文本描述.
alcMakeContextCurrent(pContext);
// 检查错误.
if (alcGetError() != ALC_NO_ERROR)
return AL_FALSE;
return AL_TRUE;
}
这是来自上一章的代码。首先,我们得到 "DirectSound3D"设备的句柄,
然后获得用于程序的表明文本描述。
这个文本描述设置当前,函数将检查在我们返回成功前,是否出错。
void ExitOpenAL()
{
ALCcontext* pCurContext;
ALCdevice* pCurDevice;
// 得到当前文本描述
pCurContext = alcGetCurrentContext();
// 得到用于当前文本描述的设备?
pCurDevice = alcGetContextsDevice(pCurContext);
// 重置当前文本描述为NULL
alcMakeContextCurrent(NULL);
//释放文本描述和设备
alcDestroyContext(pCurContext);
alcCloseDevice(pCurDevice);
}
我们用和释放的文本描述和设备将收回。另外,在OPENAL暂停程序时,设置
当前文本描述为NULL。但是这些都不可预料。如果你用了多个文本描述,
你也许需要更好的方法来做这些事。我将介绍一些比较好的方法。
ALboolean LoadALData()
{
// 导入的变量
ALenum format;
ALsizei size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -