Octavas, notas y frecuencias

Una octava es el rango de frecuencias que va desde una frecuencia hasta el doble de esa frecuencia. En una octava caben ocho notas: do, re, mi, fa, sol, la, si y do, que ya sería la primera nota de la siguiente octava.

Octava

Una nota, por su parte, se caracteriza por una frecuencia y una duración: redonda, blanca, negra, corchea, semicorchea, fusa y semifusa.

Duración notas

Las frecuencias correspondientes a cada nota pueden consultarse en el apéndice E del libro “Commodore 64 Programmer’s Reference Guide” (ver página 384). Aquí se reproduce sólo la primera octava (octava 0) y el comienzo de la segunda (octava 1):

Nota – octava Frec. decimal Frec. hex. high Frec. hex. low
C-0 268 $01 $0C
C#-0 284 $01 $1C
D-0 301 $01 $2D
D#-0 318 $01 $3E
E-0 337 $01 $51
F-0 358 $01 $66
F#-0 379 $01 $7B
G-0 401 $01 $91
G#-0 425 $01 $A9
A-0 451 $01 $C3
A#-0 477 $01 $DD
B-0 506 $01 $FA
C-1 536 $02 $18
C#-1 568 $02 $38

Esta tabla utiliza la notación musical inglesa, que tiene esta correspondencia con la notación musical tradicional :

  • Do = C.
  • Re = D.
  • Mi = E.
  • Fa = F.
  • Sol = G.
  • La = A.
  • Si = B.

Es decir, según esta tabla C-0 es do de la octava 0, C#-0 es do# (sostenido) de la octava 0, C-1 es do de la octava 1, C#-1 es do# (sostenido) de la octava 1, etc. Así desde la octava 0 hasta la octava 7. Es decir, el SID maneja frecuencias para un rango de ocho octavas.

Y como se decíamos en la entrada anterior, lo lógico es que el programa que reproduce la melodía no esté programado en términos de frecuencias, sino que esté programado en términos de notas, ya que así es como componen los músicos. De este modo, usando la tabla anterior de conversión de notas a frecuencias el programador puede pasar fácilmente de notas a frecuencias, y programar el SID con las frecuencias.

En realidad, ni siquiera es necesario que el programa maneje la tabla anterior completa (12 notas por octava x 8 octavas = 96 notas). Sabiendo que una nota (ej. C-0) tiene una frecuencia (ej. 268) y la misma nota en la siguiente octava (ej. C-1) tiene el doble de frecuencia (ej. 536), es suficiente con manejar una tabla en memoria con la información de la octava 0, obtener una frecuencia base a partir de la nota, y multiplicar esa frecuencia por 2, 4, 8, 16, 32, 64 o 128 en función de la octava.

Análogamente, también nos valdría manejar una tabla en memoria con la información de la octava 7, obtener una frecuencia base a partir de la nota, y dividir esa frecuencia por 2, 4, 8, 16, 32, 64 o 128 en función de la octava.

En realidad, la opción de dividir es más conveniente que la de multiplicar, ya que evita problemas con los redondeos y permitiría incluso introducir silencios (tiempos en que no suena ninguna nota) llegando a dividir la frecuencia base por 256.

En resumen, nuestro programa necesitará dos tablas:

  • Una tabla de conversión de notas a frecuencias para la octava 7.
  • Una tabla con la información de notas y octavas de la melodía. En realidad, hará falta una tabla de este tipo para cada una de las voces (1, 2 o 3 voces). Eso, o una tabla de triple entrada, que es equivalente.

Gráficamente, el proceso será como sigue:

Notas y frecuencias.PNG

La tabla con la melodía (o tablas; hasta tres, una por voz) puede diseñarse de muchas maneras. No obstante, dado que el SID soporta ocho octavas (0-7) y doce notas por octava (0-11), es suficiente con reservar un nibble para especificar la octava (16 valores posibles; se usarán sólo 8) y otro nibble para especificar la nota (16 valores posibles; se usarán sólo 12). De este modo, con un byte por nota (incluyendo su octava) es suficiente.

