JOAL學習筆記
由於是概念介紹文章,沒有提供實例,這裏給出一個我的測試用例,它是在第一課的基礎上修改的。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import com.jogamp.openal.AL;
import com.jogamp.openal.ALFactory;
import com.jogamp.openal.util.ALut;
public class SingleStaticSource {
static AL al = ALFactory.getAL();
// Buffers hold sound data.
static int[] buffer = new int[1];;
// Sources are points emitting sound.
static int[] source = new int[1];
// Position of the source sound.
static float[] sourcePos = { 0.0f, -10.0f, 0.0f };//這裏對其速度進行設置,此時相對速度爲10個單位,改變+、-號來控制頻移方向
// Velocity of the source sound.
static float[] sourceVel = { 0.0f, 20.0f, 0.0f };//這裏將聲源的位置改變,此時距離聽衆20個單位。
// Position of the listener.
static float[] listenerPos = { 0.0f, 0.0f, 0.0f };
// Velocity of the listener.
static float[] listenerVel = { 0.0f, 0.0f, 0.0f };
// Orientation of the listener. (first 3 elements are "at", second 3 are
// "up")
static float[] listenerOri = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
static int loadALData() {
// variables to load into
int[] format = new int[1];
int[] size = new int[1];
ByteBuffer[] data = new ByteBuffer[1];
int[] freq = new int[1];
int[] loop = new int[1];
// Load wav data into a buffer.
al.alGenBuffers(1, buffer, 0);
if (al.alGetError() != AL.AL_NO_ERROR)
return AL.AL_FALSE;
ALut.alutLoadWAVFile("wavdata/0201_.wav", format, data, size,
freq, loop);
al.alBufferData(buffer[0], format[0], data[0], size[0], freq[0]);
// Bind buffer with a source.
al.alGenSources(1, source, 0);
if (al.alGetError() != AL.AL_NO_ERROR)
return AL.AL_FALSE;
al.alSourcei(source[0], AL.AL_BUFFER, buffer[0]);
al.alSourcef(source[0], AL.AL_PITCH, 1.0f);
al.alSourcef(source[0], AL.AL_GAIN, 1.0f);
al.alSourcefv(source[0], AL.AL_POSITION, sourcePos, 0);
al.alSourcefv(source[0], AL.AL_VELOCITY, sourceVel, 0);
al.alSourcei(source[0], AL.AL_LOOPING, loop[0]);
// Do another error check and return.
if (al.alGetError() == AL.AL_NO_ERROR)
return AL.AL_TRUE;
return AL.AL_FALSE;
}
static void setListenerValues() {
al.alListenerfv(AL.AL_POSITION, listenerPos, 0);
al.alListenerfv(AL.AL_VELOCITY, listenerVel, 0);
al.alListenerfv(AL.AL_ORIENTATION, listenerOri, 0);
}
static void killALData() {
al.alDeleteBuffers(1, buffer, 0);
al.alDeleteSources(1, source, 0);
ALut.alutExit();
}
public static void main(String[] args) {
// Initialize OpenAL and clear the error bit.
ALut.alutInit();
al.alGetError();
System.out.println(al.alGetInteger(AL.AL_DOPPLER_FACTOR));
System.out.println(al.alGetInteger(AL.AL_DOPPLER_VELOCITY));
// Load the wav data.
if (loadALData() == AL.AL_FALSE)
System.exit(-1);
setListenerValues();
// Setup an exit procedure.
Runtime runtime = Runtime.getRuntime();
runtime.addShutdownHook(new Thread(new Runnable() {
public void run() {
killALData();
}
}));
char[] c = new char[1];
while (c[0] != 'q') {
try {
BufferedReader buf = new BufferedReader(new InputStreamReader(
System.in));
System.out
.println("Press a key and hit ENTER: "
+ "'p' to play, 's' to stop, 'h' to pause and 'q' to quit");
buf.read(c);
switch (c[0]) {
case 'p':
// Pressing 'p' will begin playing the sample.
al.alSourcePlay(source[0]);
break;
case 's':
// Pressing 's' will stop the sample from playing.
al.alSourceStop(source[0]);
break;
case 'h':
// Pressing 'n' will pause (hold) the sample.
al.alSourcePause(source[0]);
break;
}
} catch (IOException e) {
System.exit(1);
}
}
}
}
下面是本次值得注意的地方
在第一章開始時,我就對聲源與聽衆速度的設定感到疑惑,即使設定了速度,也需要人爲地加和來改變位置(例如第二課中關於淡出的內容),那麼這個問題在本節中找到了答案,“速度”參數實際上改變的是聲音頻率,而非位置。
文末提及的兩個常數參數,“介質速度”與“多普勒係數”,它們的默認值是1.0
關於多普勒效應實現的幾個注意點:
1. 聲源與聽衆必須處在不同的位置上,設置的距離不要過大(否則聲音強度過低就無法聽到了,我使用10.0測試還可以)
2. 聲源與聽衆間有相對速度
3. 聲源播放的聲音緩衝區必須屬於單聲道音頻。
在滿足以上條件時,可以聽到明顯的頻率變化。
OpenAL中物理量與現實的區別:在現實中,如果質點間存在速度差,則質點間的距離一定在變化之中,文章中提到了不同物理位置受到的多普勒效應影響也不同(而且是非線性的),因此現實中聽衆聽到的頻率一定處於變化之中。OpenAL中,速度影響了頻率但位置依然依賴於外部過程對其位置進行改變(本質上講,與速度無關),所以通過改變速度量可以對應獲得頻率的改變,而對應於特定的速度,頻率在聽衆處是不變的。