archivo

Archivos Mensuales: mayo 2010

En este post hablaré un poco de las funcionalidades de sonido que posee el Sinclair QL, tema con en el que he estado “jugando” últimamente. Mis pretensiones no van más allá de la mera producción de melodías sencillas con SuperBASIC y la simple curiosidad por el uso de las (limitadas) capacidades sonoras del QL. Sin buscar demasiado, he encontrado dos fuentes útiles: a) el libro ‘QL SuperBASIC Definitive Handbook’ de Jan Jones y b) un artículo de la revista QL-Today que he encontrado en el sitio de Dilwyn Jones donde se habla este tema y que he tomado como guía para este post.

Empecemos …

Las facilidades el QL para producir sonidos son bastante básicas, un sólo comando BEEP que en su forma más simple puede tener duración y tono. Pero, incluso con algo tan simple, podemos crear melodías sencillas y, posiblemente, escribir un programa corto para componer y tocar melodías con la información correcta.

El comando BEEP del QL usa valores en sus parámetros que no son tan obvios, además el manual del QL no explica realmente mucho. Por suerte, el libro ‘QL SuperBASIC Definitive Handbook’ de Jan Jones es más explícito.

La sintaxis básica del comando BEEP es:

BEEP duración, tono 

La duración se expresa como la longitud del sonido en unidades de 72 microsegundos, el rango de valores permitidos es de 0 a 32767. Así, para un segundo de duración de un determinado sonido, el valor del parámetro duración debe ser 13.889 (unidades de tono). La duración 0 no es particularmente útil, sólo indica que la nota debe estar sonando permanentemente (hasta que otro comando BEEP si parámetros cancele la señal). Puede ser útil en determinados casos en los que queramos que un sonido continúe hasta que ocurra algo para detenerlo.

Hay un aspecto importante en el manejo del sonido en el QL. Concretamente en lo referente a que no hay facilidades para manejar una cola de notas musicales o tonos de duraciones determinadas. En su lugar se debe hacer una pausa para luego interrumpir el sonido con otro comando BEEP en blanco.

Por ejemplo, una forma de manejar la reproducción de sonidos debe tener la siguiente forma:

BEEP duración, tono 
PAUSE longitud
BEEP

También puede manejarse de la siguiente manera, donde definimos un bucle que se repite hasta que el tono especificado ha dejado de sonar:

BEEP duracion, tono 
REPeat loop: IF NOT BEEPING THEN EXIT loop

El tono es más difícil de ajustar. Puede tomar valores del rango 0 a 255, lo cuales no están directamente relacionados con las notas musicales. La aproximación más cercana que podemos encontrar en la documentación es el siguiente cuadro publicado en un boletín de Sinclair. En este cuadro se relaciona el valor del tono con la notación musical:

a    41
a#   38
b    36
c    33 (DO cetral)
c#   31
d    28
d#   26
e    24
f    22
f#   20
g    19
g#   17
a    15
a#   14
b    12
c    11
c#   10
d    9
d#   8
e    7
f    6
f#   5
g    4
g#   3

En términos de la clave de sol, esto equivale a lo siguiente:

En cuanto a la duración de las notas, si vas calcular la duración de una redonda, blanca, negra, corchea y todas las demás figuras del lenguaje musical, debes tener en cuenta que éstas se basan en la mitad o el doble de tiempo unas de otras. Se trata entonces de calcular la duración relativa de todas las figuras del lenguaje musical. La siguiente tabla muestra dicha duración relativa.

redonda        = 4 * negra
blanca         = 2 * negra
negra          = 1 *
corchea        = 0.5 * negra  (1/2)
semi-corchea   = 0.25 * negra (1/4)
fusa           = 0.125 * negra (1/8)
semifusa       = 0.0625 * negra (1/16)

Lo rápido o lento que debe ser tocada una melodía depende del tiempo o “tempo” especificado para ella en el lenguaje musical (Allegro, Andante, Presto, …. ).De cara a ajustar este tiempo con SuperBASIC debemos utilizar el retardo adecuado con la orden PAUSE para esperar un cierto número de unidades de tiempo, N/50 de segundo. Tendremos entonces que ajustarnos para aproximarnos al número de latidos por minuto, según lo requerido por la melodía o la música en cuestión.

