Skip to content

5.02. Más en concreto sobre el CPC464

sevioptero edited this page Oct 6, 2019 · 1 revision

Capítulo 5. Cuando usted guste

Parte 2: Más en concreto sobre el CPC464

Contenido:


En esta sección vamos a tratar algunas cuestiones específicas del CPC464. La información básica sobre estos temas se puede encontrar en el "Curso de introducción" y en el capítulo titulado "Lista completa de las palabras clave del BASIC de Amstrad".

Temas tratados en esta sección:

  • Juegos de caracteres.
  • ASCII.
  • Variables.
  • Lógica.
  • Caracteres definidos por el usuario.
  • Formatos de escritura.
  • Ventanas.
  • Interrupciones.
  • Datos.
  • Sonido.

Caracteres

Cuando se ponga al teclado de su CPC464, no dé por supuesto que en la pantalla vayan a aparecer letras y números reconocibles. Ya hemos explicado que el ordenador no es una máquina de escribir. Lo que usted hace es pulsar una serie de conmutadores eléctricos; las señales eléctricas así producidas son traducidas por los circuitos internos para enviar a la pantalla grupos de puntos. Según sea la colocación de esos puntos, podremos reconocer letras, números u otros caracteres del "juego de caracteres" del CPC464.

Algunos de estos caracteres no son accesibles directamente a través del teclado, sino mediante la instrucción PRINT CHR$(<número>). Esto es así porque la información se almacena en el ordenador en unidades de 1 byte y, como vimos en la parte 1 de este capítulo, 1 byte puede tener 256 formas posibles. Dado que el ordenador tiene que dedicar al menos un byte a cada carácter almacenado, más vale que aprovechemos las 256 combinaciones posibles en lugar de conformarnos con los 96 "caracteres estándar" de las máquinas de escribir y desperdiciar los 160 restantes.

Los caracteres estándar son un subconjunto del juego total de caracteres. Su nombre en informática es "caracteres ASCII", término derivado de "American Standard Code for Information Interchange" (código estándar norteamericano para el intercambio de la información). Se trata de un sistema diseñado para asegurar la compatibilidad de los datos transmitidos de un ordenador a otro. En el capítulo 7 hemos dado la lista de todos los caracteres ASCII, así como de los demás caracteres disponibles en el CPC464, junto a sus números de código.

Vamos a verlos

Seguramente ya no encierra ningún secreto para usted un programa tan sencillo como éste:

10 FOR n=32 TO 255
20 PRINT CHR$(n);
30 NEXT

con el que hacemos que el ordenador muestre en la pantalla el juego completo de caracteres. Pero estudiemos un poco la esencia de este programa.

Lo primero que debemos observar es que al ordenador no le hemos dicho PRINT "abcdefghijklmn ...", sino PRINT CHR$(n). En vez de mencionar explícitamente los caracteres hemos puesto en su lugar una "variable". Una variable es un elemento de información que varía según impongan las instrucciones del programa. (El nombre que hemos dado a la variable en este caso, n, es arbitrario; podríamos haber puesto cualquier letra o combinación de letras, cualquier cosa que no fuera una palabra reservada de BASIC.)

¿Cómo sabemos que es una variable?

Un número tal como el 5 es fijo, está entre el 4 y el 6 y no tiene nada de variable. El carácter n también es fijo: es una letra concreta del alfabeto.

Entonces, ¿cómo distingue el ordenador las variables de las constantes? Si hubiéramos querido decirle que considerara la n como letra del alfabeto, la habríamos escrito entre comillas: "n". El ordenador habría respondido con el mensaje Syntax error, porque no entendería la línea FOR "n"=32 TO 255.

Al escribir la n sin comillas le hemos dicho al ordenador que n es una variable. La instrucción FOR de BASIC tiene que ir seguida del nombre de una variable, y el ordenador da por supuesto que lo que pongamos después de FOR es una variable.

También le hemos dicho al ordenador n=32 TO 255, con lo que hemos especificado el margen de variación de la variable: una sucesión que empieza en 32 y termina en 255.

Una vez declarada la variable, debemos decirle al ordenador qué tiene que hacer con ella; eso es lo que hace la línea 20:

20 PRINT CHR$(n);

Esta instrucción hace que el ordenador, cualquiera que sea el valor de n, busque en su memoria el carácter que corresponde a ese valor y lo escriba en la pantalla.

El punto y coma impide que el ordenador realice un retorno de carro y avance de línea después de escribir cada carácter. (De no ser así, los caracteres aparecerían uno debajo de otro en la primera columna de cada línea.)

La línea 30 le dice al ordenador que cuando haya concluido la tarea con el primer valor de n (que es el 32) debe retornar a la línea en la que está FOR y volver a hacer lo mismo con el siguiente (NEXT) valor de la variable n. Este mecanismo, denominado "bucle", es fundamental para la programación. Gracias a él nos ahorramos el tener que escribir largas series de instrucciones similares. Usted aprenderá enseguida a incluirlo en sus programas.

Cuando el bucle FOR ... NEXT alcanza el límite superior del margen declarado (255), el bucle termina y el ordenador vuelve al modo directo y muestra el mensaje Ready. Este mensaje indica que el ordenador está preparado para recibir más instrucciones, una de las cuales podría ser RUN, para ejecutar otra vez el programa. El programa está almacenado en la memoria y lo seguirá estando hasta que le digamos al ordenador que lo borre o apaguemos la máquina.

Este programa ilustra un hecho esencial de la informática: todo lo que el ordenador hace está relacionado con números. El ordenador ha escrito el alfabeto y todos los demás caracteres usando como referencia para acceder a ellos un número. Cuando usted pulsa la tecla A, no le está pidiendo al ordenador que escriba esa letra, sino que busque en su memoria la información numérica que necesita para exhibir el carácter en la pantalla. La localización de esa información es función del código numérico que se activa al pulsar la tecla. (Cada carácter tiene un código asociado; la relación completa se da en el capítulo titulado Para su referencia.)

Pero tampoco el hecho de visualizar el carácter tiene nada que ver con "escribir", sino que es un proceso numérico.

Por ejemplo, el código ASCII de la letra A es el 65. El ordenador tampoco entiende el número 65, por lo que tiene que traducirlo de decimal a una forma que le resulte más familiar: el código de máquina. Ya hemos estudiado los principios de esta conversión en la primera parte de este capítulo.

Al principio, la conversión de la notación decimal, a la que estamos tan acostumbrados, a notación hexadecimal nos parece muy difícil. Pensar en números decimales nos parece tan natural que cambiar de sistema de numeración es como cambiar de mano el tenedor y el cuchillo.

Para manejar la notación hexadecimal es necesario adquirir cierto grado de destreza mental. Una vez adquirida, se empieza a entender el por qué de muchos hechos informáticos y se hace patente la elegancia de la estructura de este sistema de numeración.

Si no conoce los sistemas binario y hexadecimal, le sugerimos que lea detenidamente la primera parte de este capítulo.

Cuando el ordenador ha convertido la pulsación de la tecla A en un número comprensible para él, busca en una zona de la memoria especificada por ese número, y en ella encuentra otra serie de números que describen la forma de la letra. El carácter que usted puede ver en la pantalla está formado por un bloque de datos, almacenado en la memoria en forma de "matriz" numérica:

Matriz en blanco (retícula) a minúscula A mayúscula

