Arama Motoru

OpenAL Ders 8: OggVorbis Streamleme Source Kuyruğunun Kullanılması


14/07/2003
23/05/2010


Yeniden merhaba programcı arkadaşlar. OpenAL api'e oldukça uzun bir aradan sonra başka bir dersle döndüm. Ve epey iri olacağını düşünüyorum bunun. İlkin, dizide buraya kadar desteği olanlara teşekkür etmek isterim. Diziyi web sitelerinde ağırlayan DevMaster.net 'e  çok özel teşekkürlerimi bildirmek istiyorum. Tüm seriyi Visual C++ 6’e portu için TheCell’e, ve Java JOAL için Athomas Goldberg’e (Java Bindings for OpenAL). Yine onların Brezilyaca GameDev 'i Portekizceye çevirdiğinide duydum. Yine, bir daha yazmam için kafi gazı sağlayan bazı örnek kodlar yollayan Jorge Bernal'a özel teşekkürlerimi sunmak isterim. Bu büyük bir yardımdı (İspanyolcadan kodu çevirmek bir angarya olsa bile :).

OggVorbis’e Giriş
Hiç Ogg'i duydunuz mu? Tuhaf ismi dışında daha fazlasıdır. Ses sıkıştırması için mp3'den bu yana olan en önemlisidir (yine genelde müzik için kullanılır). Umarım bir gün ses sıkıştırması için ana standart olarak mp3'in yerine geçecek. O, mp3'e kıyasla daha iyi midir? Cevaplaması biraz zor olan bir sorudur. Bu, bazı topluluklarda epey şiddetli bir tartışmadır. Ses kalitesine karşı okuma için bazen gerçekten elverişsiz olabilen sıkıştırma oranının hakkında çeşitli tartışmalar vardır. Ben şahsen,  "Daha iyisinin" olduğu düşüncesinde değilim. her durumda karşı görüşlerin tartışmalı olduğunu düşünüyorum ve Bahsetmeye değer değil. Ama benim için Ogg'in telif hakkının beleş olması  (mp3 değil) gerçeği,  tartışmayı kazandırır. Mp3 lisans ücreti, hiçbir şekilde ensesi kalın geliştiriciler için fahiş değildir, Ama boş zamanında bir projede minimal kaynaklarla çalışanlar için, Bu parayı coşmak bir seçenek değildir. Ogg’nin ücreti hayır duasıdır.

OggVorbis Streamleme APIlerinizin tasarlanması
Fazla uzatmadan biraz koda bakalım.
#include <string>; 
#include <iostream>; 
using namespace std;#include <al.h>;
#include <ogg/ogg.h>;
#include <vorbis/codec.h>;
#include <vorbis/vorbisenc.h>; 
#include <vorbis/vorbisfile.h>;#define BUFFER_SIZE (4096 * 8)