Para poner a prueba lo que nos dice la teoría, he escrito un pequeño programa en SuperBASIC para tocar una simple melodía, el archiconocido “cumpleaños feliz” (aprovechando que estamos en el 25 aniversario del Sinclair QL – MGE).

Como veréis en el programa, no toda la teoría se cumple de forma exacta a lo que he descrito en este post. Concretamente hay tres cambios que he tenido que introducir:
1) En mi QL con Gold Card he tenido que poner un PAUSE 1, para que todo funcione (tal vez debido al incremente de velocidad aportado por la Gold Card).
2) Para que la melodía salga mínimamente afinada he cambiado los valores de las notas LA (A) y DO (C) a los valores 15.5 y 10.5 (en lugar de los valores 15 y 11 que propone la tabla propuesta en el boletín de Sinclair.
3) Por comodidad, en la duración de las notas musicales yo he tomado la unidad 1 para representar a la semicorchea, 2 para la corcha, 4 para la negra. Luego multiplico por 3000 para conseguir que la melodía se reproduzca a un tiempo “Andante” del lenguaje musical (unas 100 pulsaciones por segundo).

100 REMark ---------------------------------
110 REMark --- Toca cumpleaños feliz.
120 REMark ---------------------------------
130 :
140 RESTORE 
150 CLS
160 :
170 notas% = 25
180 DIM Tonos(notas%)
190 DIM Duracion(notas%)
200 :
210 Lee Tonos, notas%
220 Lee Duracion, notas%
230 :
240 Toca Tonos, Duracion, notas%
250 :
260 STOP
270 :
280 :
290 REMark --- Datos -----------------------
300 :
310 REMark --- Tonos
320 DATA 19,19,15.5,19,10.5,12
330 DATA 19,19,15.5,19,9,10.5
340 DATA 19,19,4,7,10.5,12,15
350 DATA 6,6,7,10.5,9,10.5
360 :
370 REMark --- Tiempos
380 DATA 3,1,4,4,4,8
390 DATA 3,1,4,4,4,8
400 DATA 3,1,4,4,4,4,8
410 DATA 3,1,4,4,4,8
420 :
430 :
440 REMark --- Procedimientos --------------
450 :
460 DEFine PROCedure TocaSonido (Dur, Ton)
470   BEEP Dur*3000,Ton
480   PAUSE 1
490   REPeat loop
500     IF NOT BEEPING THEN EXIT loop
510   END REPeat loop
520 END DEFine 
530 :
540 DEFine PROCedure Lee (array, n%)
550   LOCal i
560   FOR i = 1 TO n%
570     READ array(i)
580   END FOR i
590 END DEFine 
600 :
610 DEFine PROCedure Toca (Ton, Dur, n%)
620   LOCal i
630   FOR i = 1 TO n%
640     PRINT i, Dur(i),Ton(i)
660     TocaSonido Dur(i),Ton(i)
670   END FOR i
680 END DEFine 

Como vemos, las funcionalidad del QL para reproducir sonidos y melodías son por un lado, muy elementales y simples, pero por otro lado son de fácil uso y suficientes para la generación de sonidos y melodías sencillas para acompañar a nuestros programas.


La máquina de Turing es un dispositivo puramente teórico, que se utiliza para deducir si un problema es informatizable o no.

En este artículo vamos a echar una mirada al lado teórico de los ordenadores: al campo que se denomina “ciencia de la computación”. Tal ciencia es a la informática lo que las matemáticas a la ingeniería, es decir, un campo que se caracteriza por ser extremadamente teórico pero del cual derivan las ideas prácticas.

