Воспроизведение звука
Воспроизведение звука — еще одна ключевая составляющая программирования игр. Штатные функции SDL для проигрывания звука довольно запутанные. Поэтому мы будет разбираться в том, как проигрывать звуки при помощи библиотеки SDL_mixer
. SDL_mixer
— библиотека расширений, которая делает использование звука безумно простым делом. Скачать SDL_mixer
можно тут. Для того, чтобы установить ее просто следуйте инструкции. Ставится 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();
}
}