Ukážeme si způsob, jak snadno přehrát zvukové stopy WAVE souborů pomocí knihoven SDL a SDL_Mixer. Budeme upravovat celkovou hlasitost, panning (hlasitost levého a pravého kanálu) a na závěr si předvedeme jdenoduché využití pro 2D hry (posluchač X zdroje zvuku) na osách X a Y.

 

Úvod

SDL (Simple DirctMedia Layer) je multimediální knihovna, díky které můžeme, mimo jiné, přehrávat jednoduše zvuk. Tato knihovna obsahuje i grafické prostředky, práci s joypadem, časem a CD Rom.

Jelikož potřebujeme k přehrávání panning, budeme potřebovat i knihovnu SDL_mixer, která nám rozšířuje možnosti práce se zvukem.

 

Co je potřeba?

  • Základní znalost programovaní v jazyce C/C++.
  • Vhodný kompilátor (nejlépe vývojové prostředí MS Visual Studio).
  • Knihovny: windows.h  SDL.h  SDL_mixer.h  SDL.lib  SDL_mixer.lib  SDL.dll  SDL_mixer.dll  math.h (pro fci sqrt())

Inicializace SDL a SDL_mixer

if( SDL_Init(SDL_INIT_AUDIO) != 0 )
{
    printf("Nepodarilo se inicializovat SDL: %s\n", SDL_GetError());
    return 1;
}

Funkce SDL_init() je uplným základem SDL knihovny. Pomocí této funkce určíme s čím budeme v SDL operovat. To nastavíme pomocí flagů v jejím parametru. Například takto: 

SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO);

Při bezchybné inicializaci nám funkce vrátí hodnotu 0, v opačném případě -1. Ve chvíli kdy vznikne v SDL chyba, její odůvodnění získáme funkcí SDL_GetError()

Seznam flagů:

SDL_INIT_TIMER
SDL_INIT_AUDIO
SDL_INIT_VIDEO
SDL_INIT_CDROM
SDL_INIT_JOYSTICK
SDL_INIT_EVERYTHING
SDL_INIT_NOPARACHUTE
SDL_INIT_EVENTTHREAD

 

int audio_rate = 44100;                // Vzorkovací frekvence [Hz]
Uint16 audio_format = AUDIO_S16SYS;    // Zvukový formát
int audio_channels = 2;                // Zvukové kanály (1 - mono; 2 - stereo)
int audio_buffers = 1024;              // Velikost zvukového bufferu [byt]
if( Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0 ) 
{
    printf("Nepodarilo se inicializovat SDL_mixer: %s\n", Mix_GetError());
    return 1;
}

Mix_OpenAudio() nám inicializuje SDL_mixer. Za pomoci této funkce nastavíme vzorkovací frekvenci, formát, kanál a velikost bufferu. Funkce stejně jako SDL_init() vrací v korektním případě hodnotu 0, naopak -1.

Pro běžné, krátké, zvukové efekty postačí 1024 byt audio buffer. Při přehrávání delších záznamů je vhodnější zvolit větší buffer, avšak musíme dbát na to, že s větším bufferem trvá i delší dobu jeho naplnění a následné přehrání. Tím pak vzniká i delší reakce na změnu hlasitosti jednotlivých kanálů a mohlo by to dělat neplechu.

 

Mix_AllocateChannels( 10 );

Tento řádek slouží pro nastavení maximálního počtu přehrávaných zvuků (kanálů) v jeden okamžik. Ze základu je nastaveno 8.

 

Načtení zvukového souboru

Mix_Chunk *sound = NULL;
sound = Mix_LoadWAV("zvuk.wav");
if( sound == NULL )
{
    printf("Cteni ze souboru se nezdarilo\n");
    return 1;
}

Připravíme si pointer sound typu Mix_Chunk.

Funkce Mix_LoadWAV() přečte data souboru "zvuk.wav" a uloží adresu do pointeru sound

Pokud se čtení nezdařilo, pointer sound bude v hodnotě NULL.

 

Přehrávání

int channel = Mix_PlayChannelTimed( -1, sound, 1, -1);
if( channel == -1 )
{
    printf("Chyba přehrávání: %s\n", Mix_GetError() );
}

Funkce Mix_PlayChannelTimed() přehraje zvuk.
Jeho prvním parametrem je index kanálu. V případě, že nechceme řešit výběr kanálu, zadáme hodnotu -1 a při každém vyvolání této funkce se automaticky přiřadí první volný kanál a vrátí jej do proměnné channel v podobě integerového čísla. Pokud přesáhneme maxímální počet přehrávaných kanálů (který jsme si alokovali pomocí fce Mix_AllocateChannels()), vrátí nám hodnotu -1 a ponechá chybovou informaci v Mix_GetError().
Druhý argument je pointer našeho přednačteného zvukového souboru.
Třetí argument určuje počet opakování přehrání. Zvolením hodnoty 1 se nám zvuk přehraje 2x. Pokud chceme neustálé opakování (looping) zadáme hodnotu -1.
Čtvrtý argument nastaví dobu v milisekundách, po jejímž uplynutí se přehrávání zvuku zastaví. Hodnotou -1 nastavíme přehrátí celého zvuku.

 

Panning, aneb hlasitost levého a pravého kanálu