La máquina Turing, por ejemplo, es una idea puramente teórica que desarrolló Alan Turing como ayuda para estudiar los algoritmos y la posibilidad de informatización. Se trata en realidad del “mínimo ordenador posible”, de modo que si se puede demostrar que un problema determinado no se puede resolver utilizando una máquina de Turing, entonces se puede afirmar que dicho problema no es “informatizable”. Turing pensó que un ordenador mínimo de este tipo necesitaría tres configuraciones: un almacenamiento externo para grabar y almacenar la información de entrada y de salida; un medio para leer dicho almacenamiento y para escribir en él, y en tercer lugar una unidad de control que permitiese determinar las acciones a emprender.

Por definición, una máquina de Turing posee, entonces, una cinta (si le sirve de ayuda, imagínesela como una cinta magnética) de longitud infinita (es decir: sea cual fuere la cantidad de cinta necesaria para solucionar un problema, siempre habrá la suficiente). La cinta está dividida en cuadrados, que o bien estarán en blanco o contendrán un símbolo. A lo largo de la cinta se mueve una “cabeza”, que puede leer o escribir símbolos en los cuadrados y que recibe sus instrucciones desde una unidad de control que le proporciona una doble indicación: cuáles son los símbolos que debe escribir y en qué dirección se ha de mover a continuación.

La unidad de control posee un programa de ejecución, y en este sentido se puede decir que cada máquina Turing se “fabrica” específicamente para realizar una aplicación, ya que en la especificación no existen medios para cargar o alterar un programa. Hemos entrecomillado la palabra fabricar porque las únicas máquinas de Turing que se han construido físicamente lo fueron con fines puramente educativos. Sin embargo, escribir un programa en BASIC que imite el funcionamiento de una máquina Turing en un ordenador personal es un ejercicio relativamente sencillo.

El programa de control de una máquina Turing consta de un conjunto de “quíntuplos”, o sentencias que contienen cinco elementos. Qué quíntuplo se ejecuta en cada etapa depende de dos factores: el símbolo que contenga el cuadrado que esté debajo de la cabeza de la cinta, y el “estado” o “condición de la máquina. Dicho estado es una cualidad estrictamente arbitraria: podemos especificar que la máquina se ponga en marcha en el estado “Sa” y que cuando llegue al estado especial “H” entonces se detenga, dándose por acabado el cálculo. Entretanto, el estado cambiará muchas veces de acuerdo con las instrucciones de los “quíntuplos”. El estado tan sólo refleja lo que está sucediendo hasta el momento en el cálculo y ayuda a seleccionar qué “quíntuplo” se ejecutará a continuación (nuevamente, si le sirve de ayuda, imagíneselo como una variable de bandera en un programa BASIC).

Los cinco elementos de que consta cada quíntuplo son:
1) El estado en curso de la máquina;
2) El símbolo del cuadrado de la cinta que se halle debajo de la cabeza;
3) El símbolo a escribir en ese cuadrado, que será el mismo que en 2) si no se requiere ninguna modificación de los datos;
4) El estado en que la máquina ha de entrar ahora;
5) La dirección en la que se debe mover la cabeza de cinta (izquierda o derecha)

El “quíntuplo” (Sa,5,3,Sb,D), por ejemplo, se ejecutará siempre que la máquina esté en estado Sa y que la cabeza de la cinta lea un 5. El 5 se reemplazará luego por un 3, la máquina pasará del estado Sa al Sb y la cabeza de la cinta se desplazará un cuadrado hacia la derecha.

Diseñar una máquina de Turing teórica para efectuar una tarea determinada implica especificar el formato en el cual se presentarán a la máquina sus datos de entrada en cinta, el formato de los datos de salida en cinta cuando se termine el cálculo (es decir, con la máquina en estado H), y el grupo de quíntuplos requeridos para ejecutar el algoritmo.

En el ejemplo siguiente hemos diseñado una máquina de Turing para realizar la función AND. Estableceremos los dos bits de entrada (cada uno con un 1 o un 0) en cuadros adyacentes, seguidos de un signo de interrogación, que se ha de reemplazar por la respuesta (nuevamente, un 1 o un 0, dependiendo de la dos entradas). Por convenio, hemos agregado un asterisco a los dos extremo del área de datos, y pondremos la máquina en funcionamiento en el estado Sa encima del asterisco situado más a la izquierda, acabando sobre el situado más a la derecha.

