PARTE 6: UN CAMBIO DE TONO

El título de esta columna tiene un doble significado. El significado original tiene que ver con el tema que nos ocupa: formas de onda personalizadas en el Atari. Últimamente ha habido mucho interés en el tema, y con razón. La configuración de ondas personalizada puede producir efectos de sonido realistas, buenas imitaciones instrumentales y probablemente una de las modas más populares en la industria en este momento, la síntesis de voz. Es un tema maduro para una serie sobre generación de sonido.


Todas estas técnicas, sin embargo, dependen en gran medida del lenguaje Ensamblador. Los lenguajes de alto nivel no son lo suficientemente eficientes para llevar al altavoz a las frecuencias necesarias. Además, a medida que sigamos ampliando la gama de sonidos disponibles para nosotros, seguiremos encontrándonos con esta situación. De ahí el segundo significado del título: El tono de esta columna va a inclinarse seriamente hacia el lenguaje Ensamblador.


Esto no debería ser motivo de pánico entre los programadores BASIC. Se hará todo lo posible para proporcionar un código híbrido que le resulte útil o interesante. Este mes es un buen ejemplo: el listado BASIC proporciona un método conveniente para producir ondas sinusoidales que podrían adaptarse fácilmente para diferentes propósitos. Si está familiarizado con el Ensamblador, por supuesto, podrá experimentar más plenamente con formas de onda personalizadas.


Así termina la editorial. Hablemos de sonido.


De nuestra discusión anterior sobre la cancelación de formas de onda, debería tener una idea de lo que es una onda sonora: una serie rítmica de pulsos en el aire. La forma de cada pulso es lo que llamamos forma de onda y determina el carácter del sonido. Para hacer una generalización amplia, las formas de onda con bordes afilados suenan más zumbantes o más ásperas que las formas de onda con bordes redondeados. Cualquiera interesado en obtener una gama más amplia de tonos del Atari, entonces, debería interesarse por la generación de formas de onda personalizadas, ya que ofrece un mayor control sobre el carácter de un sonido.


Si tiene problemas para visualizar lo que hace una forma de onda, repasemos con un ejemplo que todos conocemos y amamos, el parámetro 10 de distorsión de tono puro del Atari. La salida de forma de onda normal con esta configuración es una onda cuadrada, una forma simple formada por arriba/abajos o encendido/apagados que se adapta perfectamente a la electrónica digital. Cuando se traduce al altavoz, una onda cuadrada implica (1) comenzar completamente retraída; (2) instantáneamente extenderse por completo; (3) instantáneamente volver a retraerse por completo.


Lo cual, dicho sea de paso, es la razón por la que realmente no se escucha una verdadera onda cuadrada. La transmisión de materia aún no se ha inventado y el altavoz no puede realmente saltar de un punto del espacio a otro. Sin embargo, se mueve allí lo más rápido que puede y el sonido es más o menos el mismo.


El punto clave a tener en cuenta es que una forma de onda es un conjunto de «instrucciones» para el cono del altavoz que tienen que ver con su patrón de movimiento. Cuando enviamos una forma de onda al altavoz, éste baila hacia adelante y hacia atrás al compás de la forma de onda que le damos. Este cono de papel vibrante empuja el aire, el que a su vez empuja una membrana en nuestro oído. El objetivo de la generación de sonido, entonces, es ofrecer un patrón interesante de movimiento hacia adelante y hacia atrás a nuestro tímpano. Afortunadamente, un altavoz puede ocupar más de dos posiciones, por lo que puede reproducir millones de patrones además de encendido/apagado/encendido/apagado. Digamos que nuestro altavoz tiene dieciséis posiciones diferentes, siendo 0 completamente retraído y 15 completamente extendido. Producir diferentes formas de onda implicaría enviar una serie repetitiva de números entre 0 y 15. El patrón de números determinaría la forma de onda y, por tanto, el carácter del tono. El tono o frecuencia del sonido dependería de la rapidez con la que se repitiera la secuencia. Las secuencias más rápidas ocurren en una frecuencia más alta y por lo tanto tienen un tono más alto.


