12: I SUONI

USARE I SUONI

Vediamo adesso come utilizzare i files sonori. Dobbiamo per prima cosa riflettere sul fatto che il suono è usato nei videogiochi in due modi diversi:

Anche riguardo ai files sonori è necessario conoscere qualche nozione tecnica; vediamone le tipologie:

.wav Sono files che contengono suoni registrati da un microfono e poi digitalizzati (cioè convertiti in una serie di bytes). Possono contenere quindi suoni realistici come voci, veri strumenti musicali, musica orchestrale, ma hanno il problema di occupare molta memoria perchè non sono compressi. In genere vanno bene per gli effetti (suoni brevi) ma non per la colonna sonora.
.mp3 E' il formato attualmente più usato per la musica perchè produce una buona qualità sonora con una notevole compressione dei files. Il formato .mp3 è però legato ad alcuni brevetti e così di solito per riprodurli da pygame è necessario installare un altro programma (codec). Dovreste fare perciò delle prove per vedere se il vostro computer li suona.
.ogg E' un formato meno diffuso dell'.mp3 ma molto simile e senza nessuna limitazione. Questi files sono supportati da pygame.
.mid Sono files completamente diversi. Un file .mid non contiene musica digitalizzata, ma una specie di "spartito" che viene suonato dal sintetizzatore MIDI del sistema operativo. In questo modo un file molto piccolo può contenere musiche anche lunghe, ma naturalmente non realistiche: l'effetto è simile a quello dei vecchi videogiochi. Vanno quindi benissimo per la colonna sonora (a patto di non avere troppe pretese) ma non per gli effetti.

In pygame le funzioni che si occupano di gestire i suoni sono raggruppate nel sottomodulo mixer.

L'OGGETTO Sound

Anche gli effetti sonori devono essere caricati in memoria a partire da un file. Le cose sono però un po' differenti rispetto alle immagini, perchè per i suoni esiste in pygame un oggetto apposito chiamato Sound, definito nel sottomodulo mixer. Quindi per caricare un suono dovremo creare un oggetto Sound tramite il costruttore ed assegnarlo ad una variabile. La sintassi, per fortuna, è simile a quella per caricare le immagini:

beep = pygame.mixer.Sound("nome_del_file")

assegnerà alla variabile beep il suono caricato dal file. Una volta assegnato il suono alla variabile, potremo riprodurlo con il metodo play() (che quindi va chiamato così: beep.play() senza più indicare i nomi dei moduli).

Un oggetto Sound può caricare i files .wav e .ogg. Anche per i files sonori sorge il problema di indicare il percorso quando il file non è nella stessa cartella del programma: adotteremo la stessa tecnica che abbiamo visto qui per i files grafici. Nella cartella Effects trovate alcune sottocartelle con vari files di effetti sonori; se non l'avete già fatto vi invito nuovamente a leggere l'approfondimento che vi spiega dove potete cercare questi files e contiene anche le informazioni di Copyright, con il nome dell'autore e il link originale di ogni file.

Riprendiamo il programma due_quadrati.py (qui) che scriveva nella finestra di IDLE quando cliccavamo su un quadrato e modifichiamolo in modo che emetta dei suoni. Dobbiamo caricare i due files "boing.wav" e "squeak2.wav" della cartella Effects.


import pygame
from pygame.locals import *
from os.path import join

# inizializzazione
pygame.init()
screen = pygame.display.set_mode((800, 600))

# creiamo la Surface surf1, la coloriamo di rosso e la posizioniamo sullo schermo
surf1 = pygame.Surface((200, 200))
surf1.fill("red")
rect1 = surf1.get_rect()
rect1.topleft = (50, 50)
screen.blit(surf1, rect1)

# stessa cosa con surf2 (blu)
surf2 = pygame.Surface((100, 100))
surf2.fill("blue")
rect2 = surf2.get_rect()
rect2.topleft = rect1.topright
screen.blit(surf2, rect2)

# ora creiamo i due suoni
sound1 = pygame.mixer.Sound(join("Effects", "boing.wav"))
sound2 = pygame.mixer.Sound(join("Effects", "squeak2.wav"))

# aggiorniamo lo schermo
pygame.display.flip()

# ciclo principale
done = False
while not done:
    for ev in pygame.event.get():
        # se l'evento è la fine del programma esce
        if ev.type == QUIT:
            done = True
        # se l'evento e' un click ...
        elif ev.type == MOUSEBUTTONDOWN:
            click = ev.pos
            if rect1.collidepoint(click):
                sound1.play()
            elif rect2.collidepoint(click):
                sound2.play()
				
# fine del ciclo e termine del programma
pygame.quit()

