Asteroids: sonido y música – reproducción de los sonidos

Vamos con la última pieza del puzle: la reproducción de los sonidos.

El fichero “Sonido.asm”, como todos sus homólogos, tiene una declaración de variables (ya vista), una inicialización (ya vista), y una actualización. Lo que nos falta es, precisamente, la actualización.

La rutina “actualizaSonido” es así:

Asteroids - Rutina actualiza sonido.PNG

Es decir, utilizando el registro Y como índice:

  • Recorre la tabla “vocesActivas”.
  • Si la entrada / voz toma el valor $01, reproduce el sonido para esa voz. Esto lo hace llamando a la rutina “reproduceSonido”, que recibe el número de la voz (0 ó 1) mediante el parámetro “rsVoz”.
  • Si la entrada / voz no toma el valor $01, pasa a la siguiente entrada / voz. Así hasta haber revisado las dos voces que contemplamos actualmente.

En definitiva, aquí comprobamos que la voz o el sonido se va a reproducir siempre y cuando se haya producido el evento asociado (disparo o colisión). Recordemos que son los eventos los que apuntan el valor $01 en la tabla “vocesActivas” llamando a las rutinas “activaSonidoDisparo” o “activaSonidoColision”.

Y poco a poco nos vamos acercando a la rutina nuclear del asunto, que es la rutina “reproduceSonido”. Esta rutina tiene dos aspectos que es importante entender muy bien:

  • La rutina funciona con cualquier voz (0 ó 1). Recibe la voz como parámetro de entrada (“rsVoz”) y, en función del valor de este parámetro, localiza y actualiza los datos correctos en las tablas “vocesActivas”, “vocesEntradas”, “vocesRetardos” y “vocesSonidos”.
  • La rutina no reproduce el sonido de comienzo a fin, sino un poquito en cada ciclo del bucle de juego. Los sonidos están definidos mediante varias entradas en las tablas de definición de sonidos, y cada entrada tiene una frecuencia y una duración (en ciclos). Pues bien, en cada ciclo del bucle de juego se va descontando un ciclo del “retardo”, hasta que el retardo llega a cero. En ese momento hay que pasar a la siguiente entrada, o terminar la reproducción del sonido.

Como la rutina es larga y compleja, y como además una ejecución guarda relación con las ejecuciones previas (porque el sonido se reproduce a lo largo de varios ciclos), lo mejor para entenderla es “despiezarla”. La variable clave en la ejecución es el retardo:

Si el retardo actual en “vocesRetardos” es cero:

Si el retardo es cero, es porque todavía no se ha reproducido ese sonido, o porque ya se venía reproduciendo de antes, pero la entrada es nueva, a estrenar.

Por tanto, la rutina tiene que hacer todo esto:

Asteroids - Reproduce sonido - retardo cero.PNG

Es decir, la rutina tiene que:

  • Ver por qué entrada iba en “vocesEntradas”.
  • Preparar un puntero para acceder a la tabla de definición del sonido (puntero $fb-$fc).
  • Leer la frecuencia de la entrada.
  • Fijar la frecuencia en la imagen del SID.
  • Leer la duración en ciclos de la entrada.
  • Activar la voz en la imagen del SID.
  • Transferir la imagen al SID.

A partir de aquí la entrada está sonando. Y va a sonar tantos ciclos como pone la entrada, porque será cuando el retardo llegue a cero cuando pasaremos a la siguiente entrada. Hasta entonces la voz seguirá igual, sin cambios.

Si el retardo actual en “vocesRetardos” no es cero:

Si el retardo no es cero, es porque el sonido / entrada se viene reproduciendo de antes. La entrada no es nueva.

Por tanto, en general, sólo hay que decrementar el retardo. De este modo, la entrada seguirá sonando:

Asteroids - Reproducir sonido - decrementa retardo.PNG

Ahora bien, si al decrementar el retardo éste llega a cero, es porque la entrada ha terminado y hay que pasar a la siguiente o dar por terminado el sonido. Veamos el apartado que sigue.

Al decrementar el retardo actual en “vocesRetardos” ha llegado a cero:

Efectivamente, si al decrementar el retardo éste ha llegado a cero, es porque la entrada ha terminado y hay que pasar a la siguiente entrada o dar por terminado el sonido.

Por tanto, la rutina tiene que hacer todo esto:

Asteroids - Reproduce sonido - siguiente entrada

Es decir, la rutina tiene que:

  • Ver por qué entrada iba en “vocesEntradas”.
  • Sumarle tres a la entrada. Las entradas son triples (frecuencia low, frecuencia high y duración). Más que entradas propiamente dichas, estamos contando octetos en la tabla de definición del sonido.
  • Preparar un puntero para acceder a la tabla de definición del sonido (puntero $fb-$fc).
  • Leer el primer octeto de la siguiente entrada.
  • Si el octeto no es $ff, es que el sonido tiene más entradas. En el siguiente ciclo la cargaremos. Ver apartado “Si el retardo actual es cero” más arriba.

Ahora bien, si el primer octeto de la siguiente entrada es $ff, es porque ya no hay más entradas y el sonido ha terminado. Veamos el apartado que sigue.

El primer octeto de la siguiente entrada es $ff:

Efectivamente, si el primer octeto de la siguiente entrada es $ff, es porque ya no hay más entradas. Hay que dar el sonido por terminado.

Por tanto, la rutina tiene que hacer todo esto:

Asteroids - Reproduce sonido - volver entrada 0.PNG

Es decir, la rutina tiene que:

  • Volver a indicar que va por la entrada cero. Esto es para preparar futuras reproducciones del mismo sonido.
  • Marcar la voz como que ya no está activa. De este modo no se intentará volver a reproducir mientras no se produzca otro evento (disparo o explosión).
  • Desactivar la voz en la imagen del SID.
  • Transferir la imagen al SID.

A partir de este momento, el sonido deja de sonar. Quedamos preparados para futuras reproducciones.

Como se puede observar, los sonidos se reproducen a lo largo de varios ciclos del bucle de juego, tantos como indique la tabla de definición del sonido. No hay ningún problema en que el SID reproduzca los sonidos, mientras el 6510 continúa con el juego. De hecho, el SID puede reproducir hasta tres voces a la vez.

Y con esto, hemos completado el puzle del sonido, que no era sencillo. Se puede repasar el puzle completo en la versión 22 del proyecto.


Código del proyecto: Asteroids22

Deja un comentario