Se necesita un total de diez quíntuplos para especificar esta máquina, si bien, como se podrá ver en el ejemplo con que trabajamos (1 AND 1 = 1) se utilizan cinco para cualquier ejecución. Si usted prueba la misma máquina para, supongamos, 0 AND 1, descubrirá que de los diez quíntuplos se selecciona un grupo de quíntuplos diferentes.

(1)
La máquina Turing
Este ejemplo muestra la construcción de una máquina Turing para realizar la función AND. Los dos bits de entrada están establecidos en cuadros adyacentes, seguidos por un signo de interrogación que será reemplazado por el resultado. Flanquean el área de datos dos asteriscos para que actúen como bordes. Los diez quíntuplos reseñados abajo especifican la operación de esta máquina, aunque para cualquier ejemplo con el cual se trabaje (en este caso 1 AND 1), sólo se utilizan cinco de los diez.

(2)
La máquina comienza a funcionar en el estado Sa con la cabeza posicionada sobre el asterisco situado a la izquierda. El único efecto de este quíntuplo es mover la cinta hacia la derecha.

(3)
Si el siguiente cuadrado contiene un 1 entonces se selecciona este quíntuplo y la máquina pasa a estado Sc, instruyéndola para que se mueva hacia la derecha. Si se ha leído un 0, el resultado es Sb.

(4)
Con la máquina en estado Sc, un 1 es el segundo cuadrado da Se. En otro caso, la máquina pasaría a Sd.

(5)
Ante signo de interrogación, según el estado de la máquina, Se o Sd, se escribirá en su lugar un 1 o un 0. En cualquier caso, la máquina se coloca en estado Sf.

(6)
La máquina pasa a estado de detención (H) con el segundo asterisco. Se puede verificar sobre el papel el funcionamiento para 1 AND 0, 0 AND 1 y 0 AND 0.

(Fuente: Reproducción del artículo “Términos clave – La Cinta Teórica”, Mi Computer, fascículo 22)

Para divertirnos con nuestro QL no solo tenemos los videojuegos del tipo “matamarcianos” y demás engendros, sino que también podemos emplear, a modo de diversión, nuestro querido SuperBASIC y un poco de ¡matemáticas!

Pues eso, proponemos en este post un simple ejercicio, convertir números decimales (en base 10) en sus equivalentes en binario y hexadecimal utilizando el SuperBASIC del QL.

Un “poquito” de teoría

El sistema binario es un sistema de numeración donde los números se representan utilizando solamente las cifras cero y uno (0 y 1). Es el sistema de numeración ideal para las computadoras ya que éstas trabajan internamente con dos niveles de voltaje (encendido 1, apagado 0).

El algoritmo utilizado para pasar de decimal a binario consiste en dividir el número del sistema decimal entre 2, cuyo resultado entero se vuelve a dividir entre 2, y así sucesivamente. Para construir el número binario debemos utilizar los restos de estas divisiones ordenados del último al primero. Obtendremos de esta manera una secuencia de unos y ceros que representará al número binario que buscamos.

Otro sistema de numeración muy utilizado en informática es el sistema hexadecimal que también es un sistema de numeración posicional de base 16 (empleando por tanto 16 símbolos, 0-9 y A-F). La justificación de la utilización de este sistema ses debido a que los ordenadores suelen utilizar el byte u octeto como unidad básica de memoria; y dos dígitos hexadecimales corresponden exactamente a un byte. Cada dígito hexadecimal representa 4 bits de información, llamado nibble.

El algoritmo es similar al anterior, sólo que debemos dividir por 16 y transformar el resto de la división (de 0 – 15) en un dígito hexadecimal.

La práctica

Veamos ahora el código fuente de un programa en SuperBASIC que transforma un número entero decimal en su equivalente binario y hexadecimal.