El fin de la melodía puede marcarse, por ejemplo, con el valor $ff, puesto que $f no es un valor válido para la octava (máximo 7) ni para la nota (máximo 11).


Programa de ejemplo: Prog51
Programa de ejemplo: Prog52 (ampliación a 3 voces)

Programar vs componer música

No es lo mismo programar que componer música. De lo primero algo sé (tampoco mucho 🙂 ); de lo segundo no sé nada.

Pero sí recuerdo algunas cosas de mis clases de solfeo de la EGB: los pentagramas, la clave de Sol, las octavas, las diferentes notas (do, re, mi, fa, sol, la, si, do), sus duraciones (redonda, blanca, negra, corchea, semicorchea, fusa y semifusa), los silencios, etc.

Adonde quiero llegar, está claro que un músico no compone canciones en términos de frecuencias, envolventes ADSR, formas de onda, y valores para registros. Más bien, al componer una melodía lo que hace el músico es registrar las notas (con sus octavas), sus duraciones, y, si acaso, podrá jugar con el volumen. Y esto para una o varias melodías o voces.

Por tanto, para separar claramente lo que es programación del SID y lo que es música o composición, una cosa que se puede hacer es llevar la información de notas / octavas, duraciones y volúmenes a unas tablas de información en memoria. De este modo, las tablas se cargarán con el trabajo del músico (la melodía o melodías), y el programador se limitará a leer esas tablas e interpretarlas en términos de programación del SID.

Por supuesto, no es obligatorio trabajar así, pero es un enfoque muy interesante, porque delimita muy bien lo que es el trabajo del músico (componer la melodía) y lo que es el trabajo del programador (programar el SID para reproducir la/s melodía/s).

Se trata de una idea que aparece descrita en el libro “Assembly Language Programming with the Commodore 64”. La forma de conseguirlo se verá detalladamente en las entradas que siguen.

Filtros

Para configurar un filtro hay que indicar el tipo de filtro, la frecuencia de corte o la frecuencia central, según el tipo de filtro, y la voz o voces que pasan por el filtro.

Filtros

Lo primero (tipo de filtro) se hace con los bits 4, 5 y 6 del registro SIGVOL: un filtro paso bajo se consigue activando el bit 4, un filtro paso banda activando el bit 5, y un filtro paso alto activando el bit 6. Incluso pueden activarse varios filtros a la vez, aunque con una única frecuencia de corte.

Lo segundo (frecuencia de corte o central) se configura con los registros CUTLO y CUTHI. Del primero se utilizan sólo los 3 bits menos significativos, y del segundo se utilizan todos los bits, lo que significa que la frecuencia de corte / central tiene 11 bits.

Por último, la voz o voces que se pasan por el filtro se configuran actuando sobre los bits 0, 1 y 2 del registro RESON, que también se utiliza para conseguir efectos de resonancia.


Programa de ejemplo: Prog50

Forma de onda cuadrada; ancho de pulso

Si la forma de onda elegida fuera la cuadrada (bit 6 = 1 en el registro VCREG1/2/3), entonces habría que fijar el ancho de pulso (pulse width). El ancho de pulso es el porcentaje del período que la señal tiene nivel alto:

Ancho de pulso

En el caso del SID, no se programa directamente el % del ancho del pulso, sino que se programa un valor N que guarda la siguiente relación con el ancho de pulso:

N = 40,95 x ancho de pulso

Por tanto, si se quisiera un ancho de pulso del 100% se grabaría el valor 4.095 ($0fff), si se quisiera un 50% el valor 2.048 ($0800), y si se quisiera un 10% el valor 41 ($0029).

Por supuesto, estos valores se grabarían separando las partes más y menos significativas, que irían a parar a los registros PWHI1/2/3 y PWLO1/2/3 respectivamente.


Programa de ejemplo: Prog49

Envolvente ADSR

La envolvente ADSR se configura con los registros ATDCY1/2/3 y SUREL1/2/3. Así como attack, decay y release son tiempos, sustain es más bien un nivel.

La correspondencia entre los valores numéricos almacenados en attack / decay / release y el tiempo asociado puede consultarse en esta tabla:

VALOR DECIMAL VALOR HEX TIEMPO ATTACK (ms) TIEMPO DECAY / RELEASE (ms)
0 $00 2 6
1 $01 8 24
2 $02 16 48
3 $03 24 72
4 $04 38 114
5 $05 56 168
6 $06 68 204
7 $07 80 240
8 $08 100 300
9 $09 250 750
10 $0a 500 1500
11 $0b 800 2400
12 $0c 1000 3000
13 $0d 3000 9000
14 $0e 5000 15000
15 $0f 8000 24000

 
Por su parte, el parámetro sustain es un nivel, no un tiempo. Puede tomar un valor entre 0 y 15, igual que el volumen (registro SIGVOL).

Formas de onda y activar / desactivar la voz

Centrándonos en cualquiera de las tres voces, uno de los registros más importantes es el VCREG1/2/3, ya que este registro sirve para controlar la voz.

Para empezar, permite elegir la forma de onda (bits 4-7):

  • Bit 4=1: Forma de onda triangular.
  • Bit 5=1: Forma de onda en rampa.
  • Bit 6=1: Forma de onda cuadrada.
  • Bit 7=1: Forma de onda ruido.

Formas onda 2.png

En caso de activar a la vez varios bits de los anteriores, las formas de onda se sumarían.

Además de lo anterior, el registro VCREG1/2/3 permite activar la nota (bit 0 = 1) y desactivarla (bit 0 = 0). Esta operación se llama “gating”.

Al activar la nota, empiezan las fases ADS (attack – decay – sustain) y la nota suena. Al desactivarla empieza la fase R (release) y la nota se extingue.

ADSR

El tiempo que transcurre desde que se activa hasta que se desactiva la nota es la duración de la misma.

Los registros del SID

El SID, igual que el VIC y otros chips del C64, consta de una serie de registros. Y programar el SID consiste en leer y escribir valores en esos registros.

Más concretamente, el SID tiene 29 registros. Ocupan desde la dirección $d400 hasta la dirección $d41c, ambas incluidas.

Una curiosidad de estos 29 registros es que 25 de ellos son de sólo escritura, mientras que los otros 4 son de sólo lectura. Normalmente los registros, igual que las posiciones de memoria normales, son de lectura – escritura.

Cuando se escribe sobre un registro de sólo lectura, la escritura no tiene ningún efecto. Análogamente, cuando se lee de un registro de sólo escritura, la lectura no tiene ningún efecto.

Una consecuencia de lo anterior (que la mayoría de los registros del SID sean de sólo escritura) es que se suele trabajar sobre una “imagen” de esos registros, y luego esa imagen se transfiere al SID. Es decir, en vez de escribir directamente sobre los registros del SID, se suele escribir sobre unas posiciones de memoria normales que conforman una copia de trabajo del SID, y luego esa copia se transfiere al SID. Esto no es estrictamente obligatorio, pero se hace así por comodidad.

Lo normal, en todo caso, suele ser empezar por inicializar el SID (los 25 registros de sólo escritura), lo cual se consigue inicializando la imagen y luego transfiriendo la imagen al SID. Véanse los programas de ejemplo al final de esta entrada.

En cualquier caso, los registros del SID son los que siguen, que corresponden a siete registros por cada una de las tres voces, cuatro registros relacionados con los filtros, y cuatro registros adicionales (total 7×3+4+4=29 registros):

REGISTRO DIRECCIÓN FUNCIÓN

-VOZ 1 (SÓLO ESCRITURA)-

FRELO1 $d400 Frecuencia de la nota. Parte menos significativa (low).
FREHI1 $d401 Frecuencia de la nota. Parte más significativa (high).
PWLO1 $d402 Ancho de pulso. Parte menos significativa (low). Sólo cuando la forma de onda es cuadrada.
PWHI1 $d403 Ancho de pulso. Parte más significativa (high). Sólo cuando la forma de onda es cuadrada.
VCREG1 $d404 Bit 0: Gate. Activa (1) / desactiva (0) la nota.

Bit 1: Sincronizar con la voz 3.

Bit 4: Forma de onda triangular.

