viernes, 15 de abril de 2016

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

Í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.
 
ACTUALIZADO 21/09/2022: Se añaden al final los ejemplos ejecutables según el nuevo apéndice C

Efectos de sonido por el altavoz

NdT: Podeis leer aquí mi artículo sobre el tema

El altavoz

Hay dos formas de generar sonido y música en el ZX Spectrum, la mejor y más complicada es a través del chip de sonido AY 38912 en los modelos 128K. Este método se describe en detalle en un capítulo posterior, pero por ahora vamos a preocuparnos por el altavoz del 48K. Por simple que sea, este método tiene sus usos, especialmente para los efectos de sonido cortos y agudos durante los juegos.

Beep

En primer lugar tenemos que saber cómo producir un pitido de un determinado tono y duración, y la ROM de Sinclair tiene una rutina en la dirección 949 bastante accesible para hacer el trabajo por nosotros, todo lo que se requiere es pasar los parámetros de tono en el par de registro HL y la duración en DE, llamar a 949 y nos dará un "bip" apropiado.

Por desgracia, la forma de calcular los parámetros con los que trabaja es un poco complicada y requiere un poco de cálculo. Necesitamos conocer el valor en Hercios de la frecuencia de la nota a emitir, esencialmente es el número de veces que el altavoz tiene que activarse por segundo para producir el tono deseado. Una tabla adecuada sería (NdT: El documento utiliza la codificación de letras, pongo también la nota):

C central   261'63   DO medio
C sostenido 277'18   DO#
D           293'66   RE
D sostenido 311'13   RE#
E           329'63   MI
F           349'23   FA
F sostenido 369'99   FA#
G           392'00   SOL
G sostenido 415'30   SOL#
A           440'00   LA
A sostenido 466'16   LA#
B           493'88   SI

Para una octava más alta sólo tienes que duplicar la frecuencia, para una octava más baja reducirla a la mitad. Por ejemplo, para producir una nota C (DO) una octava más alta que el C central (DO medio) se toma el valor de C central (261'63) y se duplica a 523'26.

Una vez establecida la frecuencia, la multiplicamos por el número de segundos requeridos, y se le pasa a la rutina de la ROM en el par de registros DE como la duración. Por tanto para hacer sonar la nota C central (DO medio) durante una décima de segundo, la duración requerida sería 261'63 * 0'1 = 26. El tono es elaborado dividiendo 437500 por la frecuencia y restando 30'125,  pasando el resultado en los registros HL. Para un C central (DO medio) esto significaría un valor de 437500 / 261'63 - 30'125 = 1'642.

En otras palabras:

DE = Duración = Frecuencia * segundos
HL = Tono = 437500 / Frecuencia - 30'125

Así que para tocar un G sostenido (SOL#) una octava por encima de la del C central (DO medio) durante un cuarto de segundo:

; Frecuencia del G sostenido en la octava del C central = 415.30
; Frecuencia del G sostenido una octava más alta = 830.60
; Duración = 830.6 * 1/4 = 207.65
; Tono = 437500 / 830.6 - 30.125 = 496.6

       ld hl,497           ; tono.
       ld de,208           ; duración.
       call 949            ; rutina de beep de la ROM.
       ret

Por supuesto esta rutina no solo es útil para notas musicales, la podemos utilizar para una variedad de efectos, uno de mis favoritos es un rutina simple de inflexión de tono:

       ld hl,500           ; tono inicial
       ld b,250            ; longitud de la inflexión del tono.
loop   push bc
       push hl             ; guardar tono.
       ld de,1             ; duración muy corta.
       call 949            ; rutina de beep de la ROM.
       pop hl              ; restablecer el tono.
       inc hl              ; subir el tono.
       pop bc
       djnz loop           ; repetir.
       ret

Hacer sonar la rutina anterior es bastante fácil para ajustar el tono hacia arriba y abajo, y al cambiar  frecuencia de inicio, inflexión de tono y duración se producen una serie de efectos interesantes. Una palabra de advertencia: no vaya demasiado a lo loco con sus valores de tono o la duración, o la rutina del beep se quedará bloqueada y no será capaz de recuperar el control de su Spectrum sin resetearlo.

Ruido blanco

Cuando se utiliza el altavoz ni siquiera hay que usar las rutinas de la ROM, es bastante fácil escribir nuestras propias rutinas de efectos de sonido, sobre todo si queremos generar ruido blanco para los choques y golpes. El ruido blanco es por lo general mucho más divertido para jugar.

Para generar ruido blanco todo lo que necesitamos es un generador de números aleatorios rápido y simple (una secuencia de Fibonacci podría funcionar, pero me gustaría recomendar usar un puntero sobre las primeras 8K de ROM e ir a buscar el byte en ese lugar para obtener una secuencia razonable de números al azar de 8 bit). A continuación, escribimos este valor en el puerto 254. Recuerda que este puerto también controla el color del borde, de modo que si no quieres un efecto de borde de rayas multicolor necesitamos enmascarar los bits del borde con AND 248 y añadir el número del color de borde que queremos (1 para el azul, 2 para rojo, etc.) antes de realizar una instrucción OUT (254). Cuando hemos hecho esto tenemos que poner un pequeño bucle de retardo (corto para tono alto, largo para tonos más bajos) y repetir el proceso unos pocos cientos de veces. Esto nos dará un buen efecto de "choque".

Esta rutina se basa en un efecto de sonido de Egghead 3:

noise  ld e,250            ; repetir 250 veces.
       ld hl,0             ; apunta al inicio de la ROM.
noise2 push de
       ld b,32             ; longitud del paso.
noise0 push bc
       ld a,(hl)           ; siguiente numero "aleatorio".
       inc hl              ; apuntar.
       and 248             ; queremos un borde blanco.
       out (254),a         ; salida al altavoz.
       ld a,e              ; como e disminuye...
       cpl                 ; ...incrementamos el retraso.
noise1 dec a               ; decrementar el contador del bucle.
       jr nz,noise1        ; bucle de retardo.
       pop bc
       djnz noise0         ; siguiente paso.
       pop de
       ld a,e
       sub 24              ; tamaño del paso.
       cp 30               ; fin del rango.
       ret z
       ret c
       ld e,a
       cpl
noise3 ld b,40             ; periodo de silencio.
noise4 djnz noise4
       dec a
       jr nz,noise3
       jr noise2

1 comentario: