Sunday, November 14, 2010

ත්‍රිමාණ රූප සමග openAL

සෑහෙන කාලෙකට පස්සෙ තමයි ලිපියක් ලියන්න වෙලාවක් ලැබුනෙ. බොහෝ දෙනෙක් ඉතින් openGL ගැන අහල ඇතිනෙ. ත්‍රිමාණ රෑප එක්ක එහෙම වැඩ කරල තියෙන අය. openAL ටිකක් ඒ වගේම තමයි සංකල්පත් openGL වගේ. වෙනසකට තියෙන්නෙ openAL තියෙන්නෙ ත්‍රිමාණ රෑප වලට නෙමෙයි ත්‍රිමාණ ශබ්ද වලට. openAL ලියල තියෙන්නෙ C++ වලින් හේතුව ඉතින් මේ වැඩේ sound card එකෙ දෘඩාංග එක්ක කිට්ටුවෙන් යන නිසා. අනිත් එක මේක හොදමට වැඩ කරන්නෙ creative දෘඩාංග එක්ක(sound cards එක්ක).නමුත් අනික් ඒවත් එක්ක උනත් මෘදුකාංග වලින් වැඩ කරන්න පුළුවන්. මට වෙනත් සහයෝගයත් අවශ්‍ය නිසා java wrapper එකක් පාවිච්චි කරල openAL ජාව වලට ගන්න සිද්ධ උනා. wrapper එක ඉතින් java open al නැත්තං joal.
joal සයිට් එකේ දකුණු පැත්තෙ තියෙනව tutorils and demos මේව ටිකක් බැලුවම openAL ක්‍රියාත්මක වෙන තත්වයට පත් කරගන්න අමාරු නැහැ. පලවෙනි එක කරල බැලුවම නිකම්මම වැඩ කරනවා. :). ඒකට හැබැයි ඒකත් එක්ක එන dll files system32 එකට දාන්න වෙනවා (windows වලදි). (බයවෙන්න දෙයක් නෑ, ලිනක්ස් සහයත් තියෙනව කිසි කරදරයක් නැතිව). හැබැයි කෝඩ් එක දැක්කම නිකං පිස්සු එකයි කිසිම දෙයක් තේරෙන්නෙ නැහැ. ඒ වගේම තමයි කෝඩ් එකේ ඒ ඒ තැන්වල තියෙන දේ පිලිබදව විස්තරයක් නෑ. ඒ වගේම method names වලින් හිතාගන්නත් බෑ මොනවද වෙලාතියෙන්නෙ කියල. දීල තියෙන examples වැඩ කරාට අපිට ඕන දේ මේ විදියට කරගන්න බෑනෙ.
මගේ අවශ්‍ය තාවය උනේ. ත්‍රිමාණ පරිසරයක තියෙන ශබ්ද නිකුත් කරන මූලාශ්‍ය එකක් හෝ එකකට වැඩි ගනනක් නිරූපණය කරන එක. මේ මූලාශ්‍ය තියෙන තැන් වෙනස් වෙන්න පුළුවන්. තියෙන ගාන කියන්නත් බෑ. දීල තියෙන tutorial එකේ තියෙනව multiple sources කියල එකක්. ඒක සම්පුර්ණයෙන්ම hard code කරල. ඒ වෙනුවට අපිට පිලිවෙල වෙනස් කරල කරගන්න විදියක් තියෙනවද කියල බලමු. ඒ වගේම ඒ ඒ method names වලින් කි‍යවෙන දේත් බලමු. (මේක ගැන කිසිම තැනක documentation එකක් නෑ. ඉතින් මට හිතිච්ච උපකල්පන තමා ලියන්නෙ. වැරැද්දක් තියෙනව නං පෙන්නල දෙන්න පුළුවන් :))
අපිට ඕනෙ sound sources interface එකක්, soundcomposer ක්ලාස් එකක් හා main class එක.