Come vedete, rispetto al vecchio programma, abbiamo solo aggiunto le righe #24 e #25, in cui carichiamo i files e li assegnamo alle rispettive variabili, ed abbiamo sostituito le vecchie print() con le istruzioni play() in #41 e #43.

NUOVO PROGRAMMA: panda_suono.py
ESERCIZIO 12.1: Riprendete il programma panda.py (visto qui) e salvatelo con il nuovo nome, caricate uno dei suoni che abbiamo visto e fate in modo che quando il panda rimbalza il programma emetta un suono (potete scegliere voi quale file usare).
SOLUZIONI

Qualche volta possiamo avere bisogno di effetti che si ripetano più volte (ad esempio una sirena della polizia); a questo scopo il metodo play() ha un parametro opzionale che indica quante volte il suono deve essere ripetuto (dopo la prima volta). Quindi se snd è una variabile di tipo Sound, possiamo scrivere snd.play(5). Questo ripeterà il suono 6 volte (la prima più 5 ripetizioni). Invece scrivendo snd.play(-1) ripeteremo il suono all'infinito, fino a quando il programma non termina.

E se volessimo fermarlo? Niente paura, l'oggetto Sound ha anche altri metodi utili, vediamone quelli più utilizzati:

Metodo Esempio Significato
stop() snd.stop() Ferma immediatamente il suono
fadeout() snd.fadeout(5000) Esegue una dissolvenza diminuendo gradatamente il volume fino a 0. Il parametro indica il numero di millisecondi (quindi 5000 = 5 secondi)
set_volume() snd.set_volume(0.6) Aggiusta il volume; il parametro è un numero decimale da 0 (silenzio) a 1 (massimo). Quando la usate il suono avrà sempre lo stesso volume finchè non lo cambate

LA COLONNA SONORA

Oltre ai file caricati in memoria, pygame può anche suonare files sonori in streaming (cioè caricando di volta in volta solo la parte che sta suonando in quel momento). Come saprete questa tecnica è nata per vedere filmati e musica in rete, in modo da non dover ricevere tutto il file prima di cominciare a suonare. Notate che, mentre per gli effetti sonori abbiamo la possibilità di riprodurne molti contemporaneamente (fino a 8), per lo streaming possiamo solo suonare un file per volta (facendone partire un altro si ferma il precedente).

Per lo streaming pygame ha delle funzioni speciali che si trovano nel sottomodulo music di mixer (sì, esistono i sottomoduli dei sottomoduli!). Dal nostro punto di vista tutto questo è una scocciatura: per gli effetti sonori si usano gli oggetti (e quindi per suonare dobbiamo usare la sintassi variabile.metodo()) mentre per la colonna sonora avremo delle normali funzioni (con la sintassi modulo.funzione(argomenti)); ciò si traduce in istruzioni "quasi uguali ma diverse" che possono facilmente portare a confondersi. Ecco anche qui una tabella con le principali funzioni.

Funzione Significato
pygame.mixer.music.load("nome_del_file") Determina il file sonoro da suonare (possiamo caricare .wav, .ogg, .mid, mentre la documentazione avverte che il supporto per gli .mp3 è limitato e potrebbero mandare in crash il programma).
pygame.mixer.music.play() Inizia a suonare il file. Anche qui possimo aggiungere un parametro con il numero delle ripetizioni (non compresa la prima); se il parametro è -1 la musica si ripeterà all'infinito.
pygame.mixer.music.stop() Ferma la musica.
pygame.mixer.music.fadeout(5000) Ferma la musica diminuendo gradatamente il volume. Il parametro n indica il numero di millisecondi (quindi 5000 = 5 secondi)
pygame.mixer.music.set_volume(0.6) Aggiusta il volume; il parametro è un numero decimale da 0 (silenzio) a 1 (massimo). Quando la usate il suono avrà sempre lo stesso volume finchè non lo cambiate

Nella cartella Music trovate alcune sottocartelle con file .ogg e .mid; potete provare anche a copiare qui qualcuno dei vostri .mp3 preferiti, per vedere se pygame li carica e suona (cosa che, come ho detto, non è garantita nell'installazione standard).

ESERCIZIO 12.2: Aggiungete al programma panda_suono.py anche una colonna sonora. Prima di entrare nel ciclo principale caricate il file "Music/Rock_On.mid" e suonatelo (ripetendolo all'infinito) con le funzioni appena viste. Per esercizio eliminate il parametro opzionale dalla play() e verificate che effettivamente il file suona una sola volta e si ferma.
Potete poi divertirvi a cercare nelle sottocartelle della "Music" altri files musicali (alcune contengono dei .mid, altre degli .ogg) da suonare come colonna sonora.
SOLUZIONI

Fine della lezione