Suono e musica

Il processo di creazione di un canale sonoro, per fargli emettere effetti sonori o musica, e l'uso dei punti d'ingresso per la gestione, dovrebbe apparire molto familiare a chi ha letto la sezione riguardante l'implementazione delle finestre grafiche. A quelli che sono passati direttamente a questa sezione si consiglia vivamente di leggere le sezioni riguardanti la grafica, prima di proseguire, specialmente la parte che riguarda la gestione delle finestre grafiche.

Un'altra lettura obbligatoria è la sezione su Blorb, dal momento che userete Blorb per rendere i file sonori disponibili al vostro gioco, proprio come viene fatto per i file grafici. I formati sonori supportati al momento da Glk e, quindi, da Glulx Inform sono AIFF e MOD. Il primo è un formato sonoro non compresso, una specie di Microsoft WAV multi piattaforma, che produce file, usando le giuste impostazioni, abbastanza fedeli al suono originale che può essere inciso su un CD. (L'inconveniente è che quando vengono confrontati con un formato lossy come l'MP3, sono abbastanza enormi). MOD è decisamente differente. I file MOD vengono creati usando dei programmi chiamati tracker, nei quali caricate alcuni piccoli campioni sonori (un colpo di tamburo, la nota di un pianoforte, un corda di chitarra pizzicata, un cane che abbaia, quello che volete) e poi componete una specie di spartito musicale, inserendo le note su una griglia con il tono appropriato, selezionando il tempo, applicandovi effetti speciali, e così via. Visto che i file non memorizzano l'intero pezzo musicale, ma semplicemente i mattoni per costruirlo e le istruzioni sul come suonarli, i file MOD sono decisamente piccoli. (È anche molto divertente metterli insieme e suonarli. Se state usando una macchina Windows, vi consiglio caldamente Modplug Tracker).

Diciamo che state codificando un ascensore, e decidete che quando il giocatore vi entra, la musica dell'ascensore deve suonare. Il processo da seguire è questo. Per cominciare dobbiamo creare un canale sonoro, e dobbiamo dargli un rock value pari a 410 o superiore (in questo caso scegliamo 410). Inseriamo le righe seguenti nel programma:

   Constant GG_MUSICCHAN_ROCK 410;
   Global gg_musicchan = 0;

E visto che ci siamo, inseriamo una variabile globale per memorizzare la musica che deve essere suonata ad ogni punto determinato:

   Global current_music = 0;

E, naturalmente, ad un certo punto abbiamo modificare il file di risorse Blorb per dare al file sonoro un nome con il quale possiamo usarlo nel nostro codice sorgente. Diciamo che vogliamo farci beffe delle leggi sul diritto d'autore e chiamiamo il nostro file "Muzak". Come indicarlo può variare; se state usando iblorb, la riga potrebbe essere:

   SOUND Muzak elevmus2.mod

Con il lavoro di preparazione terminato, possiamo concentrarci sull'apertura del canale musicale e l'invio della musica allo stesso. L'apertura è facile: basta inserire le righe seguenti in Initialise():

   if (gg_musicchan == 0) {
     gg_musicchan = glk_schannel_create(GG_MUSICCHAN_ROCK);
   }

(Personalizzatele per i vostri programmi nella maniera solita). Il canale, adesso, è aperto. Prossimo passo: suonarci la musica. Questa volta il comando chiave è "glk_schannel_play_ext()", che richiede quattro argomenti:

1) Il nome del canale sonoro. Notate che potete avere diversi canali sonori -- ad esempio, uno per gli effetti speciali, ed uno per la musica -- ma su ogni piattaforma, alla fine incontrerete alcune limitazioni. Suonare più MOD insieme è una prospettiva dall'esito particolarmente dubbio.

2) Il nome del suono da riprodurre (leggete più avanti)

3) Il numero di volte il suono deve essere ripetuto. Se volete che venga ripetuto per sempre fino a quando non gli dite di smettere (o uscite dal gioco), mettete -1.