Bit 5: Forma de onda en rampa.

Bit 6: Forma de onda cuadrada.

Bit 7: Forma de onda ruido.

ATDCY1 $d405 Bits 0, 1, 2 y 3: Decaimiento (decay).

Bits 4, 5, 6 y 7: Ataque (attack).

SUREL1 $d406 Bits 0, 1, 2 y 3: Liberación (release).

Bits 4, 5, 6 y 7: Sostenimiento (sustain).

-VOZ 2 (SÓLO ESCRITURA)-

FRELO2 $d407 Frecuencia de la nota. Parte menos significativa (low).
FREHI2 $d408 Frecuencia de la nota. Parte más significativa (high).
PWLO2 $d409 Ancho de pulso. Parte menos significativa (low). Sólo cuando la forma de onda es cuadrada.
PWHI2 $d40a Ancho de pulso. Parte más significativa (high). Sólo cuando la forma de onda es cuadrada.
VCREG2 $d40b Bit 0: Gate. Activa (1) / desactiva (0) la nota.

Bit 1: Sincronizar con la voz 3.

Bit 4: Forma de onda triangular.

Bit 5: Forma de onda en rampa.

Bit 6: Forma de onda cuadrada.

Bit 7: Forma de onda ruido.

ATDCY2 $d40c Bits 0, 1, 2 y 3: Decaimiento (decay).

Bits 4, 5, 6 y 7: Ataque (attack).

SUREL2 $d40d Bits 0, 1, 2 y 3: Liberación (release).

Bits 4, 5, 6 y 7: Sostenimiento (sustain).

-VOZ 3 (SÓLO ESCRITURA)-

FRELO3 $d40e Frecuencia de la nota. Parte menos significativa (low).
FREHI3 $d40f Frecuencia de la nota. Parte más significativa (high).
PWLO3 $d410 Ancho de pulso. Parte menos significativa (low). Sólo cuando la forma de onda es cuadrada.
PWHI3 $d411 Ancho de pulso. Parte más significativa (high). Sólo cuando la forma de onda es cuadrada.
VCREG3 $d412 Bit 0: Gate. Activa (1) / desactiva (0) la nota.

Bit 1: Sincronizar con la voz 3.

Bit 4: Forma de onda triangular.

Bit 5: Forma de onda en rampa.

Bit 6: Forma de onda cuadrada.

Bit 7: Forma de onda ruido.

ATDCY3 $d413 Bits 0, 1, 2 y 3: Decaimiento (decay).

Bits 4, 5, 6 y 7: Ataque (attack).

SUREL3 $d414 Bits 0, 1, 2 y 3: Liberación (release).

Bits 4, 5, 6 y 7: Sostenimiento (sustain).

-FILTROS (SÓLO ESCRITURA)-

CUTLO $d415 Bits 0, 1 y 2: Bits 0, 1 y 2 de la frecuencia de corte / central.
CUTHI $d416 Bits 0 – 7: Bits 3 – 10 de la frecuencia de corte / central.
RESON $d417 Bits 0, 1 y 2: Voces que pasan por el filtro.

Bits 4, 5, 6 y 7: Efecto de resonancia.

SIGVOL $d418 Bits 0, 1, 2 y 3: Volumen global, desde 0 hasta 15.

Bits 4, 5 y 6: Filtros paso bajo (bit 4=1), paso banda (bit 5=1) y paso alto (bit 6 = 1).

Bit 7: Desconecta la voz 3 de la salida de audio.

-VARIOS (SÓLO LECTURA)-

POTX $d419 Conversor analógico digital X.
POTY $d41a Conversor analógico digital Y.
RANDOM $d41b Salida de la voz 3. Si la forma de onda es ruido, sirve para generar valores aleatorios.
ENV3 $d41c Salida de la “envolvente” ADSR para la voz 3.

La forma habitual de trabajar con estos registros será como sigue (el orden puede cambiar):

  • Configurar el volumen.
  • Configurar la frecuencia de la nota.
  • Configurar la envolvente ADSR.
  • Seleccionar la forma de onda.
  • Activar la nota.
  • Esperar un tiempo (duración de la nota).
  • Desactivar la nota.