Bu ders pür C++ kodlarla yazılı bu yüzden ilkin C++ 'ın bazı standart header'larını include ederiz. tabii OpenAL include edilecek (her zaman ki gibi), Ve aynı şekilde, 4 yeni header'ı include edeceğiz. Bu yeni header'lar, OggVorbis'in geliştiricileri tarafından yazılan kütüphaneler takımı içindir. Toplamda bu 4 tane: 'ogg.dll' (format ve dekoder), 'vorbis.dll' (kodlama düzeni), 'vorbisenc.dll' ( encoding araçları), ve 'vorbisfile.dll' (streamleme ve seeking araçları). vorbisenci kullanmayacağız Ama kullanabilir dosyalardan biri olduğunu göstermek için onu ekledim. Bu kütüphaneleri kullanmak, işin 99% zorluğunu alacak (hemen hemen tümü). Gerçekten, onları kullanmamak için hiçbir sebep yoktur. her şeyi biz yapsaydık tekerleği tekrar icat ediyor olurduk, Ve ben, biz koderlerin asıl geliştiricilere kıyasla daha iyisini yazabileceğinden şüpheliyim. Diğer bir artı: Bizim tarafımıza herhangi bir ekstra iş düşmeden format evrimi mesela bu kütüphanelerce güncelleştirilecek. Ama bu kütüphaneleri kullanmanın en büyük sebebi tutarlılıktır . Eğer bütün Ogg dosyaları dekoder ve encodinglemede bu kütüphaneleri kullansa O zaman bütün Ogg'ler bütün Ogg çalıcılarında çalınabilir. bu standart kütüphane setini kullandığımız taktirde  o zaman varolan tüm Ogg dosyalarını destekleyebileceğimizden emin olabiliriz.
Yine her güncellemede streamden okumayı istediğimiz büyüklüğü tanımlayan 'BUFFER_SIZE' makrosunu yaratırız. çoğunlukla güncelleştirilmediğinden dolayı daha kaliteli sesi üreten Ve genellikle herhangi beklenmedik duraksama veya ses bozukluklarını önleyecek buffer büyüklüğünü keşfedersin (Birazcık denemeyle). Tabii buffer'ının ne kadar büyükse aynı oranda daha çok bellek tüketimi demektir. lüzumsuz Bir stream yapmak. 4096'nın sahip olunmalı minimum buffer boyutu olduğuna  inanıyorum. daha küçüğünü kullanmayı tavsiye etmem. Denedim, ve çok cızırtıya sebebiyet verdi.
Böyle niye streamlemeyle canımızı sıkıyoruz ki? Niye bir tampona tüm dosyayı yükleyipte sonrada çalmayalım? Ee, bu güzel bir soru. Hızlı cevap, gerçekte çok fazla ses verisine sahip olunur bir oyunda. Asıl Ogg dosya boyutu oldukça küçükse bile (Genellikle 1-3 MB civarında) Sen, bu ses verisinin sıkıştırıldığını aklından çıkarmamalısın. verinin sıkıştırılmış biçimini çalamazsın
. bir bufferda kullanılabilmeden önce O encode edilmeli ve OpenAL'in tanıdığı forma döndürülmeli. İşte bu bizim dosya streamleme nedenimizdir.

class ogg_stream
{
   
public:

       
void open(string path); // dosyaya handle elde et
       
void release();         // dosya handleyini serbest bırak
       
void display();         // Ogg’de bazı bilgileri göster
        
bool playback();        // Ogg streami çal
       
bool playing();         // source’nin çalındığını kontrol et
       
bool update();          // gerekliyse stream’i güncelle

   
protected:

       
bool stream(ALuint buffer);   // buffer ‘a yeniden yükle
       
void empty();                 // kuyruğu boşalt
       
void check();                 // OpenAL hata durumunu kontrol et
        string errorString(
int code); // hata kodunu stringe çevir

Bu, Ogg streamleme apimizin temeli olacak. public metotlar  Ogg'i çalacak birinin aslında sahip olmaya ihtiyaç duyduğu her şeydir. Protected metotlar, daha içsel prosedürlerdir (Hata kontrolu gibi). tüm fonksiyonlara girmeyeceğim. Açıklamalarımın size onların neyin nesi olduğu gibi  bazı fikirler verdiğine inanıyorum.

    private:

        FILE*           oggFile;      
// dosya handle
        OggVorbis_File  oggStream;    
// stream handle
        vorbis_info*    vorbisInfo;   
// bazı formatlı data
        vorbis_comment* vorbisComment;
// kullanıcı açıklamaları

        ALuint buffers[2];
// ön saf ve arka saf bufferları
        ALuint source;    
// ses source
        ALenum format;    
// internal format
};

