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