openal 基礎知識


原文地址:http://blog.csdn.net/woker/article/details/8687380

一簡介

OpenAL抽象出三種基本對象:buffers(緩沖區)sources()listener(聽者)Buffer用來填充聲音數據,然后附加到一個Source上,Source可以被定位並播放。聲音播放的效果取決於source相對於listener的位置和方向。通過創建數個sourcesbuffers和一個唯一的listener,並動態更新sources的位置和方向,就可以產生逼真的3D音效。

OpenAL基本對象及其與contextdevice之間的關系:

初始化OpenAL時必須打開至少一個device。這個device中,至少要創建1contextcontext中含有一個listener,並可創建若干個source。每個source可以附加若干個bufferBuffer是共享的,不屬於某個context

1. 設備枚舉

alcOpenDevice()傳入一個字符串參數,打開對應的device。字符串應該是一個有效的OpenALrendering device的名字,或者NULL用以請求默認devicePC系統中可能存在多個OpenALrendering device,所以OpenAL的應用程序需要有區分不同設備的能力,可以使用OpenALEnumerationextension(枚舉擴展包)Enumerationextension允許開發者獲得一個字符串,是一個包含了可用設備的列表【alcGetString(NULL,ALC_DEVICE_SPECIFIER)】,也可以獲得默認設備的名字【alcGetString(NULL,ALC_DEFAULT_DEVICE_SPECIFIER)】。對於錄音設備,相應的參數為ALC_CAPTURE_DEVICE_SPECIFIERALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER

用戶可以通過alcIsExtensionPresentalIsExtensionPresent來獲取每個device支持的extensions

2. 初始化/退出

初始化OpenAL的第一步是打開一個device,再為這個device創建一個context。然后就可以操控基本對象了。buffer操作的各種函數及步驟:

創建buffers(1)alGetError重置錯誤狀態;(2) alGenBuffers 創建多個buffer;(3) alGetError檢測是否有錯誤發生。

填充bufferalBufferData

創建sources(1)alGetError重置錯誤狀態;(2) alGenSources 創建多個source;(3) alGetError檢測是否有錯誤發生。

附加bufferssourcesalSourcei

source播放bufferalSourcePlay

動態更新sourcelistener屬性:alGetListenerfv,alListener3f, alSourcei, alGetSource3f

示例:

 

[cpp]   view plain copy
 
  1. // Initialization  
  2. Device = alcOpenDevice(NULL); // select the "preferred device"  
  3. if (Device) {  
  4.     Context=alcCreateContext(Device,NULL);  
  5.     alcMakeContextCurrent(Context);  
  6. }  
  7.   
  8. // Check for EAX 2.0 support  
  9. g_bEAX = alIsExtensionPresent("EAX2.0");  
  10. // Generate Buffers  
  11. alGetError(); // clear error code  
  12. alGenBuffers(NUM_BUFFERS, g_Buffers);  
  13. if ((error = alGetError()) != AL_NO_ERROR)  
  14. {  
  15.     DisplayALError("alGenBuffers :", error);  
  16.     return;  
  17. }  
  18.   
  19. // Load test.wav  
  20. loadWAVFile("test.wav",&format,&data,&size,&freq,&loop);  
  21. if ((error = alGetError()) != AL_NO_ERROR)  
  22. {  
  23.     DisplayALError("alutLoadWAVFile test.wav : ", error);  
  24.     alDeleteBuffers(NUM_BUFFERS, g_Buffers);  
  25.     return;  
  26. }  
  27.   
  28. // Copy test.wav data into AL Buffer 0  
  29. alBufferData(g_Buffers[0],format,data,size,freq);  
  30. if ((error = alGetError()) != AL_NO_ERROR)  
  31. {  
  32.     DisplayALError("alBufferData buffer 0 : ", error);  
  33.     alDeleteBuffers(NUM_BUFFERS, g_Buffers);  
  34.     return;  
  35. }  
  36.   
  37. // Unload test.wav  
  38. unloadWAV(format,data,size,freq);  
  39. if ((error = alGetError()) != AL_NO_ERROR)  
  40. {  
  41.     DisplayALError("alutUnloadWAV : ", error);  
  42.     alDeleteBuffers(NUM_BUFFERS, g_Buffers);  
  43.     return;  
  44. }  
  45.   
  46. // Generate Sources  
  47. alGenSources(1,source);  
  48. if ((error = alGetError()) != AL_NO_ERROR)  
  49. {  
  50.     DisplayALError("alGenSources 1 : ", error);  
  51.     return;  
  52. }  
  53.   
  54. // Attach buffer 0 to source  
  55. alSourcei(source[0], AL_BUFFER, g_Buffers[0]);  
  56. if ((error = alGetError()) != AL_NO_ERROR)  
  57. {  
  58.     DisplayALError("alSourcei AL_BUFFER 0 : ", error);  
  59. }  
  60.   
  61. // Exit  
  62. Context=alcGetCurrentContext();  
  63. Device=alcGetContextsDevice(Context);  
  64. alcMakeContextCurrent(NULL);  
  65. alcDestroyContext(Context);  
  66. 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

XYZ位置

AL_VELOCITY