Dikkat çekmek istediğim ilk şey, wav dosyalar için streamlemede her zaman kullandığımız 1'den daha ziyade 2 buffer'ı adamış olmamızdır. Bu, önemlidir. Bunu anlamak için, Ben,  OpenGL / DirectX'de çift tamponlama nasıl çalıştığı hakkında düşünmenizi istiyorum. herhangi görevde geride bir arka saf buffer  çizime hazırlanırken "Ekranda"  olan ise ön saf buffer vardır. Onlar sonra, değiş tokuş edilir. Arka saf buffer, ön saf olur ve terside doğru. tamamen aynı ilke, burada uygulanır. Çalınan bir buferr ile çalınmak için bekleyen bir başkası  vardır . buffer çalması bittiğinde sonraki başlar. Sonraki buffer çalınırken, İlk olan streamden yeni bir veri parçasıyla tekrar doldurulup çalma bittiğinde ilk çalıncak diye set edilir. Yine de karışık? daha çok ayrıntıda bunu sonra açıklayacağım.
'FILE*' e bakıp C++ kullanırken  neden C’e özgül dosya handleyini neden kullandığımızı düşündüğünü biliyorum. Ee, vorbisfile C++'den ziyade C'nin etrafında tasarlandı Bundan dolayı onların C dosya sistemini kullanması normaldir. bu mümkündür, Ve gerçekten oldukça kolaylık , fstream ile çalışmanın vorbisfile'de sağlanması. Bu kolaylık olmasına rağmen  onu kullanmak o kadar basit değildir.

void ogg_stream::open(string path)
{
   
int result;
   
   
if(!(oggFile = fopen(path.c_str(), "rb")))
       
throw string("Could not open Ogg file.");

   
if((result = ov_open(oggFile, &oggStream, NULL, 0)) < 0)
    {
        fclose(oggFile);

       
throw string("Could not open Ogg stream. ") + errorString(result);
    }

Demek istediğimi anladın? Eğer biz, fstreamı kullanmış olsaydık 'ov_open_callbacks' içinde birkaç yeni fonksiyon yaratmak zorunda olurduk . Bu, sizin için daha faydalı olabilir
 Eğer sanal dosya sistemi desteğine gereksinirseniz. 'ov_open' Fonksiyonu Ogg stream ile dosya handleyini bağlar. Şimdi  bu dosya handleyi stream'in kendinindir ki Kendiniz onla oynaşmazsınız.

    vorbisInfo = ov_info(&oggStream, -1);
    vorbisComment = ov_comment(&oggStream, -1);

   
if(vorbisInfo->channels == 1)
        format = AL_FORMAT_MONO16;
   
else
        format = AL_FORMAT_STEREO16;

Bu, dosyada bazı bilgileri kapar. OpenAL format enumeratorü Ogg'de kaç kanal olduğu temelinde çıkarsarız.

    alGenBuffers(2, buffers);
    check();
    alGenSources(1, &source);
    check();
   
    alSource3f(source, AL_POSITION,        0.0, 0.0, 0.0);
    alSource3f(source, AL_VELOCITY,        0.0, 0.0, 0.0);
    alSource3f(source, AL_DIRECTION,       0.0, 0.0, 0.0);
    alSourcef (source, AL_ROLLOFF_FACTOR,  0.0          );
    alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE      );
}

önceden çoğunu gördün. ön tanımlı değerlerin bir demetini set ederiz, pozisyon, hız, yön... Ama rolloff faktörü nedir? Bu, azaltmayla ilgilidir. sonraki bir makalede azaltımı anlatacağım Bundan dolayı ben, fazla derine girmeyeceğim, Ama ben, temelde onu açıklayacağım
. Rolloff faktörü, mesafe sebebiyle kuvvet zayıflamasını yönetir . onu  0'a set etmeyle onu kapatmış oluruz. Listener’ın çok uzakta olmasına rağmen Ogg kaynağı yine de duyalacak anlamındadır. Aynı mantık source'e uygulanır.

void ogg_stream::release()
{
    alSourceStop(source);
    empty();
    alDeleteSources(1, &source);
    check();
    alDeleteBuffers(1, buffers);
    check();

    ov_clear(&oggStream);
}

Kullanım sonu temizlik bu. source'İ durdururuz, hala Kuyrukta olan herhangi buffer varsa boşaltırız, Ve nesnelerimiz yok edilir. 'ov_clear' , dosya streamlemede tutulan handleyi  serbest bırakıp ayrıca bizim için handlleyi kapatacak .

