Ссылка на проект занятия (lesson 11.flowballs.zip): https://github.com/selfedu-rus/pygame
На этом занятии
мы с вами рассмотрим работу со звуком. В библиотеке Pygame для этого
имеются два модуля:
-
pygame.mixer
– для работы со звуковыми эффектами;
-
pygame.mixer.music
– для добавления фоновой музыки.
Полная их
документация доступна по адресам:
https://www.pygame.org/docs/ref/mixer.html
https://www.pygame.org/docs/ref/music.html
Давайте для
начала разберемся, как использовать эти модули и какие наиболее часто
используемые методы они содержат. Начнем с модуля pygame.mixer.music.
Этот модуль
поддерживает основные звуковые форматы:
mp3,
ogg, wav
и загружает их с
помощью функции load:
import pygame
pygame.init()
pygame.mixer.music.load("sounds/bird.mp3")
W, H = 500, 300
sc = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()
FPS = 60
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
clock.tick(FPS)
После успешной
загрузки мы можем воспроизвести этот файл с помощью функции
play(loops=0,
start=0.0, fade_ms = 0)
-
loops – число повторений
(0 – проигрывать один раз, 1 – два раза и т.д, -1 – бесконечное повторение);
-
start – начальное
время проигрывания файла (в секундах);
-
fade_ms – затухание
звука при окончании проигрывания (в мс).
Например,
запустим фоновую музыку с бесконечным повторением:
pygame.mixer.music.play(-1)
Добавим
возможность останавливать проигрывание при нажатии на клавишу пробел:
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
flPause = not flPause
if flPause:
pygame.mixer.music.pause()
else:
pygame.mixer.music.unpause()
Смотрите, здесь
используются две функции:
-
pause() – поставить
воспроизведение на паузу;
-
unpause() – продолжить
воспроизведения с места паузы.
Соответственно,
у нас при изменении флага flPause воспроизведение то ставится на
паузу, то снимается с паузы. Начальное значение этого флага определим как False:
Если нам нужно
остановить воспроизведение, то используется метод:
pygame.mixer.music.stop()
а для
воспроизведения с начала метод:
pygame.mixer.music.rewind()
Также часто
используются методы:
-
set_volume(volume)
– установить уровень громкости (volume – вещественное значение от 0 до
1);
-
get_volume()
– получить текущее значение уровня громкости.
Например,
сделаем, чтобы при нажатии на курсорные клавиши влево/вправо звук уменьшался и
увеличивался:
elif event.key == pygame.K_LEFT:
vol -= 0.1
pygame.mixer.music.set_volume(vol)
print( pygame.mixer.music.get_volume() )
elif event.key == pygame.K_RIGHT:
vol += 0.1
pygame.mixer.music.set_volume(vol)
print( pygame.mixer.music.get_volume() )
А сам параметр vol изначально
установим в 1.0:
По аналогии
используются и все остальные функции модуля music.
Модуль pygame.mixer
Теперь
рассмотрим работу модуля pygame.mixer. Он служит для работы со звуковыми
эффектами, например, выдавать звук при столкновениях, ловле профитов,
начисления очков и т.п. Данный модуль поддерживает многоканальный звук, т.е.
одновременное воспроизведение нескольких звуковых дорожек.
Первое что нужно
сделать, это проинициализировать этот модуль. Для этого у него есть две
функции:
init(frequency=44100,
size=-16, channels=2, buffer=512, devicename=None,
allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE)
и
pre_init(frequency=44100,
size=-16, channels=2, buffer=512, devicename=None)
Что они делают,
как и когда их вызывать? Очевидно, что они нужны для тонкой настройки миксера в
нашем приложении. Названия параметров говорят сами за себя:
-
frequency – частота
воспроизведения звуковых файлов;
-
size – число бит для
представления аудио данных (знак минус говорит, что используются знаковые
числа);
-
channels – число
каналов;
-
buffer – размер буфера
(в байтах);
-
allowedchanges –
дополнительные флаговые настройки.
Функция init вызывается
автоматически при инициализации Pygame:
Но с аргументами
по умолчанию. Если нужно поменять эти параметры, то следует до pygame.init вызвать метод pygame.pre_init() с нужным
набором параметров. Мало того, как мы увидим, вызов pre_init устраняет один
из неприятных эффектов – задержку в воспроизведении звуков.
Итак, у миксера
также есть похожий набор функций для останова и пауз:
-
stop()
– остановить вопроизведение;
-
pause()
– пауза воспроизведения;
-
unpause()
– снятие с паузы.
Но вот загрузка
и воспроизведение звуковых файлов выполняется немного по другому – с помощью
класса:
pygame.mixer.Sound(filename)
Здесь filename – это звуковой
файл в формате
wav или ogg
Обратите
внимание, класс Sound не поддерживает файлы в формате mp3. Итак, чтобы
загрузить какой-либо звуковой эффект, достаточно выполнить вот такую строчку:
s = pygame.mixer.Sound("sounds/catch.ogg")
И, далее, уже
через переменную s можем работать с воспроизведение данного
эффекта. Класс Sound поддерживает такие основные методы:
-
play(loops=0, maxtime=0, fade_ms=0) –
воспроизведение звука;
-
stop()
– останов воспроизведения;
-
set_volume(value)
– настройка громкости звучания;
-
get_volume()
– возвращает текущее значение громкости (число от 0 до 1).
Например,
сделаем, чтобы при нажатии на клавишу Enter звучал файл catch.ogg:
elif event.key == pygame.K_RETURN:
s.play()
Однако,
смотрите, нажимая клавишу, звук появляется с задержкой. Это из-за того, что
нужно выполнить команду pre_init() миксера до
инициализации самого Pygame:
pygame.mixer.pre_init(44100, -16, 1, 512) # важно вызвать до pygame.init()
Теперь, при
воспроизведении звуковых эффектов задержек не будет.
Также вы можете
заметить, что класс Sound не содержит методов для пауз. Дело в
том, что весь этот функционал выносится на уровень канала или миксера в целом.
Что это за каналы? Смотрите, когда мы запускаем воспроизведение из класса Sound, то
автоматически создается канал, в котором происходит обработка звука. И уже на уровне
канала существуют методы для пауз, остановок, затухания звучания и т.п.
Это сделано для
возможности одновременного воспроизведения нескольких звуковых дорожек: каждый
звук работает в своем отдельном канале. А для получения ссылки на канал
достаточно записать команду:
То есть, метод play возвращает
ссылку на канал, в котором происходит воспроизведение. И далее, уже через
переменную ch можно вызывать
методы канала, например:
Если же мы хотим
поставить на паузу все каналы, то следует вызвать такую же функцию на уровне
всего микшера:
По аналогии
работают остальные методы и функции микшера.
Добавление звуковых эффектов в игру
Теперь, когда мы
в целом разобрались с работой звука в Pygame, давайте
добавим звуковые эффекты в нашу игру с шариками.
Смотрите, здесь
вначале идет инициализация микшера:
pygame.mixer.pre_init(44100, -16, 1, 512) # важно прописать до pygame.init()
так, чтобы не
было задержек при воспроизведения звука.
Далее, мы
загружаем и проигрываем фоновый звук, зациклив воспроизведение:
pygame.mixer.music.load('sounds/bird.mp3')
pygame.mixer.music.play(-1)
Затем, формируем
звуковой эффект для ловли шара:
s_catch = pygame.mixer.Sound('sounds/catch.ogg')
И в функции collideBalls
проигрываем этот звук, если шар попадает в телегу:
def collideBalls():
global game_score
for ball in balls:
if t_rect.collidepoint(ball.rect.center):
s_catch.play()
game_score += ball.score
ball.kill()
Запускаем игру и
теперь у нас все работает со звуковыми эффектами. По аналогии можно добавить и
другие звуки, но это вы уже сможете сделать самостоятельно. Ссылка на эту
программу в начале страницы и каждый из вас сможет внимательно ее изучить и
изменять по своему усмотрению.