public class SoundComposer {

ArrayList SoundSources = new ArrayList();
AL al;
float Listenerx = 0;
float Listenery = 0;
float Listenerz = 0;
float ListenerVelx = 0;
float ListenerVely = 0;
float ListenerVelz = 0;
float ListenerOrix = 0;
float ListenerOriy = 0;
float ListenerOriz = 0;
int buffer[];
int[] sources;
public SoundComposer() {
ALut.alutInit();
al = ALFactory.getAL();
}

public void setListenerValues() {
al.alListenerfv(AL.AL_POSITION, new float[]{Listenerx, Listenery, Listenerz}, 0);
al.alListenerfv(AL.AL_VELOCITY, new float[]{ListenerVelx, ListenerVely, ListenerVelz}, 0);
al.alListenerfv(AL.AL_ORIENTATION, new float[]{0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}, 0);
}

public void loadSoundSources() {

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];
int noofsources = SoundSources.size();
buffer = new int[noofsources];
sources = new int[noofsources];
al.alGenBuffers(noofsources, buffer, 0);
al.alGenSources(noofsources, sources, 0);
//buffers and the sources are generated at the same time;

if (al.alGetError() != AL.AL_NO_ERROR) {
System.out.println("Error at generating sources");
}
System.out.println("size" + noofsources);
int i = 0;
for (SoundSource sound : SoundSources) {
ALut.alutLoadWAVFile(sound.AudioPath, format, data, size, freq, loop);
al.alBufferData(buffer[i], format[0], data[0], size[0], freq[0]);
sound.SourceID = i;
System.out.println(sound.SourceID + "==" + buffer[i]);
//
al.alSourcei(sources[i], AL.AL_BUFFER, buffer[i]);
al.alSourcef(sources[i], AL.AL_PITCH, 1.0f);
al.alSourcef(sources[i], AL.AL_GAIN, 1.0f);
al.alSourcefv(sources[i], AL.AL_POSITION, new float[]{sound.x, sound.y, sound.z}, 0);
al.alSourcefv(sources[i], AL.AL_VELOCITY, new float[]{sound.vx, sound.vy, sound.vz}, 0);
al.alSourcei(sources[i], AL.AL_LOOPING, sound.loop);
//

i++;
}
setListenerValues();

}

} } }

මෙතන කොල පාටිනුයි මුලින් තද නිල් පාටි‍නුයි දක්වල තියෙන්නෙ wav file එක buffer එකට දාගන්න buffer එක සෙට් කරගන්නයි buffer එක source එකකට දාගන්න source එක හදාගන්නා හැටියි. සාමාණ්‍යයෙන් buffer කරන ඒව ඔක්කොම ඉවරකරල ඊට පස්සෙ source සම්බන්ධ කරන විදියට තමා හුගක් තැන් වල තියෙන්නෙ. නමත් මේ දෙකේ සම්බන්ධයක් එන්නෙ හුගක් පස්සෙ නිසා එකටම කරයි කියල අවුලක් නෑ. sources set කරාට පස්සෙ ඒ කියන්නෙ තද නිල්පාට මේ source array එකට unique අංක සෙට් එකක් ගහල එවනවා. ඒ අංකෙන් source එක හරියටම අදුනගන්න පුළුවන්. ඒ කියන්නෙ ඊට පස්සෙ අපි කරන්නෙ buffer කරගත්ත wav එක අර අංකෙත් එක්ක සම්බන්ධ කරන එක. ඒක ලා නිල් පාටින් පේනවා. බැලූ බැලුමට වෙනදේ තේරෙනවා වගේ. නමුත් alSourcei, alSourcef, alSource3f, alSourcefv කියන්නෙ මොනවද? මට තේරුන විදියට නං මේවා setters sourcei කියන්නෙ int එකක් අපි දෙන පලවෙනි parameter එකෙන් කියවෙන එකට සෙට් කරනවා කියන එක. sourcef කියන්නෙ float එකක්. Souce3f කියන්නෙ float 3ක් කියන එක ඒ වගේම තමා sourcefv කියන්නෙ float array එකක් කියන එක. මේ විදියට අපිට එක method එකක් මගින් හැම එකම set කරගන්න පුළුවන්. එක අතකට ඒක හොද අදහසක්. :). (මට නං හැබැයි ජීවිතේටවත් ඒ විදියටනං කරන්න හිතෙන්නෙ නෑ.)

int[] state = new int[1];
al.alGetSourcei(sources[0], AL.AL_SOURCE_STATE, state, 0);
System.out.println(state[0]);

මේ තියෙන්නෙ ඉතින් ඕකෙ අනිත් පැත්ත තමා. එලියට ගන්න විදිය getter එක. ඒකත් අපි store කරන්න ඕනෙ variable array එක පාස් කරල ඒක හරහා ගන්න ඕනෙ. අනික තමා මේක මේ iterate වෙන්නෙ මං කලින් එවපු Sources කියල arraylist එකක් වටේට. ඒකෙ තියෙන object වල x,y,z හා ඒකට අදාල wav file reference එක තියෙනවා. තද රතුපාටින් දක්වල තියෙන්නෙ ඒක. පලවෙනි tutorial එක බැලුවනං වැඩේ තිතට තේරෙනවා. sound.x, sound.vx විදියට අරං තියෙන්නෙ ඒ source එකේ තියෙන තැන x ඛන්ඩාංකයි. x දිශාවට තියෙන ප්‍රවේගයයි. ඒක පොඩි class එකක් හදලා දාගත්තම ඇති data entity එකක් විදියට.