void ogg_stream::display()
{
    cout
        << "version         " << vorbisInfo->version         << "\n"
        << "channels        " << vorbisInfo->channels        << "\n"
        << "rate (hz)       " << vorbisInfo->rate            << "\n"
        << "bitrate upper   " << vorbisInfo->bitrate_upper   << "\n"
        << "bitrate nominal " << vorbisInfo->bitrate_nominal << "\n"
        << "bitrate lower   " << vorbisInfo->bitrate_lower   << "\n"
        << "bitrate window  " << vorbisInfo->bitrate_window  << "\n"
        << "\n"
        << "vendor " << vorbisComment->vendor << "\n";
       
   
for(int i = 0; i < vorbisComment->comments; i++)
        cout << "   " << vorbisComment->user_comments[i] << "\n";
       
    cout << endl;
}

Biz, dosyada ekstra bilgileri görmek için bunu kullanabiliriz.

bool ogg_stream::playback()
{
   
if(playing())
       
return true;
       
   
if(!stream(buffers[0]))
       
return false;

   
if(!stream(buffers[1]))
       
return false;
   
    alSourceQueueBuffers(source, 2, buffers);
    alSourcePlay(source);
   
   
return true;
}

Bu, Ogg'i çalmaya başlatacak. Eğer Ogg hali hazırda çalıyorsa  O zaman, tekrar bunu yapmak için hiçbir sebep yoktur. Biz aynı şekilde, onların ilk veri setiyle bufferları ilklemeliyiz
. Biz sonra, onlar kuyrukta bekleriz ve onları çalmak için source söyleriz . Bu, bizim, 'alSourceQueueBuffers''ı kullandığımız ilk seferdir. Temel olarak yaptığı,  source çoklu bufferlaşır. Bu bufferlar, sırayla çalınacak . source kuyruğuyla beraber bunu daha sonra açıklayacağım. not geçeceğimiz bir şey: streamleme için bir source kullanırsanız 'alSourcei' kullanarak onu bir buffera asla bağlama, Her zaman 'alSourceQueueBuffers' daim kullan.

bool ogg_stream::playing()
{
    ALenum state;
   
    alGetSourcei(source, AL_SOURCE_STATE, &state);
   
   
return (state == AL_PLAYING);
}

Bu, source'nin durumunu kontrol etme işini basitleştirir.

bool ogg_stream::update()
{
   
int processed;
   
bool active = true;

    alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);

   
while(processed--)
    {
        ALuint buffer;
     
        alSourceUnqueueBuffers(source, 1, &buffer);
        check();

        active = stream(buffer);

        alSourceQueueBuffers(source, 1, &buffer);
        check();
    }

   
return active;
}

Kuyruğun, kısaca nasıl çalıştığı buradadır: bufferların bir 'Listesi' vardır. Bir buffer'ı kuyruktan aldığın zaman o ölür. bir buffer'ı kuyruğa aldığın zaman o arkaya sıraya konur. Olay bu. oldukça basit?
Bu, sınıfta önemli olan 2 metotdan ilkiydi. bu kod parçasında yaptığımız kontrol Herhangi bir buffer'ın hali hazırda çalınıp çalınmadığıdır. Öyleyse o zaman kuyruğun arkasına onların her birini almaya başlarız, Biz, stream'den veriyle bufferları tekrar doldururuz, Ve biz sonra, kuyruğa onları koymaya zorlarız ki onlar, çalınabilir. İnşallah Listener bizim bunu yaptığımız hakkında hiçbir fikre sahip olmayacak. o uzun devamlı müzik zinciri gibi çalmalı. Eğer stream çalma biterse 'stream' fonksiyonu aynı şekilde bize söyler. Bu flag fonksiyonun döndüğü zamanı bildirir.

