Otros trucosContenidosDibujando tus propias imágenesMúsica y sonido

Música y sonido

El proceso de crear un canal de sonido, lanzar efectos de sonido y música en él, y usar puntos de entrada para manejarlos, debería resultar muy familiar a quienes han leido ya la sección sobre implementación de ventanas gráficas. A quienes se hayan saltado ese capítulo para venir directamente aqui, se les recomienda muy fervientemente que lean antes la sección sobre gráficos, especialmente la parte sobre manejo de ventanas gráficas. Otra lectura necesaria es la sección sobre Blorb, ya que usarás Blorb para hacer que los ficheros de sonido estén disponibles para tu juego, en la misma forma que lo hiciste para los ficheros de gráficos. Los formatos de sonido que actualmente soporta Glk, y por tanto Inform Glulx, son AIFF y MOD. El primero es un formato de sonido sin compresión, una especie de equivalente multiplataforma del más conocido WAV de Microsoft, que produce ficheros que, con los parámetros adecuados, son de calidad suficiente como para grabar con ellos un CD de audio. (El inconveniente es que comparados con un formato con pérdida de calidad como el MP3, son bastante más enormes). MOD es bastante diferente. Los ficheros MOD se crean con programas llamados trackers, en los cuales tú cargas algún tipo de muestra de sonido breve (un golpe de tambor, un acorde de guitarra, un ladrido de un perro, lo que quieras) y despues compones una especie de partitura, colocando notas en una rejilla con el tono adecuado, seleccionando un tempo, aplicando efectos especiales a las muestras, etc. Puesto que el fichero no almacena el sonido final de la música, sino sólo las piezas de las que se forma junto con instrucciones de cómo tocarlas, los ficheros MOD son bastante pequeños. (Además es muy divertidos de coleccionar y retocar. Si usas una máquina Windows, te recomiendo encarecidamente el Tracker Modplug). Así que pongamos que estás programando un ascensor, y que decides que cuando el protagonista entre en él, debe sonar música ambiente de ascensor. El proceso sería como sigue. Primero, necesitas crear un canal de sonido, y darle un número-roca de 410 o superior (en este caso, elegiremos 410). Escribimos las líneas siguientes en el programa:

Constant GG_CANALMUSICA_ROCK 410;
Global   gg_canalmusica = 0;

Y ya que estamos, añadamos una variable global para almacenar un identificador de qué música está sonando en cada momento del juego:

Global musica_actual = 0;

Y naturalmente, en algún momento necesitaremos abrir el fichero de recursos Blorb y darle al fichero de sonido un nombre que podamos usar en el código fuente. Digamos que te apetece mofarte de las leyes del mercado y llamar al fichero Muzak. Cómo indicar esto puede variar; si estás usando iblorb, la línea será algo como:

SOUND Muzak musicascensor.mod

Una vez liquidada la preparación anterior, podemos dedicarnos al negocio de abrir el canal de sonido y enviarle música. Abrirlo es fácil: basta añadir lo siguiente en Inicializar:

  if (gg_canalmusica == 0)
    gg_canalmusica = glk_schannel_create(GG_CANALMUSICA_ROCK);
  }

(Personaliza lo anterior en tus propios programas en la forma obvia.) Con esto, el canal está ahora abierto. Lo siguiente: tocar sonidos en él. Esta vez el comando clave es glk_schannel_play_ext() que necesita cuatro argumentos:

  1. El nombre del canal de sonido. Observa que puedes tener múltiples canales de sonido - digamos, uno para efectos especiales y otro para música - pero en cualquier plataforma llegarás eventualmente a un límite. Tocar múltiples MODs a la vez es una perspectiva especialmente dudosa.
  2. El nombre del sonido a tocar (pero lee más abajo)
  3. El número de veces que el sonido debe ser repetido. Si quieres que se repita por siempre, hasta que le digas explícitamente que pare (o hasta que el juego acabe), pon -1.
  4. Este debe ser 0, a menos que quieras recibir eventos del tipo evtype_SounNotify en tu rutina HandleGlkEvent() cuando el sonido finalice su ejecución. Por ejemplo, podrías querer programar una mansión encantada, en la que suenen al azar espectrales ruidos de monstruos. El código podría ser así:

       [ HandleGlkEvent ev context sonido_nuevo;
          context = 0; ! evitar el warning de variable no usada
          switch (ev-->0) {
             evtype_SoundNotify:
                sonido_nuevo = random(Aullido, Chirrido, Grunyido);
                glk_schannel_play_ext(gg_canalmusica, sonido_nuevo, 1, 1);
          }
       ];
      