4) Deve valere 0, a meno che vogliate inviare un evento evtype_SoundNotify alla vostra routine HanldeGlkEvent() quando termina la riproduzione del suono. Ad esempio, potreste voler implementare una casa infestata con dei suoni paurosi riprodotti a caso. Il codice potrebbe essere:

   [ HandleGlkEvent ev context new_sound;
      context = 0; ! sopprime gli avvertimenti ignorati
      switch (ev-->0) {
         evtype_SoundNotify:
            new_sound = random(Ululato, Urlo, Ringhio);
            glk_schannel_play_ext(gg_musicchan, new_sound, 1, 1);
      }
   ];

Ma siamo andati un po' troppo oltre. Torniamo indietro.

Come quando disegnamo le immagini in una finestra grafica, non vogliamo riprodurre un commento sonoro direttamente attraverso un canale sonoro, specialmente se deve essere suonato indefinitamente. Se lo facessimo, il giocatore potrebbe far entrare il proprio personaggio nell'ascensore, poi ricaricare un gioco salvato nel punto in cui il personaggio era nel mezzo di una zona di guerra -- e la musica dell'ascensore starebbe ancora suonando! Per evitare questi potenziali errori, usiamo la variabile globale che abbiamo creato in precedenza, e scriviamo la seguente routine:

   [ MyRestartMusicChannel;
      if (gg_musicchan) {
         if (current_music == 0) glk_schannel_stop(gg_musicchan);
         else glk_schannel_play_ext(gg_musicchan, current_music, -1, 0);
      }
   ];

Il codice all'interno delle parentesi graffe riproduce qualunque motivo deve essere suonato al momento, o smette di riprodurre musica nel caso in cui la variabile current_music sia impostata a 0; naturalmente, se non ci sono canali sonori aperti, non viene riprodotto nulla. Ora possiamo creare un oggetto ascensore, con un blocco before come questo:

   before [;
      Enter: current_music = Muzak;
             MyRestartMusicChannel();
             print "Entri nell'ascensore. La selezione musicale di oggi è:
                Arrangiamento di corno per xylofono e flauto.^";
             PlayerTo(In_Ascensore);
   ],

Ed, alla fine, una routine IdentifyGlkObject() per assicurarsi che tutto torni a posto correttamente dopo un restore od un undo. Se ne avete già una, aggiungetevi questo:

   [ IdentifyGlkObject phase type ref rock res id;
      if (phase == 0) { ! Azzera i riferimenti ai nostri oggetti.
         gg_musicchan = 0;
         return;
      }

      if (phase == 1) { ! Non c'è niente da fare per i suoni in questa fase.
         return;
      }

      if (phase == 2) {
         ! Itera attraverso tutti i canali esistenti -- potrebbe essercene
         ! uno o nessuno -- ed identifica i nostri.
         id = glk_schannel_iterate(0, gg_arguments);
         while (id) {
            switch (gg_arguments-->0) {
               GG_MUSICCHAN_ROCK: gg_musicchan = id;
            }
            id = glk_schannel_iterate(id, gg_arguments);
         }
         ! Ora, abbiamo appena cambiato lo stato del gioco, così dobbiamo
         ! cambiare musica o spegnerla del tutto.
         MyRestartMusicChannel();
      }
   ];

In questo caso il codice in phase 2 fa più o meno le stesse cose del codice in phase 1 nella sezione sulle finestre grafiche; la differenza è che un canale sonoro non è né una finestra, né uno stream o un riferimento a file, così la phase 1 non ha bisogno di sapere come deve trattarlo.

E questo dovrebbe funzionare! Naturalmente, se lo provate a casa, potreste restare un po' contrariati -- al momento della scrittura di queste righe, solo un paio di piattaforme hanno il supporto per i file MOD (Windows e DOS, ed il codice DOS MOD è bacato). Ma altre piattaforme dovrebbero entrare in gioco abbastanza presto.


Prossima sezione: Input del mouse
O ritorna al sommario