bool ogg_stream::stream(ALuint buffer)
{
   
char data[BUFFER_SIZE];
   
int  size = 0;
   
int  section;
   
int  result;

   
while(size < BUFFER_SIZE)
    {
        result = ov_read(&oggStream, data + size, BUFFER_SIZE - size, 0, 2, 1, & section);
   
       
if(result > 0)
            size += result;
       
else
           
if(result < 0)
               
throw oggString(result);
           
else
               
break;
    }
   
   
if(size == 0)
       
return false;

    alBufferData(buffer, format, data, size, vorbisInfo->rate);
    check();

   
return false;
}

Buda sınıfın öteki önemli metodudur. Bu kısım Ogg bitstreamdan veriyle bufferları doldurur. Onun biraz kavraması daha zordur  çünkü tepeden tırnağa davranışı açıklanabilir değildir. 'ov_read',  yaptığını düşündüğünüz şeyi yapar; O, Ogg bitstreamdan veriyi okur
. Vorbisfile, tüm bitstream decodelemesini yapar, Bundan dolayı biz, ondan endişe duymak zorunda olmayız. Bu fonksiyon, bizim 'oggStream' yapımızıdecodelenmiş sesin yazılabildiği yer olarak bir data buffer, ve decodelemeyi istediğininz yığının boyutunu argüman olarak alır. En son 4 argüman senin gerçekten hakkında endişelenmek zorunda olmadığındır Ama ben, yine de açıklayacağım. Göreli olarak: ilki little endian (0) (önemli bitin en solda olduğu düzen) veya big endian (1) (önemli bitin en sağda olduğu düzen)’ı belirtir, ikincisi 8 bit (1) veya 16 bit (2) olarak data boyutu (bayt cinsli) belirtir, üçüncüsü datanın işaretsiz (0) veya işaretliliğini (1) belirtir, ve sonuncusu mevcut bitstream sayısını düzenler.
'ov_read' 'nin dönüş değeri ba şeyleri gösterir. Eğer sonuç değeri pozitifse o zaman, ne kadar verinin okunduğunu ifade eder. Bu, önemlidir çünkü 'ov_read' talep edilen bütün boyutu okumayabilir (misal dosyanın sonundadır ve Okumak için kalan hiçbir şey yoktur). her halükârda 'ov_read' sonucu karşı 'BUFFER_SIZE' i kullan. Eğer 'ov_read' 'ın sonucu negatif olursa o zaman bitstreamda bir hata olduğunu gösterir. Sonuc değeri bu durumda bir hata kodudur. Eğer sonuç sıfıra eşit olursa o zaman Çalmak için dosyada bırakılan hiçbir şey yoktur.
bu kodu karışıklaştıran döngüleme esnasıdır. Bu metot, modüler ve değiştirilebilir olmak için tasarlandı. istediğinize 'BUFFER_SIZE'i değiştirebilirsin ve O hala, çalışacak. Ama 'ov_read' 'da çoklu çağrılarla bufferın tam boyutunu doldurulup Her şeyin uygun şekilde düzenlendiğinden emin olunmalı. Bu metodun son parçası Ogg'nin kullandığı 'ov_read' 'den streamlediğimiz veriyle buffer id dolduran 'alBufferData' çağrısıdır. daha önce gösterdiğimiz 'format' ve 'VorbisInfo' datalarını kullanırız.

void ogg_stream::empty()
{
   
int queued;
   
    alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
   
   
while(queued--)
    {
        ALuint buffer;
   
        alSourceUnqueueBuffers(source, 1, &buffer);
        check();
    }
}

Bu metot,  source'de bekleyecek herhangi bir buffer'I kuyruğa alacak.

void ogg_stream::check()
{
   
int error = alGetError();

   
if(error != AL_NO_ERROR)
       
throw string("OpenAL error was raised.");
}
Bu, bizim hata kontrollerimiz için bazı yazımlardan kurtarır.