Lo anterior se puede hacer para una, dos o tres voces. Todo esto se irá viendo en detalle en las entradas que siguen.


Programa de ejemplo: Prog48

Introducción a la música y el sonido con el SID

El sonido es una onda de presión. Dicho de otro modo, cuando la presión del aire cambia, estas oscilaciones son percibidas por el oído humano como “sonido”.

Como toda onda, el sonido puede expresarse como una función matemática del espacio y del tiempo. Del espacio porque el sonido se propaga; en un instante de tiempo dado no es lo mismo el sonido aquí que allí. Y del tiempo porque el sonido cambia; en un lugar dado no es lo mismo el sonido ahora que dentro de unos segundos.

En general, suele ser más interesante el análisis en función del tiempo que el análisis en función del espacio o lugar, así que simplificaremos y entenderemos que el sonido es una función del tiempo. Concretamente, la amplitud del sonido (A) es una función del tiempo, es decir, A = f(t).

A una magnitud física que cambia con el tiempo, por ejemplo, el sonido o un voltaje, sobre todo cuando se utiliza para transportar información, también se le denomina “señal”.

Señal

Las señales en general, y el sonido en particular, se pueden caracterizar por:

  • Su amplitud.
  • Su frecuencia.
  • Su estructura de armónicos.
  • Su dinámica.

La amplitud es la fuerza de la señal. A mayor amplitud más energía. En definitiva, es el valor en el eje de ordenadas (Y), el valor de la señal propiamente dicho en cada instante de tiempo. En el caso del sonido, a la amplitud se le llama “volumen”.

Cuando una señal es periódica (repetitiva) se habla de período (el tiempo que tarda en repetirse) y de frecuencia (el número de repeticiones por unidad de tiempo). Uno de los ejemplos más característicos de señal periódica es una sinusoide (A = sin(t)):

Sinusoide

Aun cuando la señal no sea periódica, se sabe que puede descomponerse en frecuencias. Habrá una frecuencia fundamental F, y luego unos armónicos, que son los múltiplos de F (2F, 3F, etc.). Cada armónico estará presente con mayor o menor energía. A esto se le llama estructura de armónicos y, en el caso particular del sonido, se le llama “timbre”. Cada instrumento musical tiene un timbre característico.

Armonicos

La estructura de armónicos guarda relación con la forma de la onda. Cada forma de onda tiene una estructura de armónicos característica. Por ejemplo, una señal sinusoidal es una frecuencia pura; una señal triangular tiene una frecuencia fundamental y algunos armónicos; etc.

Algunas formas de onda habituales son:

  • Sinusoidal.
  • Triangular.
  • En rampa.
  • Cuadrada.
  • Arbitraria.
  • Etc.

Formas onda

Los sintetizadores de música en general, y el SID en particular, no suelen generar la señal a base de sumar o componer frecuencias. Más bien, ofrecen al usuario una gama variada de formas de onda, cada una con su timbre o estructura de armónicos, y unos filtros que permiten modificar esos timbres.

Un filtro es un circuito electrónico que permite filtrar (eliminar) algunas frecuencias a la vez que deja pasar otras. Desde un punto de vista teórico, los filtros se suelen clasificar en:

  • Filtro paso bajo: Deja pasar las frecuencias inferiores a la de corte.
  • Filtro paso alto: Deja pasar las frecuencias superiores a la de corte.
  • Filtro paso banda: Deja pasar las frecuencias en torno a la frecuencia central.
  • Filtro rechazo banda: Deja pasar todas las frecuencias, menos la frecuencia central.

Filtros.jpg

Por último, está la dinámica, es decir la evolución temporal. Pero ahora no nos referimos tanto a la evolución temporal de la señal completa (esto sería la forma de onda), como a la evolución temporal de cada nota. Una nota es una pequeña porción de la señal, que se caracteriza por una duración (redonda, blanca, negra, corchea, semicorchea, fusa y semifusa) y por una frecuencia.