Como ya podrá adivinar, Atari nos proporciona una manera de comunicarnos directamente con el cono del altavoz y entregar nuestro patrón de «instrucciones» o nuestra propia forma de onda. Al configurar el bit 4 en AUDCX, habilitamos un modo especial llamado salida forzada, el que pasa el parámetro de volumen directamente al altavoz en forma de un voltaje fijo. De esta manera podemos hacer que el altavoz baile en cualquier patrón que queramos (dentro de unos límites muy definidos).


Si no recuerda AUDCX, es el registro de control de audio para cada voz, denominado AUDC1 (dirección $D201), AUDC2 ($0203), etc. El nibble superior de AUDCX contiene el parámetro de distorsión para el canal, y el nibble inferior contiene la información del volumen. Un tono puro de volumen 8, por ejemplo, es $A8, el $A (10 decimal) para tono puro, el 8 para volumen. La implementación de salida forzada simplemente implica almacenar un valor entre $10 y $1F en el registro AUDC de un canal. Un valor de $10 retrae el altavoz, $1F lo extiende completamente y los valores entre estos extremos colocan al altavoz en una posición media correspondiente.


Por ejemplo, almacenar sucesivamente los valores $10, $1F, $10, $1F... en AUDC1 producirá la onda cuadrada normalmente producida por el ajuste de tono puro en el canal 1. (Excepto que será el resultado de su propio trabajo, y ¡por lo tanto sonará mucho mejor!) Una secuencia más interesante podría ser:


$10, $14, $18, $1C, $1F, $10, $14, $18, $1F...

lo que produciría una onda de rampa (o de sierra).


Sin embargo, existen algunas desventajas de la salida forzada que debe tener en cuenta. La primera es importante: el tiempo del procesador. Para producir una alta frecuencia, el 6502 debe dedicar todos sus recursos a la producción de la forma de onda. Esto significa que su programa se detendrá cada vez que desee cantar. No hay cambios gráficos, nada. Sin embargo, esa no es toda la historia. Para producir una forma de onda sin distorsión, todas las interrupciones deben estar desactivadas, al igual que todo DMA.


Si no está familiarizado con estos términos, se refieren a eventos que interrumpen momentáneamente la ejecución del programa por parte del 6502. Cada vez que se presiona una tecla, se produce una interrupción del teclado y el 6502 guarda toda la información con la que estaba trabajando, salta a un programa para manejar la interrupción y luego regresa a su programa después de recuperar la información que guardó. Es como leer un libro durante una conversación: siempre estás poniendo un dedo en la página para poder responder una pregunta. No se puede leer mucho de esta manera y el 6502 no se puede realizar mucha computación. DMA significa Direct Memory Access (Acceso Directo a Memoria) y ocurre cada vez que se genera la visualización en pantalla. ANTIC (el chip que maneja la pantalla) detiene el 6502 para que pueda tomar prestadas las líneas de dirección y datos. Estas constantes interrupciones crean «interrupciones» de zumbidos en la forma de onda que deben detenerse.


¿Qué significa esto para el usuario? Bueno, fealdad. Cada vez que se ingresa a la rutina de sonido, la pantalla parpadea y es reemplazada por el color de fondo. Si el color de fondo es negro, se parece mucho a un fallo del sistema. Además, si se entra y sale de la rutina repetidamente, como en la demostración, el parpadeo distraerá a todos menos a un ciego.


¿Qué se puede hacer al respecto? Muy poco. Es útil almacenar el color normal de la pantalla (en los gráficos 0, $94) en el registro de fondo. Esto significa que sólo el texto parpadea. Sí, sigue siendo feo.