string ogg_stream::errorString(int code)
{
   
switch(code)
    {
       
case OV_EREAD:
           
return string("Read from media.");
       
case OV_ENOTVORBIS:
           
return string("Not Vorbis data.");
       
case OV_EVERSION:
            
return string("Vorbis version mismatch.");
       
case OV_EBADHEADER:
           
return string("Invalid Vorbis header.");
       
case OV_EFAULT:
           
return string("Internal logic fault (bug or heap/stack corruption.");
       
default:
            
return string("Unknown Ogg error.");
    }
}

Bu, hata mesajının stringleştirilmesini yapar böylece anlamlı şekilde konsoldan veya mesaj kutusundan veya herneydense okunabilir.

Kendi OggVorbis Player’ınızı yapma
Eğer şimdiye kadar benleysen o zaman işe yarar şekilde bunu anlamada hayli ciddi olmalısın. Endişelenme ! neredeyse işi bitiriyoruz. şimdi yapmamız gerekli tek şey, bir Ogg dosyasını çalmak için kullanılacak yeni bir sınıf tasarlamaktır. O, şuana kadara göre basit bir işlem. en zor bölümü yaptık. bir oyun döngüsünde bunu kullanacağınızı farz etmiyorum, Ama döngü tasarladığımda akılda onu tutacağım.

int main(int argc, char* argv[])
{
    ogg_stream ogg;

    alutInit(&argc, argv);

Bu,  hiç kafa patlatıcı değil.

    try
    {
       
if(argc < 2)
           
throw string("oggplayer *.ogg");
   
        ogg.open(argv[1]);

        ogg.display();
C++ kullanıyor olduğumuzdan dolayı aynı şekilde istisna yönetimi için try/catch/throw anahtar kelimelerini kullanacağız. Muhtemelen bu makalede kodun başından sonuna stringler fırlattırdığımı fark ettiniz.
Benim, burada yaptığım ilk şey, kullanıcının,  diziniyle dosyanın bizi sağladığından emin olma kontrolüdür. Eğer, programa hiçbir argüman geçilmemiş ise, herhangi şey yapmayız, böyle durumda basitçe kullanıcıya Ogg uzantısı gösteren küçük bir mesaj göstereceğiz. Çok bilgilendirici değil Ama bir konsol uygulamasında bu standart bir usluptur. Eğer programa bir argüman geçilmiş olsaydı o zaman, o dosyayı açmak için onu kullanabiliriz. Aynı zamanda Ogg dosyası bilgisini göstereceğiz.

        if(!ogg.playback())
           
throw string("Ogg refused to play.");
                   
       
while(ogg.update())
        {
           
if(!ogg.playing())
            {
               
if(!ogg.playback())
                    
throw string("Ogg abruptly stopped.");
               
else
                    cout << "Ogg stream was interrupted.\n";
            }
        }
                   
        cout << "Program normal termination.";
        cin.get();
    }
her zaman programın ana döngüsünün yazılan en eğlenceli kısım olduğu düşünürüm. Ogg'i çalarak başlarız. Bir Ogg, eğer 2 bufferla streamlemede yeterli veri yoksa Veya basitçe dosyayı okuyamazsa çalmayı reddedebilir (Diğer bir deyişle Ogg çokça küçüktür).
Program, 'update' metodu true döndürmeyi sürdürdüğü sürece devamlı olarak döngülenir, Ve başarılı bir şekilde, okuma yapılıp ses çalınabilidiği sürece true döndürmeyi sürdürecek . döngü içinde, Ogg'nin çalıyor olduğundan emin olacağız. Bu, onun, 'update' gibi aynı maksada hizmet ettiği düşünülebilir, Ama o hem de, sistemle yapmak zorunda olan bazı diğer meseleleri çözecek. Ben basit bir test için aynı anlı birçok diğer program çalışırken bu programı çalıştırdım. oggplayerin, nasıl tepki gösterecek olduğunu görmek için yaptığım bunda çok cpu zamanı yenip bitti. Mesaj göstermek için kesilmesi şaşırtabilir. Streamleme , harici processlerce kesilebilir. Bu bir hataya neden olmaz ama. Akılda bunu tut .
Eğer başka hiçbir şey sonra olmazsa, program küçük bir mesajla sizi bilgilendirerek normal olarak sonlanacak.

    catch(string error)
    {
        cout << error;
        cin.get();
    }

Fırlatılmış(throw) bir hata stringini yakalayıp (catch) programın neden sonlanmak zorunda olduğu hakkında bazı bilgiler gösteriliyor.

    ogg.release();
   
    alutExit();

   
return 0;
}

main'imizin sonu, yine kafa patlatıcı değil.

Sorabileceğiniz sorulara cevaplar

streamleme için bir tampondan fazlasını kullanabilir miyim?
Kısaca, evet. aynı anda source'de kuyrukta beklenen birçok buffer olabilir. Bunu yapmak da aslında, size daha iyi sonuçlar verebilir. Daha önce dediğim gibi , Her daim kuyrukta 2 bufferla olmalı , cpu meşgul (veya sistem yanıt vermediğinde), stream diğerini decodelemeden önce Kaynak aslında çalmayı bitirebilir. kuyrukta 3 veya hatta  4 buffera sahip olmak,  güncelleştirmeyi kaçırma olasılığıyla ilerde birazcık daha fazla alıkoyacak sizi.

ogg.update'i ne kadar sık çağırmalıyım?
Bu, birkaç şeye bağlı olarak değişecek. Eğer çabuk bir cevap istiyorsan, söyleyeyim, her nezaman istersen günceleyebilirsin, ama bu gerçekten gerekli değildir. Yeter ki source kuyruğun sonunda çalmayı bitirmeden önce güncellensin. Bunu etkileyecek olan en büyük faktörler, Kuyrukta tahsis edilmiş buffer boyutu ve bufferların sayısıdır. Eğer çalmaya hazır çok veriye sahipsen daha az güncelleştirme gerekli olacak.

Aynı anda bir Ogg'den fazlasını streamlemek güvenli midir?
Bu açık olmalı. Herhangi uç test yapmadım ama ben olamayacağını düşünmüyorum. Siz genellikle zaten birden çok streamlemeyi yapmak zorunda olmayacaksınız. Arka plan müziğini çalmak için bir tane ve oyun içi ara sıra olan karakter diyalogu için olacak, tabi ses efektlerinin çoğu streamlemenin can sıkmayacağı kadar kısadır. Source'lerinin çoğu,  onlara bağlanan sadece bir buffer'a sahip olur.

İsimler ne alaka?
"Ogg", Xiph.org'un ses, video ve metadata için konteyner biçimi ismidir. "Vorbis" , Ogg’deki konteynerlar için tasarlanmış özel bir ses sıkıştırma düzeninin adıdır. Sözcüklerin özel anlamlarına gelince ... Ee, anlatması daha bir zor. Terry Pratchett romanlarıyla bazı garip bağlar içerdiğini düşünüyorum. Detaylandırılamayacak kadar küçük bir sayfa burası.

Örnek programı çalıştırdığımda konsolda neden 'Oggplayer* .ogg' yazısı gösteriliyor?
Bir dosya adı belirtmek zorunluluğu var. Kolayca program üzerine bir Ogg dosyası sürükle bırak yapabilirsiniz ki bu pek güzelde işe yarar. Bununla birlikte örnekle gidecek bir Ogg dosyası sağlamadım. Kısmen birinin müziğini kullanmanın yasallığı kısmen dosya boyutunu azaltmak için. Eğer biri bir parça bağışlamayı istiyorsa (tabi ben onu beğenecem :) )  örnek dosyalarına onu ekleyebilirim. Ama lütfen telif haklı materyalı sunulmamış veya hip hop olmasın :).


Dev-C++ kaynak ve proje dosyalarını Yükle.
Visual C++ 6.0 kaynak ve proje dosyalarını - (TheCell tarafından port edilmiştir)
Bu dersin Delphi’e portunu yükle - (Sascha Willems, ve Peter Hine tarafından port edilmiştir)
Bu dersin Linux’e portunu yükle - (Lee Trager tarafından port edilmiştir)


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