Mix_SetPanning( channel, 255, 255 );

U této funkce je prvním parametrem index přehrávaného kanálu, druhý nastavuje hlasitost levého kanálu a třetí parametr hlasitost pravého kanálu. Parametry hlasitostí jsou typu unsigned char, takže se zadávají od hodnoty 0-255, kde 0 je nejnižší a 255 nejvyšší hlasitost.

 

Ukončení práce

while( Mix_Playing(channel) );  // čekáme na konec přehrávání
Mix_FreeChunk( sound );         // uvolníme chunk sound
Mix_CloseAudio();               // ukončíme práci se zvukem
SDL_Quit();                     // ukončíme SDL

Funkce Mix_Playing() vrací hodnotu 1 v případě, že je zadaný kanál v jejím parametru přehráván. Pokud ne, vrací hodnotu 0. Zadáním hodnoty -1 do parametru funkce, vrátí počet přehrávaných zvuků.

Jelikož nechceme ukončit přehrávání dřív, než bude dohrán zvuk, dáme tuto funkci do smyčky, která se přeruší až po dohrání zvuku.
Pak následuje uvolnění paměti se zvukem, ukončení SDL_mixeru a samotného SDL.

 

Prostorové přehrávání v 2D prostoru (ukázka)

Jak jsem sliboval, ukážeme si, jak přehrávat zvuk v prostoru s určením pozice posluchače a zdroje zvuku.

Includujeme potřebné knihovny.

#include <Windows.h>
#include <SDL.h>
#include <SDL_mixer.h>
#include <math.h>

#pragma comment(lib,"SDL.lib")
#pragma comment(lib,"SDL_mixer.lib")

 

Inicializujeme SDL, SDL_mixer a nastavíme pozici a hlasitost přehrávání.

int main(int argc, char** argv[])
{
    char volume  = 100;                    // Nastavíme hlasitost přehrávání
    int listen_x = 1;                      // Nastavíme pozici posluchače na ose X
    int listen_y = 1;                      // Nastavíme pozici posluchače na ose Y

    int audio_rate = 44100;                // Vzorkovací frekvence [Hz]
    Uint16 audio_format = AUDIO_S16SYS;    // Zvukový formát
    int audio_channels = 2;                // Zvukové kanály (1 - mono; 2 - stereo)
    int audio_buffers = 1024;              // Velikost zvukového bufferu [byt]

    /* Inicializujeme SDL                               */
    /* Pokud vznikne chyba inicializace, ukončíme práci */
    if( SDL_Init(SDL_INIT_AUDIO) != 0 )    
    {
        printf("Nepodarilo se inicializovat SDL: %s\n", SDL_GetError());
        return 1;
    }
	
    /* Inicializujeme SDL_mixer                         */
    /* Pokud vznikne chyba inicializace, ukončíme práci */
    if( Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0 ) 
    {
        printf("Nepodarilo se inicializovat SDL_mixer: %s\n", Mix_GetError());
        return 1;
    }

    Mix_AllocateChannels( 1 );             // Alokujeme si paměť pro kanály

 

Načteme zvuk ze souboru a uložíme adresu do pointeru.

    Mix_Chunk *sound = NULL;
    sound = Mix_LoadWAV("zvuk.wav");
    if( sound == NULL )
    {
        printf("Cteni ze souboru se nezdarilo\n");
        return 1;
    }

 

Přehrajeme zvuk a do smyčky nastavíme hlasitost levého a pravého kanálu dle pozice kurzoru myši.

    int channel = Mix_PlayChannelTimed( -1, sound, -1, -1);

    while( !kbhit() ) // po stisku klávesy ukončíme aplikaci
    {
        // Získáme pozici kurzoru myšky //
        POINT p;
        GetCursorPos( &p );

        // Přepočítáme pozici kurzoru a posluchače //
        int xx = p.x - listen_x;
        int yy = p.y - listen_y;

        // Nastavíme dosah zvuku //
        float len = 1000;

        // Zjistíme vzdálenost kurzoru od posluchače //
        // a přepočítáme ji do rozsahu 0-1.          //
        // Tím zajistíme postupné zeslabení zvuku v  //
        // závislosti na vzdálenosti.                //
        float dist = max( 0, 1-(sqrt( (float)(xx*xx + yy*yy) )/len));

        // Získáme rozptyl zvuku na druhý kanál podle pozice. //
        // Hodnota 400 určuje rozptyl.                        //
        // Čím větší hodnota, tím větší rozptyl               //
        float pan = ((float)xx/400)*255;

        // Přepočteme hlasitost levého a pravého kanálu.      //
        float L = 255-min(255,max(0,pan));
        float R = 255-min(255,max(0,-pan));

        // Přepočítáme hlasitost na rozsah 0-1 //
        float vol = volume/100;

        // Nastavíme přehrávanému zvuku panning na           //
        // levý a pravý kanál + zajistíme globální hlasitost //
        Mix_SetPanning( channel, L*dist*vol, R*dist*vol );
    }

 

Ukončíme celý proces

    Mix_FreeChunk( sound );         // uvolníme chunk sound
    Mix_CloseAudio();               // ukončíme práci se zvukem
    SDL_Quit();                     // ukončíme SDL
	
    return 0;
}

 

Přidat komentář

Bezpečnostní kód
Obnovit