Los elementos de la matriz son puntos dispuestos en filas columnas. El carácter se "escribe" encendiendo y apagando correctamente los puntos. En el CPC464 cada matriz tiene 8 filas y 8 columnas. Si entre los 255 caracteres no encuentra el que necesita, usted mismo puede definirlo a su gusto con la instrucción SYMBOL que describiremos más adelante.

Los caracteres "definidos por el usuario" se construyen especificando cada uno de los 64 puntos de la matriz. Las combinaciones posibles con 1.84467E+19, es decir, aproximadamente un 2 seguido de 19 ceros. Si a esto añadimos la posibilidad de agrupar caracteres para formar bloques más grandes, vemos que las posibilidades de generar gráficos sólo están limitadas por la imaginación del usuario.

Lógica

Una diferencia fundamental entre una calculadora y un ordenador radica en la capacidad de éste para manejar operaciones lógicas y tomar decisiones en instrucciones del tipo IF ... THEN ... (si ... entonces ...). Para ello, los operadores lógicos tratan los valores a los que son aplicados como grupos de bits y examinan y modifican los bits uno a uno. No es fácil describir las operaciones lógicas sin antes dar unas definiciones concisas.

Las dos mitades de una expresión lógica son los "argumentos". Una expresión lógica tiene la siguiente forma:

<argumento> [<operador lógico> <argumento>]

donde <argumento> puede ser:

  • NOT <argumento>
  • <expresión numérica>
  • <expresión de relación>
  • (<expresión lógica>)

Los dos argumentos de un operador lógico tienen que ser enteros; de lo contrario se produce el error número 6.

Los operadores lógicos (en orden de prioridad) y su efecto sobre los bits son los siguientes:

  • AND. El resultado es 0 a menos que los bits de los dos argumentos sean 1.
  • OR. El resultado es 1 a menos que los bits de los dos argumentos sean 0.
  • XOR. El resultado es 1 a menos que los bits de los dos argumentos sean iguales.

AND es el operador lógico más utilizado.

PRINT 10 AND 10

da como resultado 10.

PRINT 10 AND 12

da como resultado 8.

PRINT 10 AND 1000

también da como resultado 8.

Esto se debe a que los números 10 y 1000 han sido convertidos a su forma binaria:

      1010
1111101000

La operación AND comprueba los bits dos a dos. Si los dos bits de las dos filas son 1, el resultado es 1:

0000001000

y este número binario es el 8 decimal. El operador lógico AND se utiliza para detectar cuándo se cumplen simultáneamente dos condiciones. He aquí un ejemplo que explica como:

10 INPUT "Dia del mes: ",dia
20 INPUT "Mes número: ",mes
30 IF dia=25 AND mes=12 THEN 50
40 CLS:GOTO 10
50 PRINT "Feliz Navidad!"

OR funciona de forma análoga, pero da como resultado 1 a no ser que los bits de los dos operandos sean 0, en cuyo caso el resultado es 0. Aplicado a los mismos números que en el ejemplo de AND,

PRINT 1000 OR 10
1002

Bit a bit:

      1010
1111101000

cuyo resultado es

1111101010

Un programa ejemplo:

10 CLS
20 INPUT "Mes número: ",mes
30 IF mes=12 OR mes=1 OR mes=2 THEN 50
40 GOTO 10
50 PRINT "Estamos en invierno!"

El operador NOT invierte todos los bits del argumento (convierte el 0 en 1, y viceversa):

10 CLS
20 INPUT "Mes número: ",mes
30 IF NOT(mes=6 OR mes=7 OR mes=8) THEN 50
40 GOTO 10
50 PRINT "No estamos en verano!"

Observe que se pueden combinar los operadores lógicos, sin más limitación que la longitud de la línea:

10 INPUT "Dia del mes: ",dia
20 INPUT "Mes número: ",mes
30 IF NOT(mes=12 OR mes=1) AND dia=29 THEN 50
40 CLS:GOTO 10
50 PRINT "No es ni diciembre ni enero, pero puede ser un año bisiesto"

El resultado de una expresión de relación es -1 o 0. La representación binaria del número -1 es una sucesión de bits iguales a 1; para el 0, todos los bits son 0. El resultado de una operación lógica entre argumentos de este tipo da –1 (verdadero) o 0 (falso).

Añada las siguientes líneas al programa anterior:

60 PRINT NOT(mes=12 OR mes=1)
70 PRINT (mes=12 OR mes=1)

Si al ejecutar el programa introduce 29 para el día y 2 para el mes, obtendrá el mensaje de la línea 50, y las líneas 60 y 70 escribirán los resultados de las operaciones.

Finalmente, XOR (OR eXclusivo) produce como resultado "verdadero" siempre que los argumentos sean diferentes.

A continuación resumimos todo lo dicho en una tabla, denominada tabla de verdad. Es una forma muy clara de ilustrar qué sucede en una operación lógica bit a bit.

Argumento A:      1010
Argumento B:      0110

Resultado de AND: 0010
Resultado de OR:  1110
Resultado de XOR: 1100

Caracteres definidos por el usuario

Una de las primeras aplicaciones que el lector encontrará para los números binarios es el diseño de caracteres con la instrucción SYMBOL. Como sabemos, el carácter se diseña en una retícula de 8 por 8; cada una de las 8 filas se convierte en un número binario poniendo un 1 en lugar del pixel que debe ser iluminado, y un cero en lugar del pixel que debe quedar del color del papel. Los 8 números así obtenidos serán los parámetros de SYMBOL. Por ejemplo, para definir un carácter que representa una casa:

la orden es

SYMBOL 240,8,60,66,165,129,181,177,255

o bien

SYMBOL 240,&08,&3C,&42,&A5,&81,&B5,&B1,&FF

o bien

SYMBOL 240,&X00001000,&X00111100,&X01000010,&X10100101,&X10000001,&X10110101,&X10110001,&X11111111

Para escribir el carácter así definido:

PRINT CHR$(240)

Finalmente, para agrupar caracteres se puede hacer

adosado$=CHR$(240)+CHR$(240)
PRINT adosado$

o bien

urbanizacion$=STRING$(15,240)
PRINT urbanizacion$

La imprenta

PRINT es la primera instrucción que se usa cuando se empieza a programar. En principio es muy sencilla, pero podemos complicarla considerablemente. En efecto, no basta con pedirle al ordenador que escriba, sino que también debemos decirle dónde y cómo.

Formato de escritura

La instrucción PRINT se puede utilizar de diversas formas. La más sencilla es poner a su derecha el elemento que se desea escribir, que puede ser un número, una cadena literal o el nombre de una variable:

PRINT 3
 3
PRINT "hola"
hola 
a=5
PRINT a
 5
a$="prueba" 
PRINT a$
 prueba 

En una instrucción PRINT se pueden poner varios elementos, intercalando entre ellos un separador, o bien TAB o SPC. Los separadores pueden ser la coma o el punto y coma. El punto y coma hace que el siguiente elemento se escriba inmediatamente a continuación del que se acaba de escribir; la coma provoca el salto a la siguiente zona de escritura. La anchura implícita de la zona de escritura es 13, pero se la puede modificar con la orden ZONE:

PRINT 3;-4;5
 3 -4  5
PRINT "buenos","dias"
 buenos             dias
PRINT 3,-4,5
 3             -4              5
ZONE 4
PRINT 3,-4,5
 3    -4     5

Observe que los números positivos llevan un espacio a la izquierda, mientras que en los negativos ese espacio está ocupado por el signo –. Todos los números llevan un espacio en blanco a la derecha. Las cadenas se escriben literalmente tal como están entre las comillas.