Pero nos estamos saliendo un poco de madre. Volvamos con lo nuestro. Al igual que ocurría con las ventanas gráficas, no queremos simplemente lanzar directamente una música a un canal de sonido, especialmente si va a repetirse en bucle. Si lo hiciéramos, el jugador podría hacer que el protagonista entrara en el ascensor, después restaurar un juego salvado en un punto en que el protagonista estaba en medio de un campo de batalla - ¡y la música del ascensor aún seguiría sonando! Para evitar estas potenciales pifias, usaremos la variable que hemos creado antes, y escribiremos una rutina como esta:

   [ ReiniciarCanalMusica;
      if (gg_canalmusica) {
         if (musica_actual == 0) glk_schannel_stop(gg_canalmusica);
         else glk_schannel_play_ext(gg_canalmusica, musica_actual, -1, 0);
      }
   ];

El código dentro de las llaves hace sonar la música que debería estar sonando, indicada por la variable musica_actual, o detiene la musica completamente si esa variable está a 0 [el valor de esa variable sí se recupera al cargar una partida]. Por supuesto, si el canal de sonido no está abierto, no intentará tocar nada. Ahora podemos crear un objeto ascensor, con una rutina antes como esta:

   antes [;
      Meterse: musica_actual = Muzak;
             ReiniciarCanalDeMusica();
             print "Entras en el ascensor. La selección musical de
                    hoy: arreglos de Korn para xilófono y flauta de
                    pan.^";
             JugadorA(Dentro_Ascensor);
   ],

Y finalmente, una rutina IdentifyGlkObject() para asegurarse de que todo es restaurado correctamente tras un REINICIAR o UNDO. Si ya tienes una, mézclala con esta otra:

   [ IdentifyGlkObject fase tipo ref rock res id;
      if (fase == 0) { ! Poner a cero nuestras variables de glk
         gg_canalmusica = 0;
         return;
      }
      if (fase == 1) { ! En la fase 1 no se hace nada con los canales
                       ! de sonido.
         return;
      }       
      if (fase == 2) {
         ! Iterar sobre todos los canales de sonido existentes,
         ! e identificar el nuestro.
         id = glk_schannel_iterate(0, gg_arguments);
         while (id) {
            switch (gg_arguments-->0) {
               GG_CANALMUSICA_ROCK: gg_canalmusica = id;
            }
            id = glk_schannel_iterate(id, gg_arguments);
         }
         ! Ahora, que ya tenemos inicializada la variable
         ! del canal, necesitamos actualizar la musica que
         ! suena, o desconectarla
         ReiniciarCanalDeMusica();
      }
   ];

El código de la fase 2 hace práctiamente lo mismo que lo que hacía el código de la fase 1 para las ventanas gráficas; la diferencia es que un canal de sonido no es una ventana, ni un stream (flujo) ni una referencia a fichero, de modo que la fase 1 no ha de tratar con ellos. ¡Y esto debería ser todo! Por supuesto, si intentas esto en casa, puede que te lleves una desilusión ya que, en el momento en que se escribe esto, sólo un par de plataformas tienen soporte para MOD (Windows y DOS, y encima el caso DOS tiene bugs). Pero otras plataformas se subirán al tren enseguida.


Otros trucosContenidosDibujando tus propias imágenesMúsica y sonido