Pues bien, las notas no suelen tener una amplitud o volumen fijo durante toda su duración. Más bien, suelen tener una amplitud variable que normalmente se modela mediante la envolvente ADSR:

  • A = Attack (ataque).
  • D = Decay (decaimiento).
  • S = Sustain (sostenimiento).
  • R = Release (liberación).

ADSR

Como veremos más adelante, el SID permite trabajar con todo lo descrito en esta entrada: permite seleccionar el volumen, la frecuencia de las notas, su duración, su ADSR, las formas de onda, los filtros aplicados, etc. Y todo ello para tres voces independientes.

Repaso de registros del VIC

En las entradas anteriores hemos revisado las funcionalidades principales del VIC. El objetivo de esta entrada es hacer un repaso sistemático de sus registros, para que sirva de referencia, y para prepararnos ya para cambiar de temática y pasar a tratar la música y el sonido con el SID.

Además de indicar las direcciones de los registros, indicaremos sus nombres según el libro “Mapping the Commodore 64”.

Los registros principales del VIC son:

REGISTRO DIRECCIÓN FUNCIÓN
SP0X, SP0Y, SP1X, SP1Y, … $d000 – $d00f Coordenadas X e Y de los ocho sprites.
MSIGX $d010 Bits más significativos de las coordenadas X de los ocho sprites.
SCROLY $d011 Bits 0, 1 y 2: Scroll en la dirección Y.

Bit 3: Modo 24 o 25 filas (1=25, 0=24).

Bit 4: Blanqueo de pantalla (0=blanqueo).

Bit 5: Modo bitmap (1=activo).

Bit 6: Modo carácter con color de fondo extendido (1=activo).

Bit 7: Bit más significativo –bit 8– del RASTER ($d012).

RASTER $d012 Bits 0 – 7 del RASTER.
SPENA $d015 Bits para activar / desactivar los ocho sprites (1=activo).
SCROLX $d016 Bits 0, 1 y 2: Scroll en la dirección X.

Bit 3: Modo 38 o 40 columnas (1=40, 0=38).

Bit 4: Modo bitmap multicolor (1=activo).

YXPAND $d017 Bits para expandir los ocho sprites en la dirección Y (1=expandido).
VMCSB $d018 Bits 1, 2 y 3: Ubicación de los 2K de los juegos de caracteres personalizados.

Bit 3: Ubicación de los 8K del bitmap.

Bits 4, 5, 6 y 7: Ubicación de la RAM de pantalla.

VICIRQ $d019 Información sobre las interrupciones VIC generadas:

Bit 0: RASTER.

Bit 1: Colisión sprite – fondo.

Bit 2: Colisión sprite – sprite.

Bit 3: Lápiz óptico.

Bit 7: Cualquier fuente.

IRQMSK $d01a Programación de las interrupciones del VIC:

Bit 0: RASTER.

Bit 1: Colisión sprite – fondo.

Bit 2: Colisión sprite – sprite.

Bit 3: Lápiz óptico.

SPBGPR $d01b Bits para controlar la prioridad entre sprites y fondo (0=sprite, 1=fondo).
SPMC $d01c Bits para controlar el multicolor de los ocho sprites (1=multicolor).
XXPAND $d01d Bits para expandir los ocho sprites en la dirección X (1=expandido).
SPSPCL $d01e Bits para controlar las colisiones sprite – sprite (1=sí).
SPBGCL $d01f Bits para controlar las colisiones sprite – fondo (1=sí).
EXTCOL $d020 Color del borde de la pantalla.
BGCOL0 $d021 Color de fondo 0.
BGCOL1 $d022 Color de fondo 1.
BGCOL2 $d023 Color de fondo 2.
BGCOL3 $d024 Color de fondo 3.
SPMC0 $d025 Color compartido 0 de los sprites multicolor.
SPMC1 $d026 Color compartido 1 de los sprites multicolor.
SP0COL, SP1COL, … $d027 – $d02e Colores propios de los ocho sprites.

El VIC tiene algún registro adicional, y alguno de los registros vistos también tiene algún bit adicional, pero lo recogido en la tabla de arriba es más del 90%.

Y a partir de ahora, música y sonido…

Scroll horizontal y vertical