La función SPC lleva como parámetro una función numérica; "escribe" tantos espacios como indique el valor de la expresión. Si el valor es negativo, se toma el 0; si es mayor que la anchura de la ventana actual se toma esa anchura:

PRINT SPC(5)"hola"
     hola
x=3
PRINT SPC(x*3)"hola"
         hola

TAB es similar, pero el número de espacios que escribe es el necesario para que el siguiente elemento se empiece a escribir en la columna especificada.

La ventana en la que se escribe es la número 0, a no ser que se especifique otro número de canal (#) antes de la lista de elementos. Se pueden especificar otros canales para enviar la salida a otras ventanas. Los canales 8 y 9 están reservados para la impresora y la cinta, respectivamente. (Obsérvese que para "escribir" en el canal #9 se debe utilizar WRITE en lugar de PRINT.)

PRINT "hola"
hola                    - ventana 0
PRINT #0,"hola"
hola                    - tambien ventana 0
PRINT #4,"hola"
hola                    - ventana 4 (primera linea de la pantalla)
PRINT #8,"hola"
hola                    - en la impresora (si esta conectada)

Con TAB y SPC se pueden controlar los formatos más sencillos, pero en cuanto el formato deseado sea un poco más complejo habrá que utilizar PRINT USING y una "plantilla" adecuada. Una plantilla de formato es una expresión literal que contiene caracteres especiales, cada uno de los cuales especifica un formato determinado. Estos caracteres, denominados "especificadores de formato", están explicados en detalle en la descripción de PRINT USING (capítulo 3). Aquí vamos a dar algunos ejemplos.

En primer lugar, he aquí los formatos disponibles para escribir cadenas literales:

" " escribe tantos caracteres como espacios haya en la plantilla, más dos:

PRINT USING "      ";"cadena de prueba"
cadena d

"!" escribe solamente el primer carácter de la cadena:

PRINT USING "!";"cadena de prueba"
c

Pero el formato literal más útil es seguramente "&". Con él se anula una función de BASIC por la cual, si una cadena es demasiado larga como para caber en la línea actual, el ordenador la escribe al principio de la línea siguiente. PRINT USING "&"; desactiva esa función. (En el siguiente ejemplo ponga BORDER 0 para hacer visibles los bordes del papel.)

MODE 1:LOCATE 39,1:PRINT "demasiado"
                                    -- linea 1 
demasiado                           -- linea 2
                                     
MODE 1:LOCATE 39,1:PRINT USING "&";"demasiado"
                                 de -- linea 1
masiado                             -- linea 2

Para los números se dispone de gran variedad de plantillas. La más sencilla es PRINT USING "#####", en la que cada # reserva espacio para un dígito:

PRINT USING "######";123
   123

La posición del punto decimal se puede especificar incluyendo un punto en la plantilla:

PRINT USING "####.#####';12.45
  12.45000

Los dígitos que quedan a la izquierda del punto decimal se pueden agrupar de tres en tres, separados por comas, si se pone una coma a la izquierda del punto en la plantilla:

PRINT USING "########,.####";123456.78
   123,456.7800

En el formato se pueden incluir los signos de dólar y de libra esterlina, para que aparezca siempre el signo monetario antes del primer dígito, aunque el número no llene el formato. Esto se consigue poniendo $$ en la plantilla:

PRINT USING "$$##";7
$7

PRINT USING "$$##";351
$351

PRINT USING "$$####,.##";1234.567
$1,234.57

Observe cómo se ha redondeado este último número.

Se puede rellenar el espacio sobrante por la izquierda con asteriscos poniendo ** en la plantilla:

PRINT USING "**####.#";12.22
****12.2

Esto último se puede combinar con los signos monetarios poniendo **$ en la plantilla.

Un signo + al principio de la plantilla especifica que siempre se debe escribir el signo del número a su izquierda. Si el + está al final de la plantilla, el signo se describe a la derecha del número.

El signo - sólo se puede poner al final de la plantilla; específica que se debe poner el signo - a la derecha del número si éste es negativo.

PRINT USING "+##";12
+12

PRINT USING "+##";-12
-12

PRINT USING "##+";12
12+

PRINT USING "##-";-12 
12-

PRINT USING "##-";12
12

La inclusión de "↑↑↑↑" en la plantilla hace que el número se escriba en forma exponencial:

PRINT USING "###.##^^^^";123.45
12.35E+01

Sustituir ^^^^ por ↑↑↑↑.

En cualquier caso, si el número es demasiado grande como para caber en el formato especificado, el número no se trunca, sino que se lo escribe entero, precedido de un signo % para indicar lo que ha ocurrido:

PRINT USING "####";123456
%123456

Ventanas

EI BASIC del CPC464 permite la definición y el control de hasta ocho ventanas de texto. Todas las acciones de control de textos se pueden referir a cualquiera de estas ventanas.

Las ventanas se definen con la orden WINDOW, que va seguida de 5 parámetros. El primero es opcional y especifica el número de la ventana que se va a definir; si se lo omite, el ordenador supone el 0, que es el canal por el que el BASIC emite sus mensajes normales (Ready, errores, etc.). Antes del número se pone el signo # para indicar que se está dando un número de canal. Los otros cuatro parámetros especifican los extremos izquierdo, derecho, superior e inferior de la ventana. Como son números de fila y de columna, pueden estar comprendidos entre 1 y 80 los dos primeros, y entre 1 y 25 los dos últimos.

El siguiente ejemplo define la ventana (canal) número 4, la cual se extiende desde la columna 7 hasta la 31, y desde la fila 6 hasta la 18. Reinicialice la máquina y luego escriba:

WINDOW #4,7,31,6,18

No parece que haya ocurrido nada, así que escriba lo siguiente:

INK 3,9
PAPER #4,3
CLS #4

En la pantalla ha aparecido un gran rectángulo verde, que es la ventana número 4. Este último ejemplo demuestra que las instrucciones PAPER y CLS se pueden referir a cualquiera de las ocho ventanas especificando el número de canal; su omisión hace que la orden actúe sobre la ventana número 0.

Las órdenes para las que se puede especificar número de ventana son las siguientes:

CLS, INPUT, LINE INPUT, LIST, LOCATE, PAPER, PEN, POS, PRINT, TAG, TAGOFF, VPOS, WINDOW, WRITE.

La ventana verde que hemos creado habrá borrado parte del texto que teníamos en la pantalla, que había sido enviado a la ventana número 0.

El texto se puede escribir en cualquier ventana especificando el número de canal en la instrucción PRINT:

PRINT #4,"estoy en la ventana 4"

Estas palabras han aparecido en el extremo superior de la ventana verde, no en la línea siguiente de la pantalla, que es lo que habría ocurrido con:

PRINT "estoy en la ventana 0"

Observe que al escribir esta última orden el texto ha invadido parte de la ventana verde.

Si usted desea confinar todos los mensajes de BASIC a la ventana número 4, intercámbiela con la implícita (la número 0) mediante la orden:

WINDOW SWAP 0,4

El mensaje Ready ha aparecido ahora en la ventana verde y el cursor está debajo de él. Escriba lo siguiente:

PRINT #4,"estoy en la ventana 4"

El texto ha aparecido debajo de la orden WINDOW SWAP, en lo que antes era la ventana 0 y ahora es la 4. Estos ejemplos demuestran que el ordenador recuerda la posición de escritura de cada ventana incluso después de un intercambio. Escriba lo siguiente:

LOCATE #4,20,1
PRINT "estoy en la ventana 0"
PRINT #4,"estoy en la ventana 4"

Mientras no se ejecuta una orden WINDOW, todas las ocho ventanas coinciden con la pantalla entera. Lo mismo ocurre después de una orden MODE. Así pues, si después de jugar con las ventanas se encuentra con que el cursor está en una muy pequeña, puede salir del lío escribiendo MODE 1:

MODE 1
WINDOW 20,21,7,18
MO
DE 
1

El ordenador se ha visto obligado a partir la palabra MODE, pero la instrucción funciona igual. (No olvide dejar un espacio entre la E y el 1.)

Ahora que ya tiene una idea de cómo funcionan las ventanas, escriba y pruebe el siguiente programa:

10 MODE 0
20 FOR n=0 TO 7
30 WINDOW #n,n+1,n+6,n+1,n+6
40 PAPER #n,n+4
50 CLS #n
60 FOR c=1 TO 200:NEXT c
70 NEXT n

Este programa crea 8 ventanas que se solapan y las borra con un color de papel diferente para cada una.

Cuando termine el programa y haya aparecido Ready, pulse [INTRO] varias veces para observar cómo afecta el desplazamiento de la ventana 0 a los bloques de colores. Sin embargo, aunque el contenido de las ventanas se desplace, las ventanas en sí siguen estando en el mismo sitio. Compruébelo escribiendo:

CLS #4

Fíjese también en los diferentes efectos de las siguientes órdenes:

LIST
LIST #4
LIST #3

Otra característica interesante de la orden WINDOW es que también admite los números que especifican los bordes izquierdo y derecho en orden inverso; es decir, aunque el primer parámetro sea mayor que el segundo, BASIC los interpreta en el orden correcto. Análogamente ocurre con los bordes inferior y superior.

10 MODE 0
20 a=1+RND*19:b=1+RND*19
30 c=1+RND*24:d=1+RND*24
40 e=RND*15
50 WINDOW a,b,c,d
60 PAPER e:CLS
70 GOTO 20

Interrupciones

Por si todavía no lo ha leído en otro lugar de este manual, le diremos que una de las principales innovaciones del software de los ordenadores Amstrad es su capacidad de gestión de las interrupciones desde BASIC; esto hace que el BASIC de Amstrad sea capaz de realizar acciones simultáneas controladas por programa. Esto es lo que se suele denominar “multitarea”, y se programa con las instrucciones AFTER y EVERY.

Esta misma habilidad queda demostrada por la forma en que se controla el sonido a través de recursos tales como las colas de sonido y la sincronización de canales.

De todo lo que tenga que ver con la medida del tiempo se encarga el cronómetro patrón del sistema, que es un circuito controlado por un cristal de cuarzo. Este reloj se encarga de cronometrar y de sincronizar los procesos que tienen lugar dentro del ordenador: desde el barrido de la pantalla hasta el envío de impulsos al microprocesador. Toda función del hardware que tenga que ver con el tiempo depende del reloj patrón.

Las instrucciones AFTER (después de) y EVERY (cada) hacen precisamente lo que su nombre sugiere. Así, AFTER invoca una determinada subrutina cuando ha transcurrido el tiempo especificado.

El CPC464 mantiene un reloj de tiempo real. La orden AFTER permite que un programa de BASIC realice una tarea en un instante futuro especificado. Existen cuatro temporizadores de retardo, cada uno de los cuales puede tener una subrutina asociada.

Cuando el tiempo especificado ha transcurrido, la rutina se ejecuta automáticamente, exactamente igual que si el ordenador hubiera encontrado un GOSUB en la línea actual del programa. Cuando la rutina se acaba, con el RETURN habitual, el programa continúa a partir del punto en que fue interrumpido.

La orden EVERY permite que el programa de BASIC ejecute subrutinas a intervalos de tiempo regulares. También en este caso se dispone de cuatro temporizadores, a cada uno de los cuales se puede asignar una subrutina distinta.

Los temporizadores tienen prioridades de interrupción diferentes, lo que tiene importancia cuando varios de ellos compiten por interrumpir el programa en un momento dado. El temporizador 3 tiene la máxima prioridad, y el 0 la mínima (véase el capítulo Para su referencia).

10 MODE 1:n=14:x=RND*400
20 AFTER x,3 GOSUB 90
30 EVERY 25,2 GOSUB 150
40 EVERY 10,1 GOSUB 160
50 PRINT"Pruebe sus reflejos:"
60 PRINT"pulse la barra espaciadora"
70 PRINT"cuando yo le diga."
80 IF ind=1 THEN END ELSE 80
90 x=REMAIN(2)
100 SOUND 129,20:PRINT"AHORA":t=TIME
110 IF INKEY(47)=-1 THEN 110
120 PRINT"Ha tardado";
130 PRINT(TIME-t)/300;"segundos"
140 ind=1:RETURN
150 SOUND 1,0,50:PRINT".";:RETURN
160 n=n+1:IF n>26 THEN n=14
170 INK 1,n:RETURN

Las órdenes AFTER y EVERY se pueden ejecutar en cualquier lugar del programa. Su efecto es reelegir la rutina asociada y poner a cero el temporizador correspondiente. Los temporizadores están compartidos por AFTER y EVERY, de modo que una orden AFTER cancela la anterior EVERY referida al mismo temporizador, y viceversa.

Las órdenes DI y EI inhiben y habilitan, respectivamente, las interrupciones. Esto sirve para permitir que cierta interrupción se procese sin ser interrumpida por otra más prioritaria. La orden REMAIN da el tiempo que queda en un temporizador y lo desactiva.

Listas de datos

Si un programa necesita que se le suministre siempre la misma información cada vez que se lo ejecuta, es preferible hacer que esa información esté contenida en el propio programa para no tener que teclearla con cada ejecución. Esto es posible gracias al par de instrucciones READ/DATA. La orden READ es similar a INPUT en el sentido de que asigna valores a variables, pero en lugar de captar los valores por el teclado los lee en listas encabezadas por la palabra DATA. Los dos ejemplos siguientes ilustran la diferencia:

10 INPUT "escriba 3 numeros separados por comas: "a,b,c
20 PRINT"los numeros son";a;"y";b;"y";c
run
10 READ a,b,c
20 PRINT"los numeros son";a;"y";b;"y";c
30 DATA 12,14,21
run

Los datos contenidos en las listas DATA van separados por comas, lo mismo que los que se teclean en respuesta a una instrucción INPUT.

Las listas DATA pueden contener, no sólo números, sino también cadenas literales constantes:

10 DIM a$(11)
20 FOR i=0 TO 11
30 READ a$(i)
40 NEXT
50 FOR i=0 TO 11
60 PRINT a$(i);" ";
70 NEXT
80 DATA Cuentan,de,un,sabio,que,un,dia,tan,pobre,y,misero,estaba
run

Observe que no es necesario encerrar entre comillas las cadenas que se ponen en las listas DATA. Las comillas en este caso son opcionales (también lo son en INPUT). El único caso en que son necesarias es cuando una cadena contiene una coma; si no se la pusiera entre comillas, la instrucción READ se detendría en la coma y no leería el resto de la cadena.

10 READ a$
20 WHILE a$<>"*"
30 PRINT a$
40 READ a$
50 WEND
60 DATA los dias de la semana son lunes, martes, miércoles, jueves, viernes y sábado
70 DATA "los dias de la semana son lunes, martes, miércoles, jueves, viernes y sábado"
80 DATA *
run

La cadena de la línea 60 contiene comas, y por lo tanto cada tramo será leído por READ y escrito por separado. En cambio, la de la línea 70 ha sido delimitada por comillas y READ la lee de una sola vez.

El ejemplo anterior demuestra que los datos pueden estar distribuidos en varias líneas (60, 70, 80, ...). Otro detalle no tan evidente es que las líneas DATA pueden estar en cualquier lugar del programa, antes o después de las instrucciones READ que leen la información.

Si un programa contiene varias instrucciones READ, cada una continúa leyendo donde terminó la anterior:

10 DATA 123,456,789,321,654,2343
20 FOR i=1 TO 5
30 READ num
40 total=total+num
50 NEXT
60 READ total2
70 IF total=total2 THEN PRINT "los datos son correctos" ELSE PRINT "hay un error en los datos"
run

Modifique uno de los primeros cinco números de la lista de la línea 10 y ejecute otra vez el programa. Esta técnica de poner al final de la lista un dato adicional que sea la suma de los anteriores constituye un buen método de detección de errores en los datos, especialmente si los datos son muchos. Se le llama "suma de verificación" (checksum).

Si un programa requiere datos mixtos (cadenas y números), se los puede combinar en una misma lista DATA, a condición de que READ los lea en el orden correcto. Por ejemplo, si una lista DATA contiene dos números seguidos de una cadena, la instrucción READ tendrá que leer primero dos variables numéricas y luego una literal:

10 DIM a(5),b(5),s$(5)
20 FOR i=1 TO 5
30 READ a(i),b(i),s$(i)
40 NEXT
50 DATA 1,7,Alfredo,3,9,Juan,2,2,Enrique,4,6,Pedro,9,1,Manuel
60 FOR i=1 TO 5
70 PRINT s$(i),":";a(i)*b(i)
80 NEXT

También se puede separar los datos en dos listas distintas:

10 DIM a(5),b(5),s$(5)
20 FOR i=1 TO 5
30 READ a(i),b(i)
40 NEXT
50 FOR i=1 TO 5
60 READ s$(1)
70 NEXT
80 DATA 1,7,3,9,2,2,4,6,9,1
90 DATA Alfredo,Juan,Enrique,Pedro,Manuel
100 FOR i=1 TO 5
110 PRINT s$(i),":";a(i)*b(i)
120 NEXT

Si ahora cambiamos el límite superior de la línea 20:

20 FOR i=1 TO 4

los dos primeros intentos de leer cadenas darán "9" y "1". Estos valores son cadenas válidas, pero el programa no funciona como esperábamos. Una forma de asegurar que el programa funcione correctamente consiste en incluir las líneas:

15 RESTORE 80
45 RESTORE 90

La orden RESTORE hace que el puntero de datos "apunte" hacia el principio de la línea especificada; por lo tanto se la puede incluir en una instrucción condicional para que el bloque de datos leídos dependa del resultado de alguna comprobación. Por ejemplo, en un juego que esté previsto para varios niveles de destreza, los datos de cada nivel pueden ser seleccionados mediante una variable adecuada. Veamos un ejemplo:

1000 REM seccion para dibujar la pantalla
1010 IF nivel=1 THEN RESTORE 2010
1020 IF nivel=2 THEN RESTORE 2510
1030 IF nivel=3 THEN RESTORE 3010
1040 FOR y=1 TO 25
1050 FOR x=1 TO 40
1060 READ car
1070 LOCATE x,y:PRINT CHR$(car);
1080 NEXT x,y
...
2000 REM DATA para pantalla 1
2010 DATA 200,190,244,244,210, ... etc.
...
2500 REM DATA para pantalla 2
2510 DATA 100,103,245,243,251, ... etc.
...
3000 REM DATA para pantalla 3
3010 DATA 190,191,192,193,194, ... etc.

Otra aplicación típica de las instrucciones DATA/READ/RESTORE es un programa que interprete una melodía. Los periodos de tono se pueden poner en listas data; RESTORE puede hacer que se repita una sección moviendo el puntero de datos hacia atrás:

10 FOR i=1 TO 3
20 RESTORE 100
30 READ nota
40 WHILE nota<>-1
50 SOUND 1,nota,35
60 READ nota
70 WEND
80 NEXT
90 SOUND 1,142,100
100 DATA 95,95,142,127,119,106
110 DATA 95,95,119,95,95,119,95
120 DATA 95,142,119,142,179,119
130 DATA 142,142,106,119,127,-1
run

El sonido de la música

De todas las instrucciones del CPC464, es posible que las de sonido y envolventes le parezcan las más imponentes a primera vista. Y sin embargo, con un poco de práctica, muy pronto podrá programar ruidos de diversos tipos e incluso melodías con armonía.

Empecemos por analizar las cuatro primeras partes de la instrucción SOUND, que son las siguientes: situación de canales, periodo de tono, duración de la nota y volumen. Lo primero que hay que saber es en qué margen de valores puede estar cada uno de estos parámetros.

Aplazaremos el primero de momento porque es el más complicado. El segundo, período de tono, puede tener cualquier valor entero comprendido entre 0 y 4095. Sin embargo sólo algunos de estos valores producen notas reconocibles: son los que están relacionados en la parte 5 del capítulo Para su referencia. Por ejemplo, el número 478 produce la nota DO media; el 506 produce la nota SI inmediatamente anterior; los valores 479 a 505 producen cada uno un tono diferente, pero ninguno de ellos corresponde a la escala del piano. Si el parámetro es 0, no se produce ningún tono; esto es útil cuando se está generando ruido.

El tercer parámetro de la orden SOUND especifica la duración de la nota en unidades de centésimas de segundo. Su valor puede estar normalmente entre 1 y 32767. Si es 0, la duración queda controlada por la "envolvente" (de la que hablaremos más adelante). Si el parámetro es negativo, su valor absoluto indica cuántas veces se va a repetir la envolvente; por ejemplo, -3 significa "repetir la envolvente tres veces".

El cuarto parámetro especifica el volumen. Puede valer entre 0 y 15; el valor implícito es 12, que es el que el ordenador supone si no se especifica otra cosa. En los sonidos sencillos que hemos conocido hasta ahora, el volumen ha permanecido constante durante el tiempo en que ha sonado cada nota. Sin embargo, cuando se utiliza una "envolvente de volumen" para hacer que éste deje de ser constante, el parámetro "volumen" de SOUND se considera como volumen inicial de la nota.

Bueno, vamos con el parámetro de situación de canales. Quizá sepa ya el lector que el significado de este parámetro depende del valor de sus bits; para entenderlo necesitará saber algo acerca de los números binarios (parte 1 de este capítulo).

El sonido se puede generar en tres canales distintos. Si el ordenador está conectado a un amplificador estereofónico, un canal será el derecho, otro el izquierdo y otro común a ambos o central. Para especificar en qué canal o canales debe sonar una nota se utilizan los siguientes números:

  • 1 canal de A
  • 2 canal de B
  • 4 canal de C

Para enviar el sonido a varios canales, se suman los números correspondientes. Por ejemplo, para que la nota suene en los canales A y C, el parámetro debe ser 1+4=5.

SOUND 5,284

Se preguntará el lector por qué el número del canal C es 4, y no 3. Observe que estos tres números son potencias de 2(1=2↑0, 2=2↑1, 4=2↑2) y se combinan para dar un número binario. Si imaginamos un número binario de tres dígitos, cada uno de ellos se puede utilizar para indicar si el canal correspondiente debe estar conectado o desconectado. En el ejemplo anterior, 5 en decimal es equivalente a 1*4+0*2+1*1, es decir, 101 en binario. Si a los dígitos de este número binario les ponemos las etiquetas C, B y A, tenemos

C B A
1 0 1

de forma que C y A están conectados, mientras que B está desconectado. Si quisiéramos que la nota sonase en los canales A y B, el número tendría que ser

C B A
0 1 1

En decimal: 0*4+1*2+1*1=3. La orden SOUND sería

SOUND 3,284

Naturalmente, este número tiene que coincidir con el que se obtendría sumando los valores correspondientes a los dos canales: 1+2=3 (recuerde que A=1, B=2, C=4).

Si después de todo no ha entendido cómo funciona esto en binario, no se preocupe. Le basta con saber que las combinaciones de canales se programan sumando los números de selección de los canales deseados.

Lamentablemente (o afortunadamente, según cómo se mire), todavía podemos sumar otros números a este parámetro. Así, los números 8, 16 y 32 especifican que el sonido debe sincronizarse con otro canal (A, B o C, respectivamente). Ahora hace falta saber qué es eso de "sincronizar con un canal". Pues bien, los sonidos que hemos generado hasta ahora han ido directamente al canal especificado. Escriba lo siguiente:

SOUND 1,284,2000
SOUND 1,90,200

A menos que sea usted un mecanógrafo muy lento, habrá tenido tiempo de escribir la segunda orden antes de que se extinguiera el primer sonido. Esto ocurre porque el sistema de sonido puede guardar hasta cinco órdenes en cada una de las colas de los tres canales. Si queremos que suene una nota por el canal A y luego dos notas simultáneamente en los canales A y B, necesitamos un forma de indicar al ordenador que no debe ejecutar la nota del canal B mientras no haya terminado la primera del A. En esto consiste la sincronización de canales. Hay dos formas de conseguirla:

SOUND 1,200,1000
SOUND 3,90,200

En este ejemplo hemos dirigido la segunda nota a A y B, y por lo tanto no puede sonar mientras no haya concluido la primera. La limitación de este método es que el sonido que se envía a varios canales tiene que ser igual en todos ellos (en este caso, ,90,200 era igual para el A que para el B). El otro método es el siguiente:

SOUND 1,200,2000
SOUND 1+16,90,200
SOUND 2+8,140,400

Aquí hemos hecho que la segunda nota de A se sincronice con el sonido de B (y que éste se sincronice con el canal A). La ventaja de este método es evidente: las notas sincronizadas pueden ser (y en este caso son) diferentes. Estos números de sincronización también son interpretables bit a bit:

  • 8=2↑3, 16=2↑4, 32=2↑5

Así, el número de situación de canales se puede considerar como número binario cuyos dígitos tienen el siguiente significado:

Sincronizar con Sumar Sonar en Sumar
C 32 C 4
B 16 B 2
A 8 A 1

Por ejemplo, para hacer sonar una nota en el canal C sincronizado con el A:

0   0   1   1   0   0

Éste es el número binario 1100, equivalente a 8+4 en decimal.

Así pues, el número de situación de canales 12 ordena a la máquina que haga sonar una nota en el canal C y que espere por una nota que debe sonar en el canal A y que ha sido marcada para sincronizarla con el C.

Si ahora sumamos 64 (=2↑6) al parámetro, estamos indicando que la nota debe ser retenida. Esto significa que no va a sonar mientras no la liberemos con la orden RELEASE.

Finalmente, si sumamos 128 (=2↑7), borramos la cola de sonido del canal especificado.

Por ejemplo, si hemos ordenado un sonido que va a durar un buen rato, podemos anularlo borrando la cola del canal correspondiente:

SOUND 1,248,30000   ' (esta nota dura 5 minutos)
SOUND 1+128,0       ' (pero esta la detiene)

Cuando se esté en modo directo, la forma más rápida de interrumpir un sonido es pulsar [←BORR] al principio de la línea; el pitido que así se produce borra todas las colas de sonido.

Ahora que ya sabemos enviar sonido a cualquier combinación de canales (con sincronización, si es necesario), vamos a intentar producir algo más agradable que los molestos pitidos que produce una orden SOUND en esta forma sencilla. Lo haremos dotando al sonido de una envolvente: una gráfica que define cómo evoluciona la intensidad del sonido a lo largo del tiempo. Las notas producidas por los instrumentos musicales tienen una fase inicial de ataque en la que el volumen sube muy deprisa; después se mantiene a un nivel algo inferior hasta que finalmente decae gradualmente a cero. En el ordenador se puede dar una envolvente de este tipo a las notas producidas por la orden SOUND. La instrucción con la que se programa la envolvente es ENV. Veamos un ejemplo sencillo:

ENV 1,5,3,4,5,-3,8
SOUND 1,284,0,0,1

La instrucción ENV se debe ejecutar antes que la SOUND que la utiliza. Para invocar una envolvente en una instrucción SOUND se pone como quinto parámetro de éste el número de referencia de la envolvente, en este caso el 1, que es el número con que se la creó en la instrucción ENV. Los parámetros de ENV describen tanto la duración como el volumen de la nota, de modo que en SOUND podemos poner 0 en lugar de los datos de duración y volumen. La envolvente del ejemplo anterior hace que la nota crezca en 5 etapas, en cada una de las cuales el volumen aumenta en 3 unidades y cuya duración es de 4 centésimas de segundo. Después se especifica que el volumen debe decaer en 5 etapas, –3 unidades en cada una, siendo la duración de cada etapa 8 centésimas de segundo. Es decir, el primer parámetro de ENV es el número de referencia de la envolvente y va seguido por grupos de tres números. Dentro de cada grupo, el primer parámetro es el número de escalones de variación del volumen; el segundo, la amplitud de esos escalones; y el tercero, su duración. La duración total de cada sección será igual al producto del primer parámetro (número de escalones) por el tercero (duración de cada escalón). El aumento o disminución total del volumen es igual al producto del primer parámetro por el segundo (variación del volumen por escalón). La duración total de una envolvente es la suma de las correspondientes a las secciones que la integran.

En el ejemplo anterior, SOUND fijaba en 0 el volumen inicial de la nota. Pero esto no tiene que ser necesariamente así. En el siguiente ejemplo el volumen decrece desde el valor inicial 15 y luego vuelve a subir:

ENV 2,5,-2,1,20,0,1,10,1,1
SOUND 1,284,0,15,2

El número de esta envolvente es el 2. Consta de tres secciones. En la primera el volumen se reduce en 5 escalones de -2; es decir, varía a través de 5 etapas y en cada una se reduce en 2 unidades. La duración de cada etapa es de 1 centésima de segundo. La segunda sección tiene 20 etapas en las que no varía el volumen (0) y cada una de las cuales dura 1 centésima de segundo. Finalmente, la tercera sección consta de 10 etapas, con un incremento de volumen de 1 unidad y duración de 1 centésima de segundo cada una.

La instrucción SOUND especifica un volumen inicial de 15; al final de la primera sección ha decrecido hasta 5; se mantiene a ese nivel durante 20 centésimas de segundo y luego vuelve a crecer hasta alcanzar el nivel 15.

Para mejor visualizar y diseñar la forma de las envolventes conviene dibujarlas en un papel milimetrado y leer en él los valores de los parámetros requeridos. En las dos figuras de la página anterior mostramos las dos envolventes definidas hasta ahora.

El máximo número de secciones que se puede incluir en una envolvente es 5; como cada sección requiere 3 parámetros, la instrucción ENV puede llegar a tener 16 parámetros en total, contando el primero, que indica cuál de las 15 envolventes posibles se está definiendo. Podemos imaginar los números de volumen como dispuestos en círculo; si vamos subiendo de nivel y sobrepasamos el 15, volvemos al 0; análogamente, si intentamos descender por debajo del 0, volvemos al 15. Por ejemplo, en

ENV 3,9,5,20
SOUND 1,284,0,0,3

la envolvente consta de una sola sección de 9 etapas, cada una de las cuales incrementa el volumen en 5 unidades y dura 20 centésimas de segundo. Al terminar la tercera etapa, el volumen ha subido de 0 a 15; en la cuarta etapa volverá a 4; en la quinta a 9, etc. El proceso está ilustrado en la figura siguiente.

El margen de valores para el número de escalones es de 0 a 127. En cada uno el valor puede variar entre -128 y +127 (los valores negativos representan disminución). La duración de cada escalón puede ser de entre 0 y 255 (centésimas de segundo).

Ya sabemos cómo variar el volumen de una nota. Ahora podemos estudiar cómo se define la variación de su tono con el tiempo para producir efectos tales como el "vibrato".

El método es muy parecido al de las envolventes de volumen. Las envolventes de tono se definen con la instrucción ENT. Por ejemplo:

ENT 1,5,1,1,5,-1,1
SOUND 1,284,10,15,,1

Las envolventes de tono se invocan con la instrucción SOUND poniendo en esta como sexto parámetro el número de referencia de la envolvente. La instrucción ENT tiene que ser ejecutada antes que la SOUND que la utiliza.

Este primer ejemplo de ENT define la envolvente de tono número 1. La primera sección consta de 5 etapas; en cada una el periodo de tono crece en 1 unidad; cada una dura 1 centésima de segundo. La segunda sección consta de 5 etapas; la variación del periodo de tono en cada una de ellas es –1 (descenso); la duración de cada etapa es de 1 centésima de segundo. La duración total es, pues, 5+5=10 centésimas de segundo. Obsérvese que esta duración ha sido especificada en SOUND, ya que la duración de la envolvente de tono no determina la duración de la nota (mientras que sí lo hace la envolvente de volumen). Si la duración especificada en SOUND es menor que la de la envolvente, el final de ésta se perderá. Si es mayor, el final de la nota se ejecutará a tono constante. Esto último es también aplicable a las envolventes de volumen.

(Nótese la ausencia del número de envolvente de volumen en la última instrucción SOUND, debida a que aún no hemos definido una envolvente de volumen para este sonido.)

Las envolventes de tono normalmente duran menos que la nota. Se puede hacer que la envolvente se repita mientras la nota está sonando. Para ello se especifica un número de envolvente negativo, cuyo valor absoluto se cita en la instrucción SOUND:

ENT -5,4,1,1,4,-1,1
SOUND 1,284,100,12,,5

Esta repetición de la envolvente produce el efecto "vibrato". Cuando se diseñan envolventes de tono, es conveniente que el tono varíe simétricamente con respecto al valor inicial, de forma que al repetir la envolvente el tono no se desvíe demasiado con respecto al valor central. Pruebe el siguiente sonido:

ENT -6,3,1,1
SOUND 1,284,90,12,,6

Habrá observado que la frecuencia ha disminuido drásticamente. Esto ha ocurrido porque la envolvente impone un aumento del periodo de tono de 3 unidades y se repite 30 veces (90/3). No obstante, ese efecto se puede aprovechar para imitar trinos y sirenas:

ENT -7,20,1,1,20,-1,1
SOUND 1,100,400,12,,7

ENT -8,60,-1,1,60,1,1
SOUND 1,100,480,12,,8

Se pueden definir hasta 15 envolventes de tono, con números de referencia del 1 al 15; los números negativos indican que la envolvente se repite. Para cada sección, el número de escalones puede estar entre 0 y 239. La variación del periodo de tono en cada escalón puede ser de entre –128 y +127. La duración de cada escalón puede ser de entre 0 y 255 (centésimas de segundo). Cada envolvente puede tener hasta 5 secciones.

El último parámetro que se puede incluir en la instrucción SOUND, el séptimo, caracteriza el nivel de ruido que se añade al sonido. Obsérvese que sólo hay un canal de ruido y que, por consiguiente, cada vez que se especifica un nivel de ruido se anula la anterior especificación.

El ruido se puede mezclar con un tono, pero también se lo puede programar por separado, para lo cual se debe poner un 0 como período de tono en SOUND. Esto es útil para imitar ruidos de percusión:

ENT -3,2,1,1,2,-1,1
ENV 9,15,1,1,15,-1,1
FOR a=1 TO 10:SOUND 1,4000,0,0,9,3,15:NEXT

Un ruido como éste puede servir de base para imitar el de una locomotora. Obsérvese que hemos combinado los dos tipos de envolvente y el ruido. En SOUND hemos puesto 0 para los parámetros de duración y de volumen, por lo que estas características quedan controladas por las envolventes de volumen.

Como ya estamos en condiciones de utilizar SOUND, ENV y ENT a plena potencia, vamos a estudiar algunas otras órdenes y funciones.

Como el lector recordará, al describir el primer parámetro de SOUND dijimos que si le sumábamos el número 64 el sonido quedaba "retenido" en la cola, y que no sonaría mientras no lo liberásemos. La forma de liberarlo es ejecutar la orden RELEASE. Esta palabra va seguida de un número cuyos bits determinan a qué canales afecta la orden:

  • 4 significa canal C
  • 2 significa canal B
  • 1 significa canal A

Los canales se combinan sumando los números correspondientes. Así, para liberar el sonido de los tres canales la orden que se requiere es:

RELEASE 7

donde 7=1+2+4. Si no hay sonido retenido en ningún canal, la orden no tiene efecto. Pruebe lo siguiente:

SOUND 1+64,90
SOUND 2+64,140
SOUND 4+64,215
RELEASE 3:FOR t=1 TO 1000:NEXT:RELEASE 4

No se produce ningún sonido mientras no se ejecuta la primera orden RELEASE, la cual libera los sonidos de los canales A y B. Después de una pausa, la segunda orden RELEASE libera el canal C.

Hay otro método para sincronizar sonidos. Cuando se retiene un sonido sumando 64 a su número de situación de canal, no sólo queda él retenido, sino todos los que se envíen a continuación a ese mismo canal. Si se envían más de cuatro sonidos a una cola que está retenida, la máquina queda bloqueada hasta que se libere la cola (posiblemente al ejecutarse una subrutina invocada por AFTER o EVERY). Ésta no es una buena forma de gestionar los sonidos, ya que la máquina se detendrá cada vez que se llene una cola. Lo mismo ocurre si se ejecutan varias órdenes SOUND seguidas. Pruebe este programa:

10 FOR a=1 TO 8
20 SOUND 1,100*a,200
30 NEXT
40 PRINT"hola"
run

El texto no aparece en la pantalla inmediatamente, sino al cabo de tres segundos. Esto ocurre porque el programa no puede llegar a la línea 40 mientras no haya espacio libre en la cola para almacenar todos los sonidos.

BASIC dispone de un mecanismo de interrupción, similar al que se utiliza en AFTER, EVERY y ON BREAK GOSUB, mediante el cual se puede hacer que se ejecute una subrutina cada vez que queda espacio libre en una cola especificada:

10 a=0
20 ON SQ(1) GOSUB 1000
30 PRINT a;
40 GOTO 30
1000 a=a+10
1010 SOUND 1,a,200
1020 IF a<200 THEN ON SQ(1) GOSUB 1000
1030 RETURN

Observe que el programa no se detiene. La instrucción SOUND no se ejecuta mientras no hay espacio libre en la cola del canal A (1), hecho que detecta la orden ON SQ(1) GOSUB de la línea 20. Esta orden inicializa un mecanismo de interrupción que ejecuta la subrutina cada vez que queda un hueco libre en la cola especificada. El mecanismo tiene que ser reinicializado cada vez que se ejecuta la subrutina (línea 1020). En este ejemplo, la reinicialización sólo se produce si a es menor que 200.

En un programa que lleve a cabo acciones relativamente lentas (por ejemplo, mover objetos por la pantalla), se puede poner música de fondo programando una subrutina que ejecute una nota cada vez que quede un hueco libre en la cola. De esta forma se asegura que el programa no se va a detener en espera de que quede espacio en la cola. Si los valores de las notas están contenidos en listas DATA, se puede hacer que la subrutina de sonido deje de reinicializarse cuando los datos estén a punto de agotarse.

El parámetro que va entre paréntesis en la instrucción ON SQ( ) GOSUB puede ser 1, 2 o 4, dependiendo del canal cuya cola se desee examinar.

Hay una función, SQ( ), que se puede utilizar para determinar el estado de los canales de sonido. Su parámetro puede ser 1, 2 o 4. El valor generado por la función se interpreta bit a bit según la siguiente tabla:

Bit Decimal Significado
0, 1, 2 1 a 4 Número de huecos libres en la cola
3 8 La primera nota de la cola está marcada para sincronizar con el canal A
4 16 La primera nota de la cola está marcada para sincronizar con el canal B
5 32 La primera nota de la cola está marcada para sincronizar con el canal C
6 64 La primera nota de la cola está retenida (está a 1 el bit de retención)
7 128 En este momento está sonando una nota

Pruebe el siguiente ejemplo:

10 SOUND 2,200
20 x=SQ(2)
30 PRINT BIN$(x)
run

La línea 30 escribe el número binario 10000100. El bit 7 está a 1, lo que indica que en el canal había una nota sonando cuando se ejecutó la línea 20. Los tres dígitos menos significativos son 100; equivalen al número decimal 4, y esto quiere decir que había cuatro espacios libres en la cola. Esta función examina la situación del canal en un punto específico del programa; en cambio, ON SQ( ) GOSUB examina la cola, y reacciona en consecuencia, en un punto indeterminado.

Hasta ahora todos los ejemplos han consistido en hacer sonar una o dos notas. Si se va a ejecutar un grupo de notas independientes, por ejemplo las de una melodía, sus características se pueden guardar en líneas DATA, para luego leerlas con READ e introducirlas en SOUND:

10 FOR octava=-1 TO 2
20 FOR x=1 TO 7:REM notas por octava
30 READ nota
40 SOUND 1,nota/2^octava
50 NEXT
60 RESTORE
70 NEXT
80 DATA 426,379,358,319,284,253,239
run

Substituir el carácter ^ por ↑.

El ejemplo final de esta sección se basa en este concepto. En los canales A y B se hace sonar una melodía con ritmo, utilizando la sincronización. Este ejemplo muestra cómo utilizar las listas DATA para incluir información sobre nota, octava, duración y sincronización:

10 REM la linea 190 da la melodia en clave de agudos
20 REM la linea 200 da la melodia en clave de graves
30 DIM escala%(12):FOR x%=1 TO 12:READ escala%(x%):NEXT
40 canal1%=1:READ canal1$:canal2%=2:READ canal2$
50 CLS
60 velocidad%=12
70 escala$=" a-b b c+c d-e e f+f g+g"
80 ENV 1,2,5,2,8,-1,10,10,0,15
90 ENV 2,2,7,2,12,-1,10,10,0,15
100 ENT -1,1,1,1,2,-1,1,1,1,1
110 DEF FNm$(s$,s)=MID$(s$,s,1)
120 canal1%=1:GOSUB 200
130 canal2%=1:GOSUB 380
140 IF canal1%+canal2%>0 THEN 140
150 END
160 DATA &777,&70c,&6a7,&647,&5ed,&598
170 DATA &547,&4fc,&4b4,&470,&431,&3f4
180 DATA 4cr4f4f1f1g1A1-B2C2f4g2g1A1-B6A2Cr1f1g1f1g1a1-b1A1-b2C2g2A2g2f1g1a2g2f6e2c2e2c2g2e2c1-B1A2g2f4e4d8c4f3f1c2d4-b2fr2-B2A2g2f6e2gr4C4-B1a1f1-b1g2c2-b4a4g4fr6A2A2-B4-B2Ar2-B2A2g2f6e2g4C4-B1A1f1-B1g2C2-B4A4g8f.
190 DATA r4f4f8f4e4c4fr8f4e2f2e4d2e2d8c8c6e2f4g4g8e4f3f1c4dr8g4cr4e4c6f2d4c4c8fr8-e4dr8g8c4e4c6f2d4c4c8f.
200 REM enviar sonido al canal A
210 p1$=FNm$(canal1$,canal1%)
220 IF p1$<>"r" THEN r1%=0:GOTO 240
230 r1%=16:canal1%=canal1%+1:p1$=FNm$(canal1$,canal1%)
240 IF p1$="." THEN canal1%=0:RETURN ELSE I1%=VAL(p1$)
250 canal1%=canal1%+1
260 n1$=FNm$(canal1$,canal1%)
270 canal1%=canal1%+1
280 IF n1$="+" OR n1$="-" THEN 350
290 n1$=" "+n1$
300 nd1%=(1+INSTR(escala$,LOWER$(n1$)))/2
310 IF ASC(RIGHT$(n1$,1))>96 THEN o1%=8 ELSE o1%=16
320 SOUND 1+r1%,escala%(nd1%)/o1%,velocidad%*I1%,0,1,1
330 ON SQ(1) GOSUB 200
340 RETURN
350 n1$=n1$+FNm$(canal1$,canal1%)
360 canal1%=canal1%+1
370 GOTO 300
380 REM enviar sonido al canal B
390 p2$=FNm$(canal2$,canal2%)
400 IF p2$<>"r" THEN r2%=0:GOTO 420
410 r2%=8:canal2%=canal2%+1:p2$=FNm$(canal2$,canal2%)
420 IF p2$="." THEN canal2%=0:RETURN ELSE l2%=VAL(p2$)
430 canal2%=canal2%+1
440 n2$=FNm$(canal2$,canal2%)
450 canal2%=canal2%+1
460 IF n2$="+" OR n2$="-" THEN 530
470 n2$=" "+n2$
480 nd2%=(1+INSTR(escala$,LOWER$(n2$)))/2
490 IF ASC(RIGHT$(n2$,1))>96 THEN o2%=4 ELSE o2%=8
500 SOUND 2+r2%,escala%(nd2%)/o2%,velocidad%*l2%,0,1,2
510 ON SQ(2) GOSUB 380
520 RETURN
530 n2$=n2$+FNm$(canal2$,canal2%)
540 canal2%=canal2%+1
550 GOTO 480

run

Para ampliar información

Hay numerosas publicaciones de Indescomp y de otras editoriales en las que puede encontrar más amplia información sobre el CPC464; en concreto, las especificaciones de BASIC y del firmware.

Finalmente vamos a ofrecerle tres apéndices: un glosario de terminología informática, los listados de unos cuantos programas y un índice alfabético.

Esperamos que haya encontrado este manual instructivo e interesante y le agradecemos que haya adquirido el CPC464.


Capítulo 5. Parte 1: En términos generales / Índice / Apéndices

Clone this wiki locally