Воспроизведение звука — еще одна ключевая составляющая программирования игр. Штатные функции SDL для проигрывания звука довольно запутанные. Поэтому мы будет разбираться в том, как проигрывать звуки при помощи библиотеки `SDL_mixer`. `SDL_mixer` — библиотека расширений, которая делает использование звука безумно простым делом. Скачать `SDL_mixer` можно [тут](http://www.libsdl.org/projects/SDL_mixer/). Для того, чтобы установить ее просто следуйте [инструкции](http://tatrix.org/sdl-tutorial/3/). Ставится `SDL_mixer` так же просто, как и `SDL_image`: просто замените в тексте инструкции `SDL_image` на `SDL_mixer` Этот туториал раскрывает основы проигрыванию музыки и звуков при помощи `SDL_mixer` на примере "музыки", которую я создал барабаня по моему монитору.
//Музыка, которую будем проигрывать
Mix_Music *music = NULL;
//Звуки, которые будут использоваться
Mix_Chunk *scratch = NULL;
Mix_Chunk *high = NULL;
Mix_Chunk *med = NULL;
Mix_Chunk *low = NULL;

Здесь мы можем видеть новые типы данных, с которыми мы будем работать.Mix_Music тип данные который мы используем для музыки, и Mix_Chunk для звука соответственно.

bool init() {
    //Инициализировать все подсистемы SDL
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) {
        return false;
    }
    //Подготовить экран
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT,
        SCREEN_BPP, SDL_SWSURFACE );
    //Если при подготовке экрана произошла ошибка
    if( screen == NULL ) {
        return false;
    }
    //Инициализировать SDL_mixer
    if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ) {
        return false;
    }
    //Установить заголовок окна
    SDL_WM_SetCaption( "Monitor Music", NULL );
    //Если все прошло хорошо
    return true;
}

В функции инициализации мы вызываем Mix_OpenAudio() для инициализации аудио функций SDL_mixer Первый аргумент Mix_OpenAudio() это используемая частота звука, в данном случае равная 22050, что является рекомендуемым значением. Второй аргумент это формат звука, который мы выставим в значение по умолчанию. Третий аргумент — сколько использовать каналов. Мы задаем его равным двум, чтобы получить стерео звук. Если бы мы передали единицу, получился бы моно звук. Последний аргумент — размер сэмпла, в данном случае 4096. Если вы используете OGG, MOD или другие форматы, отличные от WAV, взгляните на Mix_Init() для инициализации декодеров и Mix_Quit() для их закрытия. Мы будем использовать только WAV файлы, так что не будем писать код для чего-то, чем мы не будем пользоваться.

{
    //Загрузить фоновое изображение
    background = load_image( "background.png" );

    //Открыть файл шрифта
    font = TTF_OpenFont( "lazy.ttf", 30 );

    //Если не загрузился фон
    if( background == NULL )
    {
        return false;    
    }

    //Если не загрузился шрифт
    if( font == NULL )
    {
        return false;
    }

    //Загружаем музыку
    music = Mix_LoadMUS( "beat.wav" );

    //Если не получилось
    if( music == NULL )
    {
        return false;    
    }

    //Загружаем звуковые эффекты
    scratch = Mix_LoadWAV( "scratch.wav" );
    high = Mix_LoadWAV( "high.wav" );
    med = Mix_LoadWAV( "medium.wav" );
    low = Mix_LoadWAV( "low.wav" );

    //Если что-то пошло не так
    if( ( scratch == NULL ) || ( high == NULL ) || ( med == NULL ) || ( low == NULL ) )
    {
        return false;    
    }

    //Все прошло удачно
    return true;    
}

Тут мы видим нашу функцию загрузки. Для загрузки музыки мы используем Mix_LoadMUS(). Mix_LoadMUS() принимает имя файла с музыкой и возвращает соответствующие данные или NULL в случае ошибки. Для загрузки звуковых эффектов мы применяем Mix_LoadWAV(). Она работает аналогично, возвращая Mix_Chunk в случае успеха и NULL в противном случае.

void clean_up()
{
    //Освобождаем поверхность фона
    SDL_FreeSurface( background );

    //Освобождаем звуковые эффекты
    Mix_FreeChunk( scratch );
    Mix_FreeChunk( high );
    Mix_FreeChunk( med );
    Mix_FreeChunk( low );

    //Освобождаем музыку
    Mix_FreeMusic( music );

    //Закрывает шрифт
    TTF_CloseFont( font );

    //Закрываем SDL_mixer
    Mix_CloseAudio();

    //Закрываем SDL_ttf
    TTF_Quit();

    //Закрываем SDL
    SDL_Quit();
}