También existen otras limitaciones. El uso de la memoria es uno de ellos. La síntesis de voz se mencionó anteriormente como un derivado del modo de salida forzada; La idea de la síntesis de voz sin tener que comprar ningún periférico adicional es realmente apasionante, y actualmente existen algunos programas en el mercado que hacen exactamente eso. Desafortunadamente, los requisitos de almacenamiento de datos, incluso para una simple oración, son asombrosos, y el programador serio debe considerar cuidadosamente qué opciones renunciará para tener una mayor fidelidad de la salida de voz. Una gran cantidad de código de máquina puede caber en el espacio reservado para "¡Te tenemos, basura terrestre!" Esto no quiere decir que la síntesis de voz no tenga cabida en el Atari, sólo que se debe realizar un examen de conciencia serio antes de tomar la decisión.


El Programa de Ejemplo. La demostración muestra un uso más modesto de la salida forzada: proporciona una manera de reproducir formas de onda personalizadas desde BASIC. Tal como está escrito, la demostración reproduce ondas sinusoidales, que son considerablemente más relajantes que las ondas cuadradas y deberían ser un cambio de tono bienvenido para aquellos que no son programadores en su casa.


El listado en Ensamblador está completamente comentado y debería ser fácil de seguir. Acepta una tabla de longitud de onda, duración de nota y frecuencia desde el BASIC. La tabla de ondas se fija en la página 6 y puede tener una longitud máxima de 256 pasos. La duración y la frecuencia también pueden ser cualquier número entre 0 y 255.


;***********************
;*  Forced Output Demo *
;*  Assembler Listing  *
;***********************

NMIEN   = $D40E
IRQEN   = $D20E
DMACTL  = $D400
AUDC    = $D201
AUDCTL  = $D208
SKCTL   = $D20F
COLBK   = $D01A
DUMMY   = $D01E
;
WVTAB   = $600
;
      ORG $CB
WVTL  DS  1
DURA  DS  2
WVPNT DS  1
WFREQ DS  1
WCNT  DS  1
;
      ORG $4000 ;(relocatable)
;
PLA;number of args
PLA;wave table length hi
PLA;wave table length In
STA WVTL
PLA;duration hi
PLA;duration lo
STA DURA+1
PLA;freq hi
PLA;freq lo
STA WFREQ;store freq
STA WCNT
LDA #0;init pointer
STA WVPNT
;no interrupts, no DMA
STA NMIEN
STA IRQEN
STA DMACTL
;init audio
STA AUDCTL
STA DURA
LDA #3
STA SKCTL
;color the screen
LDA #$94
STA COLBK
;
PLAYIT DEC WCNT;dec freq cnt
BEQ DOVOX
;waste some machine cycles
    LDX    #5
WASTE DEX
BNE WASTE
STA DUMMY,X
BEQ UPDUR
DOVOX LDA WFREQ ;recharge cnt
STA WCNT
;get index into wave table
LDY WVPNT
;get volume and set force output
LDA WVTAB,Y
ORA #$10
;punch the speaker
STA AUDC
;move the wave pointer
INY
;check for table end
CPY WVTL
BCC NOWRAP
;wrap pointer
LDY #0
NOWRAP STY    WVPNT
;update duration counter
UPDUR DEC DURA
BNE PLAYIT
DEC DURA+1
BNE PLAYIT
;time's up, return to Basic
LDA #$FF
STA NMIEN
STA    IRQEN
RTS
;
END	

No se utilizan trucos reales en el código, pero observe la ubicación del mecanismo de retardo: es importante colocar el retardo entre cada paso de la forma de onda, para que se conserve la forma de onda. También tenga en cuenta que si aún no se ha alcanzado el tiempo para generar otro paso de onda, se ingresa un pequeño retraso para ecualizar el tiempo de ejecución del bucle.


Hay dos factores de distorsión: cada 256 iteraciones, se utilizan 7 ciclos de máquina adicionales para actualizar el byte alto del recuento de duración, y cada vez que se repite la forma de onda, se utilizan 2 ciclos adicionales. Los puristas pueden estremecerse, pero cuando el 6502 funciona a 1,79 MHz, los ciclos perdidos son mínimos.