fv, 3f, iv, 3i

速度向量

AL_ORIENTATION

fv, iv

"at""up"向量描述的方向


示例:

 

[cpp]   view plain copy
 
  1. ALfloat listenerPos[]={0.0,0.0,0.0};  
  2. ALfloat listenerVel[]={0.0,0.0,0.0};  
  3. ALfloat listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};  
  4.   
  5. // Position ...  
  6. alListenerfv(AL_POSITION,listenerPos);  
  7. if ((error = alGetError()) != AL_NO_ERROR)  
  8. {  
  9.     DisplayALError("alListenerfv POSITION : ", error);  
  10.     return;  
  11. }  
  12.   
  13. // Velocity ...  
  14. alListenerfv(AL_VELOCITY,listenerVel);  
  15. if ((error = alGetError()) != AL_NO_ERROR)  
  16. {  
  17.     DisplayALError("alListenerfv VELOCITY : ", error);  
  18.     return;  
  19. }  
  20.   
  21. // Orientation ...  
  22. alListenerfv(AL_ORIENTATION,listenerOri);  
  23. if ((error = alGetError()) != AL_NO_ERROR)  
  24. {  
  25.     DisplayALError("alListenerfv ORIENTATION : ", error);  
  26.     return;  
  27. }  

 

 

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

數據拷貝的初始位置,一般沒有用

 

示例:

[cpp]   view plain copy
  1. // Retrieve Buffer Frequency  
  2. 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

sourcebuffer的頻率(采樣率)倍增器(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

附加的bufferID

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

播放的位置,字節數

 

示例:

[cpp]   view plain copy
  1. alGetError(); // clear error state  
  2. alSourcef(source[0],AL_PITCH,1.0f);  
  3. if ((error = alGetError()) != AL_NO_ERROR)  
  4.     DisplayALError("alSourcef 0 AL_PITCH : \n", error);  
  5.   
  6. alGetError(); // clear error state  
  7. alSourcef(source[0],AL_GAIN,1.0f);  
  8. if ((error = alGetError()) != AL_NO_ERROR)  
  9.     DisplayALError("alSourcef 0 AL_GAIN : \n", error);  
  10.   
  11. alGetError(); // clear error state  
  12. alSourcefv(source[0],AL_POSITION,source0Pos);  
  13. if ((error = alGetError()) != AL_NO_ERROR)  
  14.     DisplayALError("alSourcefv 0 AL_POSITION : \n", error);  
  15.   
  16. alGetError(); // clear error state  
  17. alSourcefv(source[0],AL_VELOCITY,source0Vel);  
  18. if ((error = alGetError()) != AL_NO_ERROR)  
  19.     DisplayALError("alSourcefv 0 AL_VELOCITY : \n", error);  
  20.   
  21. alGetError(); // clear error state  
  22. alSourcei(source[0],AL_LOOPING,AL_FALSE);  
  23. if ((error = alGetError()) != AL_NO_ERROR)  
  24.     DisplayALError("alSourcei 0 AL_LOOPING true: \n", error);  

 

6. buffer隊列(bufferqueuing)
buffer隊列用以保證聲音的連續播放。使用buffer隊列時,buffersource都是普通方法創建,但是附加buffersource時使用alSourceQueueBuffersalSourceUnqueueBuffers來替代alSourceialSourceQueueBuffers可以附加一個或一組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的方式(alSourceialSourceQueueBuffers)

2)所有通過alSourceQueueBuffers附加到某個sourcebuffer,都應該有相同的聲音格式。

 

7. 多普勒偏移(DopplerShift)

多普勒效應取決於sourcelistener相對於介質的速度,以及介質中聲音的傳播速度。應用程序可能希望強化或弱化多普勒效應,因為精確計算可能達不到期望的聲音效果。頻率偏移(音調改變)的量正比於listenersource接近或遠離的速度。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_FACTORsourcelistener速度的一個系數,用以放大或減小多普勒偏移量。

        void alDopplerFacor ( ALfloat dopplerFactor );

負數會導致AL_INVALID_VALUE錯誤,命令失效。默認值為1。通過alGetFloat{v}AL_DOPPLER_FACTOR可以獲取當前配置。

AL_SPEED_OF_SOUND允許應用程序改變傳播速度,sourcelistener以及聲音傳播的速度三者應該使用相同的速度單位。

        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內存溢出

示例:

[cpp]   view plain copy
 
  1. alGetError(); // Clear Error Code  
  2.   
  3. // Generate Buffers  
  4. alGenBuffers(NUM_BUFFERS, g_Buffers);  
  5.   
  6. if ((error = alGetError()) != AL_NO_ERROR)  
  7. {  
  8.     DisplayALError("alGenBuffers :", error);  
  9.     exit(-1);  
  10. }  

 

9. 擴展包(Extensions)

OpenALextension機制可以讓開發商增加新特性的API。創新科技(CreativeLabs)已經增加了多個extension,包括EAX,X-RAM, Multi-Channel Buffer playbackEffectExtension(EFX)。應用程序可以根據extension的種類調用alIsExtensionPresent或者alcIsExtensionPresent來判斷某個extension是否有效。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM