Zenedith's dev blog

Dałem się namówić.., szatanowi chyba..

Play Music : Vorbis(Ogg) + OpenAL

Postanowiłem napisać krótki wpis na temat odtwarzania dźwięku z poziomu kodu aplikacji. Ponieważ zależało mi na darmowych najprostszych rozwiązaniach, bez zbędnej „tony” innych „bajerów” (SDL_Mixer), wybrałem kombinację VorbisFile (biblioteka libvorbis) wymagające biblioteki libogg które można pobrać z jednego miejsca tutaj oraz OpenAL.

Instalacja bibliotek nie powinna sprawić nikomu problemu – ściągamy bibliotekę libogg-x.y.z.zip, rozpakowujemy, otwieramy plik solucji w Visual Studio, kompilujemy wersje bibliotek które chcemy później użyć (ja poprzestałem na wersjach static), zgrywamy lib’y do jednego zbiorczego katalogu a include do drugiego, które następnie dodajemy w opcjach Visual Studio VC++ Directories. Podobnie postępujemy z libvorbis. Wszystkie lib’y mam w jednym katalogu lib, a include w jednym katalogu include.
Pozostaje jeszcze ściągnąć ze strony OpenAL Creativelabs plik SDK OpenAL Installer for Windows (oalins), zainstalować i dodać do ścieżek lib\ i include\ Visual Studio.
Na końcu prezentuję parę screenów które mogą pomóc to o czym mówię.

Znalazłem na pierwszy rzut oka ciekawy tutorial na ten temat jednakże jak się po chwili okazało, nie jest on szczególnie aktualny. Pokazuje nam to kompilator wyrzucając np. taki błąd:

error C3861: ‚alutInit’: identifier not found

Postanowiłem sprawdzić jakie zmiany zaszły w SDK, przeglądając przykłady z tego najnowszego.  W katalogu OpenAL\SDK\samples\playoggvorbis\ znalazłem dokładnie taki przykład, jakiego potrzebowałem. Niestety, cały ten Framework ma dość duże możliwości, co trochę zaciemnia obraz najprostszej czynności jaką jest odegranie pliku .ogg.

W celu rozwiązania problemu trzeba się posłużyć metodami z nagłówka alc.h, ponieważ nagłówka alut.h już nie ma.

Inicjalizacja przebiega teraz w ten sposób, że musimy znaleźć device’a i go wybrać z listy (gdy mamy więcej niż jedną kartę dźwiękową lub po prostu skorzystać z urządzenia domyśnego w systemie).

Poniżej prezentuję kompletny kod do odtworzenia pliku *.ogg za pomocą OpenAL – nazwę pliku podajemy jako parametr do aplikacji. Kod jest przeróbką kodu autora Anthony „TangentZ” Yuen, ze wspomnianego wyżej tutorial’a.

#include <al.h>
#include <alc.h>
#include <vorbis/vorbisfile.h>
#include <stdlib.h>
#include <cstdio>
#include <iostream>
#include <vector>

//#include <windows.h>
#define BUFFER_SIZE     32768       // 32 KB buffers

using namespace std;

