viernes, 6 de mayo de 2016

Cómo escribir juegos para el ZX Spectrum. Capítulo 16

Índice de entradas

Esta serie de artículos han sido traducidos a partir del documento "How to Write ZX Spectrum Games" con permiso de su autor, Jonathan Cauldwell, un gran desarrollador de juegos para el Spectrum, os recomiendo visitar su Web donde está el texto original. El documento original, y por tanto esta traducción, tiene © Jonathan Cauldwell y solo puede duplicarse con permiso expreso por escrito de su autor.

Música y efectos AY

NdT: Mira esta entrada que hice sobre el sonido en 8 bits que puede ayudarte a enter esta parte.

 El AY-3-8912

Introducido con los modelos 128K y prácticamente estándar desde entonces, fue un chip de sonido muy popular que se utilizaba en otros muchos equipos, por no hablar de vídeo juegos y máquinas de pinball. Básicamente dispone de 14 registros que se pueden leer o escribir a través de instrucciones in y out.

Los primeros seis registros controlan el tono para cada uno de los tres canales, son parejas en modo little-endian (NdT: primero el byte bajo) como es de esperar, es decir, el registro 0 es para byte bajo para el tono del canal A, el registro 1 es el byte alto del tono del canal A, el registro 2 es el byte bajo para el tono del canal B, y así sucesivamente. El registro 6 controla el periodo del ruido blanco, con valores válidos de 0 a 31. 0 significa ruido de las frecuencias más alta, 31 de las más bajas. El registro 7 es el control del mezclador. Los bits D0-D5 seleccionar el ruido blanco, el tono, ninguno o ambos. Para activar un tono o el ruido blanco, se debe establecer un bit, siendo 0 salida de los tres canales de tono mas el ruido blanco, y 63 no pone nada a la salida. Los registros 8, 9 y 10 son para controles de amplitud y envolvente. Un valor de 16 indica al chip utilizar el generador de envolventes, y 0-15 ajusta el volumen de ese canal directamente. En la práctica, es mejor controlar el volumen por ti mismo junto con el tono. Mediante la variación de estos de un cuadro al siguiente es posible producir una variedad muy buena de efectos de sonido. Si deseas utilizar el generador de envolventes, los dos siguientes, registros 11 y 12, se emparejan para formar el período de 16 bits y el registro 13 determina el patrón del envolvente. El manual del 128K explica la lista completa de los patrones, pero no lo cubro aquí ya que nunca los encontré particularmente útiles.

Para leer un registro, se escribe el número del registro en el puerto 65533, a continuación se lee ese puerto. Para escribir en un registro, se envía de nuevo el número del registro al puerto 65533, y luego el valor al puerto 49149. Para los no iniciados, los opcodes del Z80 no parecen ser capaces de escribir direcciones de puerto de 16 bits. No dejes que te confunda, es sólo que la forma en que se escriben es engañosa. En realidad out (c),a realiza out (bc),a, y out (n),a en realidad hace out (a*256+n),a.

La lectura de un registro del chip de sonido tiene varios usos. Es posible que desees leer los registros de volumen 8, 9 y 10 y presentar una barra de volumen. Hice algo similar en Egghead 5 Además, aunque no lo creas, la pistola de Sinclair se lee a través del registro 14 del chip de sonido. Sí, de verdad. En realidad solo genera dos informaciones, si se presiona el gatillo o no, y si el arma está apuntando a una parte brillante de la pantalla (o de hecho a cualquier objeto brillante). Es responsabilidad del programador lo que hace con esa información.

Aquí algo de código básico para escribir en el chip de sonido:

;Escribir el contenido de nuestro buffer AY en los registros el AY.

w8912  ld hl,snddat        ; inicio de los registros del AY-3-8912.
       ld e,0              ; comenzar con el registro 0.
       ld d,14             ; escribir 14.
       ld c,253            ; byte bajo del puerto a escribir.
w8912a ld b,255            ; 255*256+253 = puerto 65533 = seleccionar registro.
       out (c),e           ; indicar al chip en que registro estamos escribiendo.
       ld a,(hl)           ; valor a escribir.
       ld b,191            ; 191*256+253 = puerto 49149 = escribir en registro.
       out (c),a           ; esto es lo que estamos escribiendo allí.
       inc e               ; siguiente registro del chip de sonido.
       inc hl              ; siguiente byte a escribir.
       dec d               ; decrementar contador de bucle.
       jp nz,w8912a        ; repetir hasta completar.
       ret

snddat defw 0              ; registro de tono, canal A.
       defw 0              ; registro de tono, el canal B.
       defw 0              ; igual para el canal C.
sndwnp defb 0              ; período del ruido blanco.
sndmix defb 60             ; Tono/ruido control del mezclador.
sndv1  defb 0              ; canal A generador de amplitud/envolvente.
sndv2  defb 0              ; canal B amplitud/envolvente.
sndv3  defb 0              ; canal C amplitud/envolvente.
sndenv defw 600            ; duración de cada nota.
       defb 0

Llamando a w8912 en cada iteración del bucle principal el sonido es actualizado constantemente. Tu solo debes actualizar la memoria intermedia, ya que el sonido cambia de un cuadro al siguiente. Piensa en ello como en un "animador" del sonido. Sin embargo, sólo porque dejes de actualizar el registro de sonido este no va a dejar de sonar. El chip AY mantendrá sonando tu tono o ruido hasta que le indiques que se detenga. Una forma rápida de hacer esto es establecer los tres registros de amplitud a 0. En el ejemplo anterior, escribir un cero en sndv1, sndv2 y sndv3 y luego llamar w8912.

Usando drivers para la Música

La mayoría de los driver de música de los 128K (y de algunos 48K), tienen dos puntos de entrada. Una rutina de inicialización/terminación que detiene todo sonido y restablece el driver al comienzo de la melodía, y una rutina de servicio para ser llamada varias veces, por lo general 50 veces por segundo. Un buen lugar para almacenar música suele ser 49152, el inicio del banco de RAM conmutable. Si conoces la dirección de inicio del controlador, o puedes determinarla por ti mismo, el principio general es el de inicializar la dirección en la que se carga la música. La mayoría de las veces el código en este punto es simplemente saltar a otra dirección, o bien carga un registro o un par de registros antes de saltar a otra parte. La rutina de servicio tiende a realizar inmediatamente este jp. Si el driver no tiene otra documentación, es posible tener que desmontar el código para encontrar esta dirección, por lo general en 3-6 Bytes.

Para utilizar un driver de música, llamar a la dirección de inicialización antes de comenzar y cuando quieras apagarla. Entre esos puntos es necesario llamar a la rutina de servicio en varias ocasiones. Esto puede hacerse o bien manualmente, o mediante el establecimiento de una interrupción para hacer el trabajo de forma automática. Si decides hacerlo de forma manual, por ejemplo en el código de menú, ten en cuenta que la limpieza de la pantalla, mostrar el menú, la tabla de puntuación mas alta, las instrucciones, etc. tardarán más de 1/50 de segundo, así que esto retrasará su rutina y podría sonar de forma extraña. Podría ser mejor escribir una rutina para borrar la pantalla durante varios cuadros con algún tipo de efecto especial, marcar cuando se detiene y llama a la rutina de servicio en cada cuadro.

No hay comentarios:

Publicar un comentario