14/06/2003
25/04/2010
OpenAL dizisinin bu aşamasında, bufferlarınızın birden çok source arasında paylaşılması metodunu göstereceğim. Bu, çok makul ve doğal bir adım, ve bu o kadar kolay ki bazılarınız hali hazırda bunu kendisi yapmış olabilir. Eğer bunu yaptıysanız tüm bu dersi şimdi atlayıp sonrakine geçebilir. Ama verdiğim bilginin tümünü okumaya hevesli zekiler için ilginç bulanabilir bu ders. Artı, direkt Alc katmanını uygulayacağız öyle ki ders 4'de kazanılan bilginin bir kısmını kullanacağız. Bunlara ek, hatta kullanabileceğiniz bir program yaratacağız!
Güzel, hadi. Kodun çoğu
şimdiye kadar seride tekrarlandığından dolayı sadece önemli olan kod kısmını incelemeye karar
verdim. İndirilen kaynak kodundan tamamına bakılabilir. Bir şey de: Bu ders, STL'den
vektörleri kullanacak, bundan dolayı onun
kurulu olduğundan emin olun ve çalışması hakkında
biraz
bilginizin vardır
umarım.
Burada
STL'i anlatmayacağım çünkü bu bir OpenAL
dersidir.
// bufferlar indeksi.
#define THUNDER 0
#define WATERDROP 1
#define STREAM 2
#define RAIN 3
#define CHIMES 4
#define OCEAN 5
#define NUM_BUFFERS 6
// Bufferlar ses datasını tutar.
ALuint Buffers[NUM_BUFFERS];
// çoklu çalma için sourcelerin vektör listesi.
vector Sources;
İlkin, buffer dizisini indekslemede kullandığımız benim
yazdığım birkaç makro. Farklı wav
dosyalarını kullanıyor
olacağız bundan dolayı burada
birden çok buffera ihtiyaç
duyarız. Sourceleri depolamak için
bir diziyi kullanmak yerine bir STL
vektörünü kullanacağız. Bunu yapmayı
seçtik çünkü sourcelerin sayısını
dinamik
belirlememize olanak verir.
Sourceleri
sahnede sadece OpenAL onları
tüketinceye kadar ekli tutarız. Bu, aynı şekilde
bizim, sourceleri bir
resource olarak değindiğimiz ilk derstir. Ve Evet, tükenirler; onlar
sonludur.
ALboolean InitOpenAL()
{
ALCdevice* pDevice;
ALCcontext* pContext;
ALCubyte* deviceSpecifier;
ALCubyte deviceName[] = "DirectSound3D";
// aygıt handleyini el et.
pDevice = alcOpenDevice(deviceName);
// aygıt belirtecini elde et.
deviceSpecifier = alcGetString(pDevice, ALC_DEVICE_SPECIFIER);
printf("Using device '%s'.\n", szDeviceSpecifier);
// ses context’i yarat.
pContext = alcCreateContext(pDevice, NULL);
// aktif geçerli context olarak yap.
alcMakeContextCurrent(pContext);
// hata kontrolünü yap.
if (alcGetError() != ALC_NO_ERROR)
return AL_FALSE;
return AL_TRUE;
}
Bu, bizim, son derste öğrendiğimiz örnek kodun bir kısmıdır. "DirectSound3D" aygıtına bir handle elde ederiz, ve sonra bizim uygulamamız için bir renderleme context'i elde ederiz. Bu context aktif geçerli olarak set edilir ve fonksiyon başarıyla dönmeden evvel her şey düzgün gittiğinin kontrolü yapılır.
void ExitOpenAL()
{
ALCcontext* pCurContext;
ALCdevice* pCurDevice;
// aktif geçerli context’i elde et.
pCurContext = alcGetCurrentContext();
// bu context tarafından kullanılan aygıtı elde et.
pCurDevice = alcGetContextsDevice(pCurContext);
// aktif geçerli context’i NULL’a getir.
alcMakeContextCurrent(NULL);
// context ve aygıtı serbest bırak.
alcDestroyContext(pCurContext);
alcCloseDevice(pCurDevice);
}
Bu, bizim önceki kodda
yaptığımızın tersini yapacak. O, Uygulamamızın
kullanıp
serbest
bırakacağı context ve aygıtı elde eder.
O hem de,
OpenAL'e
yollanan herhangi bir verinin işleme tabi tutulmasını askıya
alacak aktif geçerli context’e NULL 'u set eder . Onun aktif
geçerli context
olarak NULL ayarlanması önemlidir
yoksa veriyi
işleme tabi tutmak için geçersiz bir contexta sahip
olacaksınız. Bunu yapmanın
sonuçları, tahmin edilemeyebilir.
Eğer bir
multi-context uygulamasını
kullanıyorsanız ilkleme ve sonlamayla uğraşan daha ileri
bir yönteme sahip olmaya ihtiyaç
duyabilirsin. Bütün aygıtları ve contextleri global yapıp aktif
geçerli context'i geri almadan daha önce onları
ayrı ayrı kapatmanı tavsiye
ederim.ALboolean LoadALData()
{
// alutLoadWAVFile çağrısıyla dolacak değişkenler.
ALenum format;
ALsizei size;
ALvoid* data;
ALsizei freq;
ALboolean loop;
// bufferlara wav datasını yükle.
alGenBuffers(NUM_BUFFERS, Buffers);
if(alGetError() != AL_NO_ERROR)
return AL_FALSE;
alutLoadWAVFile("wavdata/thunder.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[THUNDER], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
alutLoadWAVFile("wavdata/waterdrop.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[WATERDROP], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
alutLoadWAVFile("wavdata/stream.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[STREAM], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
alutLoadWAVFile("wavdata/rain.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[RAIN], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
alutLoadWAVFile("wavdata/ocean.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[OCEAN], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
alutLoadWAVFile("wavdata/chimes.wav", &format, &data, &size, &freq, &loop);
alBufferData(Buffers[CHIMES], format, data, size, freq);
alutUnloadWAV(format, data, size, freq);
// diğer hata kontrolunu yapıp döndür.
if (alGetError() != AL_NO_ERROR)
return AL_FALSE;
return AL_TRUE;
}
Bu fonksiyondan sourceleri birlikte üretimini çıkardık. Çünkü bundan sonra, ayrı sourceleri ilkleyeceğiz.
void AddSource(ALint type)
{
ALuint source;
alGenSources(1, &source);
if (alGetError() != AL_NO_ERROR)
{
printf("Error generating audio source.");
exit(-1);
}
alSourcei (source, AL_BUFFER, Buffers[type]);
alSourcef (source, AL_PITCH, 1.0 );
alSourcef (source, AL_GAIN, 1.0 );
alSourcefv(source, AL_POSITION, SourcePos );
alSourcefv(source, AL_VELOCITY, SourceVel );
alSourcei (source, AL_LOOPING, AL_TRUE );
alSourcePlay(source);
Sources.push_back(source);
}
Bizim için
sourceleri oluşturacak olan
fonksiyon budur. Bu fonksiyon, önceki kodla oluşturduğumuz
yüklü
bufferların her
birisi için tek bir source oluşturur. Verilen
buffer ,
indeks
“tipindedir”, bu dersin başında
yarattığımız makrolardan biridir. Çalabilecek
bir
source'e sahip olduğumuzdan
emin olmak için bir hata kontrolü yaparız (dediğim gibi, onlar
sonludur). Eğer bir source tahsis
edilemezse, programdan çıkılacak.
void KillALData()
{
for (vector::iterator iter = Sources.begin(); iter != Sources.end(); ++iter)
alDeleteSources(1, iter);
Sources.clear();
alDeleteBuffers(NUM_BUFFERS, Buffers);
ExitOpenAL();
}
Bu fonksiyon, STL listesi kullanımı sebebiyle biraz değiştirildi. Ayrı ayrı listedeki her source'i silip sonra etkili olarak onu yok edecek olan liste temizliği zorunluluktur.
ALubyte c = ' ';
while (c != 'q')
{
c = getche();
switch (c)
{
case 'w': AddSource(WATERDROP); break;
case 't': AddSource(THUNDER); break;
case 's': AddSource(STREAM); break;
case 'r': AddSource(RAIN); break;
case 'o': AddSource(OCEAN); break;
case 'c': AddSource(CHIMES); break;
};
}
Bu, main'imizdeki
programın iç döngüsüdür. O basitçe, bazı klavye
girdilerini bekler ve belirli tuşun
basılmasıyla, belirli
türde yeni source’i yaratıp ses sahnesine
ekler. Aslında bizim burada
yarattığımız , insanların gevşeme için dinlediği doğa kaydı gibi
bir
şey. Arka
planda istedikleri
sesleri
özelleştirmek için kullanıcıya izin verdiğinden dolayı bizimki biraz daha
iyidir. Oldukça etkili he? Ben, kodlama yaparken kendiminkini dinlemekteyim. O, bir Zen tecrübesidir
(şu an onu
dinliyorum).
Program, daha çok wav
dosyasını kullanmak için genişletilip,
sourceleri sahne civarı keyfi pozisyona konumlatma özelliği eklemeye sahip.
Döngületmek yerine siz de
verilecek bir frekansla sourceleri çaldırtabilirsiniz. Bununla
birlikte bu dersin alanının ötesinde olan GUI
rutinlerini gerektirir. Tüm özellikleriyle
oyun motorunu yapmak için güzel bir
program olurdu. ;)
Dev-C++
proje ve kaynak dosyalarını yükle
Visual C++ 6.0 proje ve kaynak dosyalarını yükle - (TheCell tarafından port edilmiştir)
Java kaynak kodlarını yükle - (Athomas Goldberg tarafından port edilmiştir)
Bu dersin Linux’e portunu yükle - (Lee Trager tarafından port edilmiştir)
Visual C++ 6.0 proje ve kaynak dosyalarını yükle - (TheCell tarafından port edilmiştir)
Java kaynak kodlarını yükle - (Athomas Goldberg tarafından port edilmiştir)
Bu dersin Linux’e portunu yükle - (Lee Trager tarafından port edilmiştir)
* Bu dersin java
versiyonu için Java Bindings for
OpenAL sayfasını ziyaret edin (Athomas Goldberg tarafından adapte
edilmiştir)
Dersin Orjinali : http://www.devmaster.net/articles/openal-tutorials/lesson5.php
Dersin Orjinali : http://www.devmaster.net/articles/openal-tutorials/lesson5.php