1000 REMark ------
1010 REMark Conversor de números decimal a binario / hexadecimal
1020 REMark -------
1030 :
1035 IniVariables
1040 :
1050 REPeat SecPrin
1060   n = PideNumero
1070   Binario$ = ConvierteBinario$ (n)
1080   Hexadecimal$ = ConvierteHexadecimal$ (n)
1090   AT 2,2: PRINT "- en binario es:"
1095   AT 2,25: PRINT Binario$
1100   AT 3,2: PRINT "- en hexadecimal es:"
1105   AT 3,25: PRINT Hexadecimal$
1110   IF Salir% = 1 THEN
1120      EXIT SecPrin
1130   END IF
1140 END REPeat SecPrin
1150 :
1160 :
1170 STOP
1180 :
1190 :
1200 DEFine PROCedure IniVariables
1210   Binario$ = ""
1220   Hexadecimal$ = ""
1230   n = 0
1235   DigHexa$ = "0123456789ABCDEF"
1240 END DEFine
1250 :
1260 :
1270 DEFine FuNction PideNumero
1280   LOCal nn
1290   INK 7:PAPER 0:CLS
1300   INPUT "Introduce un número entero positivo entre 1 y 65535: ", nn
1310   RETurn nn
1320 END DEFine
1330 :
1340 :
1350 DEFine FuNction ConvierteBinario$ (num)
1360   LOCal nB$, byteHi%, byteLo%
1370   nB$ = ""
1380   IF num < 256 THEN
1390     nB$ = ByteBinario$(num)
1400   ELSE
1410     byteHi% = INT(num / 256)
1420     byteLo% = num - 256 * byteHi%
1430     nB$ = ByteBinario$(byteHi%) & ByteBinario$(byteLo%)
1450   END IF
1460   RETurn nB$
1470 END DEFine
1480 :
1490 :
1500 DEFine FuNction ByteBinario$ (num)
1510   LOCal cadB$, i, nTmp, resto%, numX
1520   numX = num
1530   cadB$ = ""
1540   FOR i = 8 TO 1 STEP -1
1550     nTmp = INT(numX / 2)
1560     resto% = numX - 2 * nTmp
1570     cadB$ = CHR$(48 + resto%) & cadB$
1580     numX = nTmp
1590   END FOR i
1600   RETurn cadB$
1610 END DEFine
1620 :
1630 :
1640 DEFine FuNction ConvierteHexadecimal$ (num)
1650   LOCal cadH$, byteHi%, byteLo%
1660   cadH$ = ""
1670   IF num < 256 THEN
1680     cadH$ = ByteHexa$(num)
1690   ELSE
1695     byteHi% = INT(num / 256)
1697     byteLo% = num - byteHi% * 256
1698     cadH$ = ByteHexa$(byteHi%) & ByteHexa$(byteLo%)
1699   END IF
1720   RETurn cadH$
1730 END DEFine
1740 :
1750 :
1760 DEFine FuNction ByteHexa$(num)
1770   LOCal cadH$, nibH%, nibL%
1780   nibH% = INT(num/16)
1790   nibL% = num - nibH% * 16
1800   cadH$ = DigHexa$(nibH% + 1) & DigHexa$(nibL% + 1)
1810   RETurn cadH$
1820 END DEFine
1830 :
1840 :
1850 DEFine FuNction Salir%
1860   LOCal t$, r%
1870   r% = 0
1880   PRINT: INK 4
1890   PRINT "(S)alir / (O)tro n™mero"
1900   REPeat tecla
1910     t$ = INKEY$(-1)
1920     IF t$ = "s" OR t$ = "S" THEN r% = 1: EXIT tecla
1930     IF t$ = "o" OR t$ = "O" THEN r% = 0: EXIT tecla
1940     BEEP 100,100
1950   END REPeat tecla
1960   RETurn r%
1970 END DEFine

El ejemplo es incompleto, sólo convierte números entre 0 y 65535, ¿quien se anima a mejorarlo para ampliar este rango? ….

Para saber más

http://es.wikipedia.org/wiki/Sistema_binario
http://es.wikipedia.org/wiki/Sistema_hexadecimal