El scroll es una característica gráfica muy interesante. Permite mover la información que se muestra en pantalla suavemente, pixel a pixel. El movimiento puede ser hacia arriba, hacia abajo, hacia la derecha o hacia la izquierda.

Todos hemos visto el efecto del scroll en juegos. La idea es simular el movimiento del personaje, que en realidad está fijo, moviendo el contenido del resto de la pantalla. También es muy parecido a lo que ocurre en una aplicación de PC cuando usamos la barra de scroll porque un documento ocupa más que la ventana.

La pantalla del C64 en principio tiene 25 filas por 40 columnas. Sin embargo, tienes dos modos, el modo de 38 columnas y el de 24 filas, que guardan mucha relación con el scroll. Para verlo más claramente vamos a fijarnos en el scroll horizontal, y más concretamente la situación en que la información nueva entra por la izquierda y la vieja sale por la derecha.

Para que este scroll de izquierda a derecha sea suave, la información nueva que entra por la izquierda tiene que estar lista, digamos pintada, aunque sin verse, en el extremo izquierdo de la pantalla. De este modo, cuando la pantalla se desplaza un pixel hacia la izquierda, cuyo efecto visual equivale a que entra un pixel nuevo por la izquierda, hay información lista para ser mostrada.

Pues bien, este “tener información lista pero que no se ve” se consigue con el modo 38 columnas cuando el scroll es horizontal, y con el modo 24 filas cuando el scroll es vertical. La pantalla sigue teniendo 40 columnas y 25 filas, pero hay dos columnas (la de la izquierda y la de la derecha) que no se ven, o una fila (la de arriba o la de abajo) que no se ve.

Scroll.PNG

El modo 38 columnas se activa poniendo a 0 el bit 3 del registro $d016, que también se utiliza para el modo carácter multicolor y el modo bitmap multicolor. Y el modo 24 líneas sea activa poniendo a 0 el bit 3 del registro $d011, que también se utiliza para el modo bitmap estándar y el modo bitmap multicolor.

Una vez que tenemos la pantalla en el modo 38 columnas (o 24 filas en el caso de scroll vertical), hay que desplazar la pantalla hacia la izquierda. Esto se consigue actuando sobre el registro $d016, concretamente sobre sus bits 0, 1 y 2. Con tres bits podemos establecer 8 valores, desde el 0 hasta el 7, que representan los 8 pixels que se puede mover la pantalla a derecha o izquierda.

En nuestro caso, como queremos hacer scroll de izquierda a derecha (visualmente la información entra por la izquierda y sale por la derecha), lo cual equivale a desplazar la pantalla hacia la izquierda, empezaremos con el valor %000 y lo iremos subiendo hasta el valor %111.

Si el scroll fuera de derecha a izquierda, es decir, desplazar la pantalla hacia la derecha, lo haríamos el revés, empezaríamos en %111 y lo bajaríamos hasta %000.

Llegará un momento en que el scroll alcance su tope, es decir, %111 al hacer scroll de izquierda a derecha. En ese momento, lo que hay que hacer es copiar toda la pantalla desplazada un carácter hacia la derecha, volver a poner el scroll en %000, y alimentar datos nuevos en la columna 1 (oculta).

Scrollx.gif

Análogamente, si el scroll fuera de derecha a izquierda, al alcanzar el tope de %000, habría que copiar toda la pantalla desplazada un carácter hacia la izquierda, volver a poner el scroll en %111, y alimentar datos nuevos en la columna 40 (oculta).

El scroll vertical sigue los mismos principios que el scroll horizontal, pero hay alguna pequeña diferencia. En vez de dos columnas ocultas (modo de 38 columnas) sólo tenemos una fila oculta (modo de 24 filas). Y en vez de desplazar la pantalla con el registro $d016 (bits 0, 1 y 2) lo hacemos con el registro $d011 (bits 0, 1 y 2). Cuando el desplazamiento vale %000 la fila oculta es la primera, y es ahí donde se deben alimentar los datos nuevos. Cuando el desplazamiento vale %111 la fila oculta es la última.


Programa de ejemplo: Prog46