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.
Una nota, por su parte, se caracteriza por una frecuencia y una duración: redonda, blanca, negra, corchea, semicorchea, fusa y semifusa.
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:
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)