原文地址:http://blog.csdn.net/woker/article/details/8687380
一簡介
OpenAL抽象出三種基本對象:buffers(緩沖區)、sources(源)、listener(聽者)。Buffer用來填充聲音數據,然后附加到一個Source上,Source可以被定位並播放。聲音播放的效果取決於source相對於listener的位置和方向。通過創建數個sources、buffers和一個唯一的listener,並動態更新sources的位置和方向,就可以產生逼真的3D音效。
OpenAL基本對象及其與context和device之間的關系:
初始化OpenAL時必須打開至少一個device。這個device中,至少要創建1個context。context中含有一個listener,並可創建若干個source。每個source可以附加若干個buffer。Buffer是共享的,不屬於某個context。
1. 設備枚舉
alcOpenDevice()傳入一個字符串參數,打開對應的device。字符串應該是一個有效的OpenALrendering device的名字,或者NULL用以請求默認device。PC系統中可能存在多個OpenALrendering device,所以OpenAL的應用程序需要有區分不同設備的能力,可以使用OpenAL的Enumerationextension(枚舉擴展包)。Enumerationextension允許開發者獲得一個字符串,是一個包含了可用設備的列表【alcGetString(NULL,ALC_DEVICE_SPECIFIER)】,也可以獲得默認設備的名字【alcGetString(NULL,ALC_DEFAULT_DEVICE_SPECIFIER)】。對於錄音設備,相應的參數為ALC_CAPTURE_DEVICE_SPECIFIER和ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER。
用戶可以通過alcIsExtensionPresent和alIsExtensionPresent來獲取每個device支持的extensions。
2. 初始化/退出
初始化OpenAL的第一步是打開一個device,再為這個device創建一個context。然后就可以操控基本對象了。buffer操作的各種函數及步驟:
創建buffers:(1)alGetError重置錯誤狀態;(2) alGenBuffers 創建多個buffer;(3) alGetError檢測是否有錯誤發生。
填充buffer:alBufferData
創建sources:(1)alGetError重置錯誤狀態;(2) alGenSources 創建多個source;(3) alGetError檢測是否有錯誤發生。
附加buffers到sources:alSourcei
source播放buffer:alSourcePlay
動態更新source和listener屬性:alGetListenerfv,alListener3f, alSourcei, alGetSource3f
示例:
- // Initialization
- Device = alcOpenDevice(NULL); // select the "preferred device"
- if (Device) {
- Context=alcCreateContext(Device,NULL);
- alcMakeContextCurrent(Context);
- }
- // Check for EAX 2.0 support
- g_bEAX = alIsExtensionPresent("EAX2.0");
- // Generate Buffers
- alGetError(); // clear error code
- alGenBuffers(NUM_BUFFERS, g_Buffers);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alGenBuffers :", error);
- return;
- }
- // Load test.wav
- loadWAVFile("test.wav",&format,&data,&size,&freq,&loop);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alutLoadWAVFile test.wav : ", error);
- alDeleteBuffers(NUM_BUFFERS, g_Buffers);
- return;
- }
- // Copy test.wav data into AL Buffer 0
- alBufferData(g_Buffers[0],format,data,size,freq);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alBufferData buffer 0 : ", error);
- alDeleteBuffers(NUM_BUFFERS, g_Buffers);
- return;
- }
- // Unload test.wav
- unloadWAV(format,data,size,freq);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alutUnloadWAV : ", error);
- alDeleteBuffers(NUM_BUFFERS, g_Buffers);
- return;
- }
- // Generate Sources
- alGenSources(1,source);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alGenSources 1 : ", error);
- return;
- }
- // Attach buffer 0 to source
- alSourcei(source[0], AL_BUFFER, g_Buffers[0]);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alSourcei AL_BUFFER 0 : ", error);
- }
- // Exit
- Context=alcGetCurrentContext();
- Device=alcGetContextsDevice(Context);
- alcMakeContextCurrent(NULL);
- alcDestroyContext(Context);
- alcCloseDevice(Device);
3. listener屬性
每個context含有一個listener,函數集alListener[f,3f, fv, i]和alGetListener[f,3f, fv, i](——注:A[B,C,D]表示AB,AC, AD)可以用來設置或獲取以下listener屬性:
屬性 |
數據類型 |
描述 |
AL_GAIN |
f, fv |
主增益,應為正數 |
AL_POSITION |
fv, 3f, iv, 3i |
X,Y,Z位置 |
AL_VELOCITY |
fv, 3f, iv, 3i |
速度向量 |
AL_ORIENTATION |
fv, iv |
由"at"和"up"向量描述的方向 |
示例:
- ALfloat listenerPos[]={0.0,0.0,0.0};
- ALfloat listenerVel[]={0.0,0.0,0.0};
- ALfloat listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
- // Position ...
- alListenerfv(AL_POSITION,listenerPos);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alListenerfv POSITION : ", error);
- return;
- }
- // Velocity ...
- alListenerfv(AL_VELOCITY,listenerVel);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alListenerfv VELOCITY : ", error);
- return;
- }
- // Orientation ...
- alListenerfv(AL_ORIENTATION,listenerOri);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alListenerfv ORIENTATION : ", error);
- return;
- }
4. buffer屬性
每個由alGenBuffers創建的buffer都有屬性,函數集alGetBuffer[f,i]可用來獲取下述屬性:
屬性 |
數據類型 |
描述 |
AL_FREQUENCY |
i, iv |
頻率(Hz) |
AL_BITS |
i, iv |
位寬 |
AL_CHANNELS |
i, iv |
channel數,可以大於1,但播放時不能定位 |
AL_SIZE |
i, iv |
總大小(Byte) |
AL_DATA |
i,iv |
數據拷貝的初始位置,一般沒有用 |
示例:
- // Retrieve Buffer Frequency
- alBufferi(g_Buffers[0], AL_FREQUENCY, iFreq);
5. source屬性
每個由alGenSources創建的source都有可配置的屬性,函數集alSource[f,3f, fv, i]和alGetSource[f,3f, fv, i]可以用來配置或獲取以下source屬性:
屬性 |
數據類型 |
描述 |
AL_PITCH |
f, fv |
source的buffer的頻率(采樣率)倍增器(pitchmultiplier),總是正數 |
AL_GAIN |
f, fv |
source增益,應為正數 |
AL_MAX_DISTANCE |
f, fv, i, iv |
用於反鉗位距離模型(InverseClamped Distance Model),大於次距離,source不再衰減 |
AL_ROLLOFF_FACTOR |
f, fv, i, iv |
source的衰減率,默認為1.0 |
AL_REFERENCE_DISTANCE |
f, fv, i, iv |
小於此距離時,source的音量減半(在衰減率和AL_MAX_DISTANCE作用之前) |
AL_MIN_GAIN |
f, fv |
source的最小增益 |
AL_MAX_GAIN |
f, fv |
source的最大增益 |
AL_CONE_OUTER_GAIN |
f, fv |
外錐(outercone)外的增益 |
AL_CONE_INNER_ANGLE |
f, fv, i, iv |
內錐覆蓋的角度,在此之中,source不會衰減 |
AL_CONE_OUTER_ANGLE |
f, fv, i, iv |
外錐覆蓋的角度,在此之外,source完全衰減。內錐和外錐之間平滑衰減 |
AL_POSITION |
fv, 3f |
X,Y,Z位置 |
AL_VELOCITY |
fv, 3f |
速度矢量 |
AL_DIRECTION |
fv, 3f, iv, 3i |
方向矢量 |
AL_SOURCE_RELATIVE |
i, iv |
指示position是否是相對於listener |
AL_SOURCE_TYPE |
i, iv |
source類型,AL_UNDETERMINED,AL_STATIC, AL_STREAMING |
AL_LOOPING |
i, iv |
設置循環播放,AL_TURE,AL_FALSE |
AL_BUFFER |
i, iv |
附加的buffer的ID |
AL_SOURCE_STATE |
i, iv |
source的狀態,AL_STOPPED,AL_PLAYING, ... |
AL_BUFFERS_QUEUED |
i, iv |
【只讀】用alSourceQueueBuffers入隊列的buffer個數,出隊用alSourceUnqueueBuffers |
AL_BUFFERS_PROCESSED |
i, iv |
【只讀】隊列中已經被處理的buffer數 |
AL_SEC_OFFSET |
f, fv, i, iv |
播放的位置,秒 |
AL_SAMPLE_OFFSET |
f, fv, i, iv |
播放的位置,Sample數 |
AL_BYTE_OFFSET |
f, fv, i, iv |
播放的位置,字節數 |
示例:
- alGetError(); // clear error state
- alSourcef(source[0],AL_PITCH,1.0f);
- if ((error = alGetError()) != AL_NO_ERROR)
- DisplayALError("alSourcef 0 AL_PITCH : \n", error);
- alGetError(); // clear error state
- alSourcef(source[0],AL_GAIN,1.0f);
- if ((error = alGetError()) != AL_NO_ERROR)
- DisplayALError("alSourcef 0 AL_GAIN : \n", error);
- alGetError(); // clear error state
- alSourcefv(source[0],AL_POSITION,source0Pos);
- if ((error = alGetError()) != AL_NO_ERROR)
- DisplayALError("alSourcefv 0 AL_POSITION : \n", error);
- alGetError(); // clear error state
- alSourcefv(source[0],AL_VELOCITY,source0Vel);
- if ((error = alGetError()) != AL_NO_ERROR)
- DisplayALError("alSourcefv 0 AL_VELOCITY : \n", error);
- alGetError(); // clear error state
- alSourcei(source[0],AL_LOOPING,AL_FALSE);
- if ((error = alGetError()) != AL_NO_ERROR)
- DisplayALError("alSourcei 0 AL_LOOPING true: \n", error);
6. buffer隊列(bufferqueuing)
buffer隊列用以保證聲音的連續播放。使用buffer隊列時,buffer和source都是普通方法創建,但是附加buffer到source時使用alSourceQueueBuffers和alSourceUnqueueBuffers來替代alSourcei。alSourceQueueBuffers可以附加一個或一組buffer到一個source上,然后調用alSourcePlay來播放。播放source時,可以調用alSourceUnqueueBuffers來移除已經播放了的buffer。這些buffer可以重填新的數據或者丟棄。新的或重填的buffer可以通過alSourceQueueBuffers附加到原來正在播放的source上。只要buffer隊列中一直有新的buffer用以播放,source就不會停。
1)用於流(streaming)的source不應該用alSourcei來附加其第一個buffer,始終用alSourceQueueeBuffers。任何source都可以用alSourcei(...,AL_BUFFER,0)來卸載其全部buffer,這些buffer可以接着用作流buffer或非流buffer,取決於附加到source的方式(alSourcei或alSourceQueueBuffers)。
2)所有通過alSourceQueueBuffers附加到某個source的buffer,都應該有相同的聲音格式。
7. 多普勒偏移(DopplerShift)
多普勒效應取決於source和listener相對於介質的速度,以及介質中聲音的傳播速度。應用程序可能希望強化或弱化多普勒效應,因為精確計算可能達不到期望的聲音效果。頻率偏移(音調改變)的量正比於listener和source接近或遠離的速度。OpenAL中多普勒效應的實現是通過下述公式,忽略介質(空氣、水等)移動的效應。
SS: AL_SPEED_OF_SOUND = 聲音傳播速度,默認值343.3 DF: AL_DOPPLER_FACTOR = 多普勒系數,默認為1.0 vls: listener速度標量(在source-listener直線上投影值,向內為正) vss: source速度標量(在source-listener直線上投影值,向內為正) f: 采樣頻率 F : 多普勒頻率偏移量 Mag(vec) = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) DotProduct(v1, v2) = (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z) SL = source指向listener的向量 SV = source速度向量 LV = listener速度向量 vls = DotProduct( SL, LV ) / Mag(SL) vss = DotProduct( SL, SV ) / Mag(SL) 多普勒計算: vss = min( vss, SS/DF ) vls = min (vls, SS/DF ) F = f * ( SS - DF * vls ) / ( SS - DF * vss )
有兩個API用以控制聲音傳播速度和多普勒系數。AL_DOPPLER_FACTOR是source和listener速度的一個系數,用以放大或減小多普勒偏移量。
void alDopplerFacor ( ALfloat dopplerFactor );
負數會導致AL_INVALID_VALUE錯誤,命令失效。默認值為1。通過alGetFloat{v}和AL_DOPPLER_FACTOR可以獲取當前配置。
AL_SPEED_OF_SOUND允許應用程序改變傳播速度,source、listener以及聲音傳播的速度三者應該使用相同的速度單位。
void alSpeedOfSound ( Alfloat speed );
負數會導致AL_INVALID_VALUE錯誤,命令失效。默認值為343.3(聲音在空氣中的傳播速度)。通過alGetFloat{v}和AL_SPEED_OF_SOUND獲取當前值。距離與速度的單位完全獨立,可以使用不同的單位。如果不想有多普勒效應,可以將所有速度設置成0。
8. 錯誤處理
alGetError可在任何時刻獲取OpenAL的錯誤狀態,同時清除錯誤狀態,所以通常在重要操作前后都調用。錯誤碼如下:
錯誤碼 |
描述 |
AL_NO_ERROR |
沒有錯誤 |
AL_INVALID_NAME |
傳入錯誤的名字(ID) |
AL_INVALID_ENUM |
傳入無效的枚舉值 |
AL_INVALID_VALUE |
傳入無效的值 |
AL_INVALID_OPERATION |
無效的請求 |
AL_OUT_OF_MEMORY |
請求操作導致OpenAL內存溢出 |
示例:
- alGetError(); // Clear Error Code
- // Generate Buffers
- alGenBuffers(NUM_BUFFERS, g_Buffers);
- if ((error = alGetError()) != AL_NO_ERROR)
- {
- DisplayALError("alGenBuffers :", error);
- exit(-1);
- }
9. 擴展包(Extensions)
OpenAL的extension機制可以讓開發商增加新特性的API。創新科技(CreativeLabs)已經增加了多個extension,包括EAX,X-RAM, Multi-Channel Buffer playback,EffectExtension(EFX)。應用程序可以根據extension的種類調用alIsExtensionPresent或者alcIsExtensionPresent來判斷某個extension是否有效。