// This function loads a .ogg file into a memory buffer and returns
// the format and frequency.
void LoadOGG(char *fileName, vector<char> &buffer, ALenum &format, ALsizei &freq)
    {
    int endian = 0;                         // 0 for Little-Endian, 1 for Big-Endian
    int bitStream;
    long bytes;
    char array[BUFFER_SIZE];                // Local fixed size array
    FILE *f;

    // Open for binary reading
    f = fopen(fileName, "rb");

    if (f == NULL)
        {
        cerr << "Cannot open " << fileName << " for reading..." << endl;
        exit(-1);
        }
    // end if

    vorbis_info *pInfo;
    OggVorbis_File oggFile;

    // Try opening the given file
    if (ov_open(f, &oggFile, NULL, 0) != 0)
        {
        cerr << "Error opening " << fileName << " for decoding..." << endl;
        exit(-1);
        }
    // end if

    // Get some information about the OGG file
    pInfo = ov_info(&oggFile, -1);

    // Check the number of channels... always use 16-bit samples
    if (pInfo->channels == 1)
        format = AL_FORMAT_MONO16;
    else
        format = AL_FORMAT_STEREO16;
    // end if

    // The frequency of the sampling rate
    freq = pInfo->rate;

    // Keep reading until all is read
    do
        {
        // Read up to a buffer's worth of decoded sound data
        bytes = ov_read(&oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);

        if (bytes < 0)
            {
            ov_clear(&oggFile);
            cerr << "Error decoding " << fileName << "..." << endl;
            exit(-1);
            }
        // end if

        // Append to end of buffer
        buffer.insert(buffer.end(), array, array + bytes);
        }
    while (bytes > 0);

    // Clean up!
    ov_clear(&oggFile);
    }
// end of LoadOGG

int main(int argc, char *argv[])
    {
    ALint state;                            // The state of the sound source
    ALuint bufferID;                        // The OpenAL sound buffer ID
    ALuint sourceID;                        // The OpenAL sound source
    ALenum format;                          // The sound data format
    ALsizei freq;                           // The frequency of the sound data
    vector<char> bufferData;                // The sound buffer data from file

    // Make sure there is a file name
    if (argc < 2)
        {
        cerr << "Syntax: " << argv&#91;0&#93; << " OGGFile" << endl;
        return -1;
        }

    // Initialize the OpenAL library
    //alutInit(&argc, argv);

    //ALDEVICEINFO	ALDeviceInfo;
    char *devices;
    int index;
    const char *defaultDeviceName;
    const char *actualDeviceName;

    if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) {
        devices = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
        defaultDeviceName = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);

        //OutputDebugString(defaultDeviceName);
    }

    ALCcontext *pContext = NULL;
    ALCdevice *pDevice = NULL;

    pDevice = alcOpenDevice(defaultDeviceName);
    if (pDevice)
    {
        pContext = alcCreateContext(pDevice, NULL);
        if (pContext)
        {
            //OutputDebugString("\nOpened Device\n");
            //OutputDebugString(alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
            alcMakeContextCurrent(pContext);

        }
        else
        {
            alcCloseDevice(pDevice);
        }
    }

    // Create sound buffer and source
    alGenBuffers(1, &bufferID);
    alGenSources(1, &sourceID);

    // Set the source and listener to the same location
    alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
    alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f);

    // Load the OGG file into memory
    LoadOGG(argv&#91;1&#93;, bufferData, format, freq);

    // Upload sound data to buffer
    alBufferData(bufferID, format, &bufferData&#91;0&#93;, static_cast<ALsizei>(bufferData.size()), freq);

    // Attach sound buffer to source
    alSourcei(sourceID, AL_BUFFER, bufferID);

    // Finally, play the sound!!!
    alSourcePlay(sourceID);

    // This is a busy wait loop but should be good enough for example purpose
    do
        {
        // Query the state of the souce
        alGetSourcei(sourceID, AL_SOURCE_STATE, &state);
        }
    while (state != AL_STOPPED);

    // Clean up sound buffer and source
    alDeleteBuffers(1, &bufferID);
    alDeleteSources(1, &sourceID);

    // Clean up the OpenAL library
    alcMakeContextCurrent(NULL);
    alcDestroyContext(pContext);
    alcCloseDevice(pDevice);

    return 0;
    }
// end of main
vc8_include_red

Dodanie ścieżek include od podanych bibliotek

vc8_libs_red

Dodanie ścieżek do lib

libs_include_openal_red

Przykładowa struktura zainstalowanych bibliotek

Reklamy

28 Sierpień, 2008 - Posted by | cpp, engine |

Brak komentarzy.

Skomentuj

Proszę zalogować się jedną z tych metod aby dodawać swoje komentarze:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s

%d blogerów lubi to: