Arama Motoru

OpenAL Ders 1: Basit Statik Ses

OpenAL: OpenAL Ders 1: Basit Statik Ses

14/06/2003
25/04/2010
Giriş

OpenAL'in heyecan verici dünyasına hoş geldiniz! OpenAL, API’nin büyük takipçileri olmasına rağmen tam potansiyele ulaşmamış, hala büyüme aşamasındadır. Bunun büyük sebeplerinden biri, hala özgül kartlar için tümleşik donanım hızlandırıcılarının olmamasıdır. Bununla birlikte, Creative Labs OpenAL projesinin önemli iştirakçisidir ve yine en büyük ses kartı imalatçılarının biridir. Ki bu yakın zamanda donanım akümülatörü için ümit vericidir. OpenAL'in diğer bir büyük iştirakçisi  Loki eşekler cennetine gitti. Bundan dolayı Linux platformlarında OpenAL'in geleceği belirsizdir. Yinede pek bilinmeyen birkaç web sitesinin tenha köşelerinden Linux binarylerini elde edebilirsiniz.

OpenAL , yine de  çoğu büyük ticari ürünlerce fark edilmiş değil , yanı sıra gelişimi üzebilir. Bildiğim kadarıyla OpenAL'ı kullanan tek pc oyunu Metal Gear 2 (Gerçi geçenlerde Unreal2’ninde kullandığını keşfettim). Popüler modelleme programı, Blender3D,  tüm sesler için OpenAL'i kullandığı yine bilinmekte. Bunlar dışında diğer sadece OpenAL kullanımı sdk örnekleri ve İnternette birkaç anlaşılmaz derstedir.

Ama ona yönel, OpenAL birçok potansiyele sahiptir. Daha düşük düzeyli donanımla çalışmayı isteyen(ve bu meşruda olabilir) birçok başka ses kütüphanesi vardır ama OpenAL'in tasarımcıları tasarımda onu üstün bir API yapan bazı şeyler yaptı. Onlar her şeyden önce  şimdiye kadar tasarlanmış en iyisi olan OpenGL API'i taklit etti. API stili esnektir, bu sayede farklı kodlama metotları ve donanım uyarlamaları bundan faydalanacaktır. OpenGL ‘i tecrübe etmiş çoğu kişi oldukça hızlı OpenAL'de gelişebilecektir. OpenAL aynı zamanda birçok diğer API'nin sahip olamadığı 3D surround ses yaratma avantajına sahiptir. Her şeyin üstünde aynı zamanda kusursuzca EAX ve AC3'e erişme yeteneğine sahiptir. Bildiğim hiçbir diğer ses kütüphanesi bu yeteneğe sahip değildir.
OpenAL’ı kullanmak için hala burada bir sebep bulamadıysanız o zaman bunlarda diğerleridir. O tamamen harikadır. API güzel görünür ve kodlarınızla güzel bütünleşecektir. Onunla birçok harika ses efektleri yapabileceksiniz. Tabi önce temeli öğrenmeliyiz.

Velhasıl hadi kodlara bakalım!

#include <conio.h>
#include <stdlib.h>
#include <al.h>
#include <alc.h>
#include <alu.h>
#include <alut.h>

OpenAL headerları ile OpenGL headerları arasındaki benzerliği fark etmişinizdir.  "gl.h", "glu.h", ve "glut.h" gibi aynen "al.h", "alu.h", ve "alut.h" vardır, tabi birde "alc.h" var. Alc, Audio Library Context’in kısaltmasıdır ki farklı platformlar arası ses aygıtlarını yönetir. Ve de, farklı pencerelerce bir aygıtın paylaşılması durumunu yönetir. Alc'i OpenGL'de herhangi bir şeye benzetmeyi istiyorsanız, muhtemelen en çok wgl ve glX eklentilerine benzetilebilir. Alut kütüphanesi bizim için onu içten yönettiğinden Alc'e çok girmeyeceğiz, ve şimdilik ona henüz dokunmayacağız. Aynı şekilde,  küçük demolarımızda ihtiyaç duymayacağımız bazı matematik işlevselliğini sağlayan Alu'uda çok fazla kullanmayacağız.



// Bufferlar ses datasını tutar.
ALuint Buffer;

// Sourceler ses yayılma noktalarıdır.
ALuint Source;