Tenga en cuenta también que la parte del Ensamblador fuerza el bit 4 de AUDCX a 1, de modo que BASIC pueda pasar los bits de volumen a través de la tabla de formas de onda. Configurar un bit específico es mucho más fácil en Ensamblador que en BASIC.


La rutina BASIC primero coloca el Código de Máquina en su lugar (líneas 29 a 50) y luego compila la tabla de formas de onda. La fórmula utilizada formará una onda sinusoidal compuesta de LNG pasos. El valor de LNG se puede cambiar (línea 9) a cualquier valor hasta 255. Cuanto mayor sea la tabla de formas de onda, mayor será la resolución de la onda sinusoidal y, por lo tanto, representará con mayor precisión una onda sinusoidal verdadera (en términos más subjetivos). Sin embargo, a medida que la forma de onda se alarga, la frecuencia más alta disminuye, porque hay más pasos que cubrir antes de que la forma se repita. Las ondas sinusoidales suenan mejor en frecuencias más altas, por lo que las longitudes de onda largas no son muy útiles con esta fórmula. Otras formas de onda funcionan mucho mejor en las frecuencias más bajas; pruebe la forma de onda de rampa discutida anteriormente.


Después de introducir la forma de onda, BASIC lee una frecuencia de la tabla de datos en las líneas 26 y 27 y llama al controlador del altavoz en Lenguaje de Máquina.


La demostración se puede modificar fácilmente para diferentes formas de onda; simplemente introduzca la secuencia deseada desde las ubicaciones 1536 a 1791. Las formas de onda se pueden leer desde una tabla de datos o ingresar con cualquier esquema de edición extraño que se le ocurra. Aquí hay mucho potencial para la experimentación, incluso sin profundizar en la parte del Ensamblador.


Oh sí; Recuerde siempre guardar el código híbrido antes de ejecutarlo. Un solo error en las declaraciones de datos del Código de Máquina probablemente devorará el programa, el sistema operativo, DOS, su gato...


1 REM *************************
2 REM *  FORCED OUTPUT DEMO   *
3 REM *   BY BILL WILLIAMS    *
4 REM *     BASIC LISTING     *
5 REM *************************
7 GOSUB 29
8 SETCOLOR 4,9,4
9 LNG=10:TEMPO=10
10 ? "WAVESHAPE:"
11 FOR L=0 TO LNG-1
12 N=INT(SIN(L*6.2831853/LNG)*7)+7
13 POKE 1536+L,N
14 ? N;" ";
15 NEXT L
16 FOR REPEAT=1 TO 4
17 RESTORE 25
18 FOR MELODY=1 TO 14
19 READ N
20 Q=USR(ADR(QQQ$)+1,LNG,TEMPO,N)
21 NEXT MELODY
22 NEXT REPEAT
23 END 
25 REM MELODY NOTES
26 DATA 2,16,8,4,2,4,2,16
27 DATA 20,16,20,18,16,15
29 REM MACHINE CODE (DOUBLE-CHECK!)
30 DATA 104,104,104,133,203,104,104
31 DATA 133,205,104,104,133,207,133
32 DATA 208,169,0,133,206,141,14,212
33 DATA 141,14,210,141,0,212,141,8
34 DATA 210,133,204,169,3,141,15,210
35 DATA 169,148,141,26,208,198,208
36 DATA 240,10,162,5,202,208,253,157
37 DATA 30,208,240,23,165,207,133,208
38 DATA 164,206,185,0,6,9,16,141,1
39 DATA 210,200,196,203,144,2,160,0
40 DATA 132,206,198,204,208,215,198
41 DATA 205,208,211,169,255,141,14
42 DATA 212,141,14,210,96
44 DIM QQQ$(1),QQQ(17)
45 RESTORE 29
46 FOR QQL=ADR(QQQ$)+1 TO ADR(QQQ$)+97
47 READ QQB
48 POKE QQL,QQB
49 NEXT QQL
50 RETURN	

Leer el siguiente artículo que es forma de onda personalizada y revisada.



Publicado en revista Softline Volumen 2 de Mayo y Junio del 1983, páginas 18 al 20.