В функции очистки мы вызываем Mix_FreeChunk(), чтобы избавится от загруженных звуковых эффектов и Mix_FreeMusic(), чтобы освободить ресурсы занятые музыкой. После того как мы закончили использовать SDL_mixer вызывается Mix_CloseAudio.

    //Пока пользователь не вышел
    while( quit == false )
    {
        //Пока есть события для обработки
        while( SDL_PollEvent( &event ) )
        {
            //Если нажали клавишу
            if( event.type == SDL_KEYDOWN )
            {

В функции main, после инициализации, загрузки файлов и фона, и после того, как фон и сообщения были отрисованы, мы входим в наш главный цикл. После чего начинаем обрабатывать события, начиная с нажатий на клавиши.

                //Если нажали 1
                if( event.key.keysym.sym == SDLK_1 )
                {
                    //Проиграть эффект скрипа
                    if( Mix_PlayChannel( -1, scratch, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }
                //Если нажали 2
                else if( event.key.keysym.sym == SDLK_2 )
                {
                    //Проиграть звук удара высокой частоты
                    if( Mix_PlayChannel( -1, high, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }
                //Если нажали 3
                else if( event.key.keysym.sym == SDLK_3 )
                {
                    //Проиграть звук удара средней частоты
                    if( Mix_PlayChannel( -1, med, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }
                //Если нажали 4
                else if( event.key.keysym.sym == SDLK_4 )
                {
                    //Проиграть звук удара низкой частоты
                    if( Mix_PlayChannel( -1, low, 0 ) == -1 )
                    {
                        return 1;    
                    }
                }

При проверки нажатий на клавиши, сначала мы проверяем были ли нажаты 1, 2, 3 или 4. Эти клавиши проигрывают звуковые эффекты. Если одна из этих клавиш была нажата, мы вызываем Mix_PlayChannel(), чтобы проиграть звук, ассоциированный с данной клавишей. Первый аргумент Mix_PlayChannel() это канал, в который нужно проиграть звук. Так как мы передаем -1 Mix_PlayChannel() просто берет первый доступный канал и проигрывает звук. Второй аргумент это Mix_Chunk, который нужно проиграть. Третий — сколько раз нужно повторить проигрывание. В случае если он равен 0, звук будет проигран единожды. В случае проблем с проигрыванием звука, Mix_PlayChannel() возвращает -1.

                //Если нажали 9
                else if( event.key.keysym.sym == SDLK_9 )
                {
                    //Если музыка не играет
                    if( Mix_PlayingMusic() == 0 )
                    {
                        //Запускаем проигрываение музыки
                        if( Mix_PlayMusic( music, -1 ) == -1 )
                        {
                            return 1;
                        }    
                    }

Дальше мы обрабатываем нажатие клавиши 9, которая используется для проигрывания или приостановки музыки. Сначала мы проверяем, не играет ли уже музыка при помощи Mix_PlayingMusic(). Если нет, мы вызываем Mix_PlayMusic для запуска проигрывания. Первый аргумент Mix_PlayMusic это музыка, которые мы собираемся проигрывать. Второй — сколько раз ее повторять. В нашем случае, -1 означает играть до тех пор, пока проигрывание не будет остановлено вручную. В случае проблем с проигрыванием музыки, Mix_PlayMusic() возвращает -1.

                    //Если музыка играет
                    else
                    {
                        //Если музыка на паузе
                        if( Mix_PausedMusic() == 1 )
                        {
                            //Продолжить играть
                            Mix_ResumeMusic();
                        }
                        //Если музыка играет
                        else
                        {
                            //Приостановить проигрывание
                            Mix_PauseMusic();
                        }
                    }
                }

Теперь, если музыка играла и пользователь нажимает 9, мы либо приостанавливаем либо возобновляем проигрывание. Сначала мы проверяем на паузе ли музыка при помощи Mix_PausedMusic(). Если это так, то мы возобновляем проигрываение вызывая Mix_ResumeMusic(). В противном случае мы приостанавливаем ее при помощи Mix_PauseMusic()

                //Если нажали 0
                else if( event.key.keysym.sym == SDLK_0 )
                {
                    //Остановить музыку
                    Mix_HaltMusic();
                }
            }

В конце концов, мы проверяем не нажал ли пользователь 0. И в этом случае останавливаем проигрывание музыки вызовом Mix_HaltMusic()

Скачать исходники и материалы