OpenGL İle aşina olanlar,  bir program tarafından kullanılan texturelerı yönetmek için "texture objeleri"(veya texture isimleri) kullanıldığını bilir. OpenAL, ses dosyaları için benzer şeyi yapar. Aslında OpenAL'de 3 çeşit nesne vardır. Birincisi Buffer , ses verisinin kendini ve sesin nasıl çalınacağı hakkındaki tüm bilgileri depolar, ve ikincisi source, sesin yayıldığı uzayda bir noktadır. Bir sourcenin,  ses dosyasının kendisi olmadığını anlamak önemlidir. Bir source sadece bağlanılan bir bufferdan ses datasını çalar. Source aynı zamanda "pozisyon ve hız" gibi spesyal özellikleri belirler.

Henüz bahsetmediğim üçüncü nesne listenerdır. Kullanıcının ,'sizin', konumunu temsil eden sadece bir listener vardır. Ses dosyasının nasıl duyulacağını source özellikleriyle beraber listener özellikleri saptar. Misal, onların ilgili pozisyonları sesin şiddetini saptar.

// Sourcenin Pozisyonu.
ALfloat SourcePos[] = { 0.0, 0.0, 0.0 };

// Sourcenin hızı.
ALfloat SourceVel[] = { 0.0, 0.0, 0.0 };


// listenerın pozisyonu.
ALfloat ListenerPos[] = { 0.0, 0.0, 0.0 };

// listenerın hızı.
ALfloat ListenerVel[] = { 0.0, 0.0, 0.0 };

// listenerın yönü. (ilk 3 eleman "-de,-da", ikinci 3lü "üs")
ALfloat ListenerOri[] = { 0.0, 0.0, -1.0,  0.0, 1.0, 0.0 };

Yukarıdaki kodda , source ve listener nesnelerinin "pozisyon ve hızını" belirtiyoruz. Bu diziler, kartezyan koordinatları temelli vektördür. Tartışmasız aynı şeyi yapan bir "yapı veya sınıf" geliştirebilirdiniz. Bu örnekte, basitlik için dizileri kullandım.

