大家好,欢迎来到IT知识分享网。
OpenAL简介
OpenAL(Open Audio Library)是专门负责3D定位音效方面的API,可用来开放地、跨平台地访问声音硬件。与那些今日在游戏中得到普遍应用的较大的面向对象的库相比,OpenAL是一个简单明了的替代方案。OpenAL一直在不断的创新,几乎没有一个API能达到她的全部潜能。一个很大的原因是因为hardware加速建立在特殊的版卡上。然而,Creative Labs是OpenAL的主要支持者,同时也是最大声卡厂商之一。OpenAL的另一个主要支持者是LOKI。
1、OpenAL入门
OpenAL从本质上讲是一个音频场景图库(audio scene graph library)。它描述对象之间的一系列关系。大部分的对象体现了离散的概念。其中重要概念有:
- 设备(device)
- 渲染上下文环境的描述表(context)
- 听众(listener)
- 音源(source)
大部分的OpenAL条目都和这些类型的创建、销毁或者属性改变有关。
一般而言,对象之间有如下关系:
对象初始化以及名字绑定的语法是alGen{Object}。相应地,销毁对象时调用alDelete{Object}。例如,分别调用函数alGenSource()和alDeleteSource()来创建和销毁音源对象。创建context和device的函数一此不同,稍后会详细讨论。
音源是和context相关的。在一个context内有效的音源名字在其他的context中无效。缓冲器是和context无关的,创建缓冲器无需引用任何当前活动的context。
缓冲器能够同时在多个context中与多个音源关联。
//打开设备,创建设备 ALCdevice *dev = alcOpenDevice(NULL); ALCcontextCurrent *cc = alcCreateContext(dev, NULL); alcMakeContextCurrent(cc); //创建音源和缓冲器 ALuint bid, sid; alGenSources(1, &sid); alGenBuffers(1, &bid); //取得pcm数据,用缓冲区来关联它 ALvoid *data; ALsizei size, bits, freq; ALenum format; ALboolean loop; alutLoadWAVFile("boom.wav", &format, &data, &size, &freq, &loop); alBufferData(bid, format, data, size, freq); //用音源关联缓冲器 alSourcei(sid, AL_BUFFER, bid); //播放音源然后等待直到完成 //然后释放它 alSourcePlay(sid); ALint state; do{ alGetSourcei(sid, AL_SOURCE_STATE, &state); }while(state == AL_PLAYING); alDeleteSources(1, &sid); alDeleteBuffers(1, &bid); alcMakeContextCurrent(NULL); alcDestroyContext(cc); alcCloseDevice(dev);
如前例所示的那样,OpenAL在语法、编码风格和习惯上都有模仿OpenGL。做出这个决定是为了在一定程度上迎合那些已经熟悉OpenGL的开发人员,也是为了仿效OpenAL ARB所代表的切合实际的设计原则。
2、进阶
ALfloat l_pos[] = {
0,0,5}; ALfloat s_pos[] = {
0,0,5}, s_vel[] = {
0,0,1}; ALfloat zeros[] = {
0,0,0}; alListenerfv(AL_POSITION, l_pos); alListenerfv(AL_VELOCITY, zeros); alSourcefv(sid, AL_POSITION, s_pos); alSourcefv(sid, AL_VELOCITY, s_vel); alSourcePlay(sid); ALint state; do{ s_vel[2] += 0.001; s_pos[2] += 0.001; alSourcefv(sid, AL_VELOCITY, s_vel); alSourcefv(sid, AL_POSITION, s_pos); alGetSourcei(sid, AL_SOURCE_STATE, &state); }while(state != AL_PLAYING);
//使用排队机制来关联到缓冲器第一个集 alSourceQueueBuffers(sid, NUMBUFFERS, Buffers); alSourcePlay(sid); ALuint count = 0; ALuint buffers_returned = 0; ALint processed = 0; ALboolean bFinished = AL_FALSE; ALuint buffers_in_queue = NUMBUFFERS; while(!bFinished) { //取得状态 alGetSourceiv(sid, AL_BUFFER_PROCESSED, &processed); //假如播放完毕了一些缓冲器,然后让它们退出队列 //然后装载新的音频,再把它们装入队列 if(processed>0) { buffers_returned += processed; while(processed) { ALuint bid; alSourceUnqueueBuffers(sid, 1, &bid); if(!bFinished) { DataToRead = (DataSize>BSIZE) ? BSIZE : DataSize; if(DataToRead == DataSize) bFinish = AL_TRUE; //....... //省略从音源读出DataToRead字节的代码 DataSize -= DataToRead; if(bFinish == AL_TRUE) memset(data + DataToRead, 0, BSIZE - DataToRead); alBufferData(bid, format, data, DataToRead, wave.SamplesPerSec); //对缓冲器排队 alSourceQueueBuffers(sid, 1, &bid); processed--; } else { processed--; if(buffers_in_queue-- == 0) { bFinished = AL_TRUE; break; }//if }//else }//while }// if process }
3、空间定位
4、扩展与alut库
#include <conio.h> #include <time.h> #include <stdlib.h> #include <al/al.h> #include <al/alc.h> #include <al/alu.h> #include <al/alut.c> // 我们需要的最大的数据缓冲. #define NUM_BUFFERS 3 // 我们需要放三种声音. #define NUM_SOURCES 3 // 缓冲和源标志. #define BATTLE 0 #define GUN1 1 #define GUN2 2 // 存储声音数据. ALuint Buffers[NUM_BUFFERS]; // 用于播放声音. ALuint Sources[NUM_SOURCES]; // 源声音的位置. 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 }; 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[i], 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[i][0] = -float(cos(theta)); SourcePos[i][1] = -float(rand()%2); SourcePos[i][2] = -float(sin(theta)); alSourcefv(Sources[i], AL_POSITION, SourcePos[i] ); alSourcePlay(Sourcev[i]); }//if }//for }//while return 0; }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/139437.html