ALboolean LoadALData()
{
    // alutLoadWAVFile çağrısı sonrası otomatik dolacak değişkenler.

    ALenum format;
    ALsizei size;
    ALvoid* data;
    ALsizei freq;
    ALboolean loop;

Burada bir dosyadan ses datamızın hepsini yükleyen bir fonksiyonu yaratacağız. Buradaki değişkenler, alutLoadWaveFile'ın bize sağlayacağı bazı bilgileri depolamak için gereklidir.

    // buffera wav datasını yükle.
    alGenBuffers(1, &Buffer);
    if (alGetError() != AL_NO_ERROR)
        return AL_FALSE;

    alutLoadWAVFile("wavdata/FancyPants.wav", &format, &data, &size, &freq, &loop);
    alBufferData(Buffer, format, data, size, freq);
    alutUnloadWAV(format, data, size, freq);

'alGenBuffers' fonksiyonu, buffer nesnesini yaratıp ona geçtiğimiz değişkene onu depolayacak. Her şeyin sorunsuz gittiğinden emin olmak için bir hata kontrolü yapmak önemli. OpenAL, buffer nesnesini oluşturamadığında bellek israfı olur.  Bu durumda hata biti set edilir.

Alut kütüphanesi burada çok yararı dokunmaktadır. Bizim için dosyayı açıp buffer yaratmada ihtiyaç duyduğumuz tüm bilgileri bize sağlar. Ve biz buffera bütün bu veriyi dahil ettikten sonra bu veriden kurtulmamıza da yardım eder. Tamamen temiz ve etkin bir şekilde çalışır.

    // source ile bufferı bağla.
    alGenSources(1, &Source);

    if (alGetError() != AL_NO_ERROR)
        return AL_FALSE;

    alSourcei (Source, AL_BUFFER,   Buffer   );
    alSourcef (Source, AL_PITCH,    1.0f     );
    alSourcef (Source, AL_GAIN,     1.0f     );
    alSourcefv(Source, AL_POSITION, SourcePos);
    alSourcefv(Source, AL_VELOCITY, SourceVel);
    alSourcei (Source, AL_LOOPING,  loop     );

Buffer nesnesini oluşturduğumuzla aynı biçimde bir source nesnesini oluştururuz. Sonra,  çalma zamanı kullanılacak source özelliklerini tanımlarız. Bu özelliklerden en önemlisi,  kullanacağı bufferdır. Bu, source'e çalınacak ses dosyasını söyler. Bu durumda sadece bir taneye sahip olunduğuna biz ona bağlarız. Aynı şekilde,  source'e daha önce tanımladığımız onun "pozisyon ve hızını" söyleriz.

'alGenBuffers' ve 'alGenSources' hakkında bir şey de. Bazı örnek kodlarda bu fonksiyonların yaratılan bufferlar / sourcelerin nosu için bir tam sayı değeri döndüreceğini gördüm. Ben zannedersem bunun daha sonraki sürümlerde dahil edilmeyen bir hata kontrol etme özelliği olduğunu düşünüyorum. Eğer başka kodlarda bunun yapıldığını görürseniz de siz kullanmayın. Eğer kontrol yapmak istiyorsanız bunun yerine 'alGetError' kullan (yukarda yaptığımız gibi).

    // diğer hata kontrolü yapılır ve dönülür.
    if (alGetError() == AL_NO_ERROR)
        return AL_TRUE;

    return AL_FALSE;

Fonksiyon sonunda her şeyin yolunda olduğundan emin olmak için bir daha kontrol yaparız, sonra sonucu döndürürüz.

void SetListenerValues()
{
    alListenerfv(AL_POSITION,    ListenerPos);
    alListenerfv(AL_VELOCITY,    ListenerVel);
    alListenerfv(AL_ORIENTATION, ListenerOri);
}

Listener özelliklerini set etmek için bu fonksiyonu yarattık.

void KillALData()
{
    alDeleteBuffers(1, &Buffer);
    alDeleteSources(1, &Source);
    alutExit();
}

Bu, bizim kapanış prosedürümüz olacak. Programımızın, kullandığı tüm hafıza ve ses aygıtlarını serbest bırakmak için bu çağrı gereklidir.

int main(int argc, char *argv[])
{
    // OpenAL’ı ilkle ve hata bitini resetle.

    alutInit(&argc, argv);
    alGetError();

'alutInit' Fonksiyonu, bizim için yapmada Alc ‘nin gerek duyduğu her şeyi kuracak. Basitçe Alut, Alc aracılığıyla bir OpenAL context’ini yaratır ve onu aktif geçerli olarak set eder. Windows platformunda, DirectSound'u ilkler. Sonra hata bitini resetlemek üzere hata fonksiyonuna ilk çağrıyı yaparız. Yani hata durumunu 'AL_NO_ERROR' 'e getirmek için  'alGetError' çağrısını yaparız.

    // wav datasını yükle.
    if (LoadALData() == AL_FALSE)
        return -1;

    SetListenerValues();

    // bir çıkış prosedürü kur.
    atexit(KillALData);

wav dosyalarının doğru şekilde yüklülüğünü anlamaya çalışacağız. Aksi durumda programı sonlamalıyız. Sonra, listener değerlerini set eder Ve en sonda çıkış prosedürümüzü set ederiz.

    ALubyte c = ' ';

    while (c != 'q')
    {
        c = getche();

        switch (c)
        {
            // 'p' ’e basılma çalmayı başlatacak.
            case 'p': alSourcePlay(Source); break;

            // 's' ’e basılması çalmayı bitirecek.
            case 's': alSourceStop(Source); break;

            // 'h'’e basılması çalmayı duraklatacak.
            case 'h': alSourcePause(Source); break;
        };
    }

    return 0;
}

Bu, dersin ilginç kısmıdır. Ses dosyasının çalınmasını kontrol etmemize imkan veren oldukça basit bir döngüdür. 'p' ’e basılma çalmayı tekrarlatacak, 's' ’e basılma çalmayı bitirecek ve 'h' ’e basılma çalmayı duraklatacaktır. 'q' ’e basılma programdan çıkaracaktır.
Eee durum böyle. OpenAL'ı ilk keşfiniz. Sizin için yeterince kolay olduğunu umuyorum. 1337 h4X0r için biraz fazla basit olmuş olabilir ama hepimiz bir yerden başladık. İlerledikçe daha gelişilecek.


*Bu dersin Java versiyonu için Java Bindings for OpenAL sayfasına bakın (Athomas Goldberg tarafından adapte edildi)


Dersin Orjinali : http://www.devmaster.net/articles/openal-tutorials/lesson1.php