Traducción del Día 7 y demases

This commit is contained in:
jota 2022-01-12 12:42:37 -03:00
parent c0074c1b60
commit 2f7ea7474c
3 changed files with 575 additions and 4 deletions

View File

@ -62,7 +62,11 @@ además de utilizar estrategias y fragmentos de código anteriores, cubrimos est
# día 7
¡próximamente!
aquí hablamos de los dispositivos del ordenador varvara que aún no hemos cubierto: audio, archivo y fechahora o "datetime".
este debería ser un final ligero y tranquilo de nuestro recorrido, ya que tiene que ver menos con la lógica de programación y más con las convenciones de entrada y salida en estos dispositivos.
{tutorial de uxn día 7}
# índice tentativo

View File

@ -1700,7 +1700,7 @@ aquí hay algunas posibilidades extra para que practiques y trates de implementa
# día 7
en el {tutorial de uxn día 7} hablamos de los dispositivos del ordenador varvara que aún no hemos cubierto: audio, archivo y fechatiempo o "datetime".
en el {tutorial de uxn día 7} hablamos de los dispositivos del ordenador varvara que aún no hemos cubierto: audio, archivo y fechahora o "datetime".
este debería ser un final ligero y tranquilo de nuestro recorrido, ya que tiene que ver menos con la lógica de programación y más con las convenciones de entrada y salida en estos dispositivos.

View File

@ -1,3 +1,570 @@
# día 7
# tutorial uxn: día 7, más dispositivos
¡proximamente! traducción en proceso. :)
esta es la séptima y última sección del {tutorial de uxn}! aquí hablamos de los dispositivos del ordenador varvara que aún no hemos cubierto: audio, archivo y fechahora o "datetime".
este debería ser un final ligero y tranquilo de nuestro recorrido, ya que tiene que ver menos con la lógica de programación y más con las convenciones de entrada y salida en estos dispositivos.
¡comencemos!
# el dispositivo de archivo
el dispositivo de archivo en el ordenador varvara nos permite leer y escribir en archivos externos.
sus puertos se definen normalmente de la siguiente manera:
```
|a0 @Archivo [ &vector $2 &exito $2 &estad $2 &borrar $1 &adjuntar $1 &nombre $2 &largo $2 &leer $2 &escribir $2 ]```
* el corto vector no se utiliza actualmente
* el corto éxito almacena la longitud de los datos que se han leído o escrito con éxito, o cero si ha habido un error
* el corto nombre es para la dirección de memoria donde se almacena el nombre del archivo (terminado en cero, es decir, con un 00)
* el corto largo es la cantidad de bytes a leer o escribir: ¡no olvidemos que la memoria del programa es ffff más 1 byte de largo, y que el programa mismo se almacena allí!
* el short leer es para la dirección de memoria inicial donde los datos de lectura deben ser almacenados
* el corto escribir es para la dirección de memoria inicial donde se almacenan los datos a escribir
* el corto estad es similar al de cargar, pero lee la entrada del directorio para el nombre del archivo
* el byte borrar borra el archivo cuando se escribe cualquier valor en él.
* establecer el byte adjuntar a 01 hace que `escribir` añada datos al final del archivo. cuando el byte adjuntar tiene el valor por defecto, 00, `escribir` sobrescribe el contenido desde el principio
una operación de lectura se inicia cuando se escribe en el corto `leer`, y una operación de escritura se inicia cuando se escribe en el corto `escribir`.
¡estos pueden parecer muchos campos para manejar, pero veremos que no son demasiado problema!
## leer un archivo
para leer un archivo, necesitamos saber lo siguiente:
* la ruta del archivo, escrita como una cadena de texto etiquetada en la memoria del programa y terminada por un 00 - esta ruta sería relativa a la ubicación donde se ejecuta uxnemu.
* la cantidad de bytes que queremos leer del archivo: no pasa nada si este número no es igual al tamaño del archivo; puede ser menor o incluso mayor.
* la etiqueta para una sección reservada de la memoria del programa donde se almacenarán los datos leídos
¡y eso es todo!
podemos usar una estructura como la siguiente, donde el nombre del archivo y la memoria reservada están bajo una etiqueta, y la subrutina de carga del archivo bajo otra:
```
@carga-archivo ( -- )
;archivo/nombre .Archivo/nombre DEO2 ( dirección de la ruta del archivo )
#00ff .Archivo/largo DEO2 ( intentará leer 255 bytes )
( establecer la dirección de los datos a leer y hacer la lectura )
;archivo/datos .Archivo/lectura DEO2
( comprobar el byte éxito y saltar según corresponda )
Archivo/exito DEI2 #0000 EQU2 ,&failed JCN
&exito
LIT 'Y .Consola/escribir DEO
RTN
&fallo
LIT 'N .Consola/escritura DEO
RTN
@archivo
&nombre "prueba.txt 00
&datos $ff ( reservando 255 bytes para los datos )
```
nótese que para el nombre del archivo estamos usando la runa de cadena cruda o `raw` (") que nos permite escribir varios caracteres en la memoria del programa hasta encontrar un espacio en blanco.
en este ejemplo estamos escribiendo un carácter en la consola en función de que el corto `exito` sea cero o no, pero podríamos decidir realizar cualquier acción que consideremos oportuna.
además, en este ejemplo no nos preocupa realmente cuántos bytes se han leído realmente: ¡tenga en cuenta que esta información se almacena en `Archivo/exito` hasta que se produzca otra lectura o escritura!
es importante recordar que, como siempre en este contexto, estamos tratando con bytes crudos.
¡no sólo podemos elegir tratar estos bytes como caracteres de texto, sino que también podemos elegir usarlos como sprites, coordenadas, dimensiones, colores, etc!
## escribir un archivo
para escribir un archivo, necesitamos:
* la ruta del archivo, escrita como una cadena en la memoria del programa como el caso anterior
* la cantidad de bytes que queremos escribir en el archivo
* la etiqueta de la sección de la memoria del programa que escribiremos en el archivo
¡tenga en cuenta que el archivo se sobrescribirá completamente a menos que `adjuntar` se establezca a 01!
el siguiente programa escribirá "hola" y una nueva línea (0a) en un archivo llamado "prueba.txt":
```
@guardar-archivo ( -- )
;archivo/nombre .Archivo/nombre DEO2 ( establecer nombre de archivo )
#0006 .Archivo/largo DEO2 ( intentará escribir 6 bytes )
( establecer la dirección de inicio de los datos, y hacer la escritura )
;archivo/datos .Archivo/escribir DEO2
( leer y evaluar el byte éxito )
.Archivo/exito DEI2 #0006 NEQ2 ,&fallo JCN
&exito
LIT 'Y .Consola/escribir DEO
RTN
&fallo
LIT 'N .Consola/escribir DEO
RTN
@archivo
&nombre "prueba.txt 00
&datos "hola 0a
```
¡observe lo similar que es a la subrutina cargar-archivo!
las únicas diferencias, además del uso de `Archivo/escribir` en lugar de `Archivo/leer`, son la longitud del archivo y la comparación para el corto éxito: en este caso sabemos con seguridad cuántos bytes deberían haberse escrito.
## un breve estudio de caso: el archivo de temas
los programas para el ordenador varvara escritos por 100r suelen tener la capacidad de leer un archivo "tema" que contiene seis bytes correspondientes a los tres cortos para los colores del sistema.
estos seis bytes están en orden: los dos primeros son para el canal rojo, los dos siguientes para el canal verde y los dos últimos para el canal azul.
este archivo tiene el nombre de ".tema" y se escribe en un directorio local de nasu cada vez que se guarda una hoja de sprites.
=> https://wiki.xxiivv.com/site/theme.html temas uxn
### leyendo el archivo de temas
podríamos adaptar nuestra subrutina anterior para cargar el archivo de temas y aplicar sus datos como colores del sistema:
```
@cargar-tema ( -- )
;tema/nombre .Archivo/nombre DEO2 ( establecer la dirección de la ruta del archivo )
#0006 .Archivo/largo DEO2 ( intentará leer 6 bytes )
( establecer la dirección de los datos a leer y hacer la lectura )
;tema/datos .Archivo/cargar DEO2
( comprobar el byte éxito y saltar según corresponda )
.Archivo/exito DEI2 #0006 NEQ2 ,&fallo JCN
&exito
( establecer los colores del sistema a partir de los datos leídos )
;tema/r LDA2 .Sistema/r DEO2
;tema/g LDA2 .Sistema/g DEO2
;tema/b LDA2 .Sistema/b DEO2
RTN
&fallo
RTN
@tema
&nombre ".tema 00
&datos ( reservando 6 bytes para los datos: )
&r $2 &g $2 &b $2
```
observe cómo las etiquetas &datos y &r apuntan a la misma ubicación: ¡no es un problema! :)
### escribiendo el archivo de temas
y para hacer la operación contraria, podemos leer los colores del sistema en nuestro espacio reservado en memoria, y luego escribirlos en el archivo:
```
@guardar-tema ( -- )
( leer los colores del sistema en la memoria del programa )
.Sistema/r DEO2 ;tema/r STA2
.Sistema/g DEO2 ;tema/g STA2
.Sistema/b DEO2 ;tema/b STA2
;tema/nombre .Archivo/nombre DEO2 ( establecer la dirección de la ruta del archivo )
#0006 .Archivo/leer DEO2 ( intentará escribir 6 bytes )
( establecer la dirección de los datos y hacer la escritura )
;tema/datos .Archivo/guardar DEO2
( comprobar el byte de éxito y saltar según corresponda )
.Archivo/exito DEI2 #0006 NEQ2 ,&fallo JCN
&exito
( ¿informar el éxito? )
RTN
&fallo
RTN
```
¡te invito a comparar estas subrutinas con las presentes en los programas 100r como nasu!
=> https://git.sr.ht/~rabbits/nasu/tree/main/item/src/main.tal código fuente de nasu
# el dispositivo fechahora o "datetime"
el dispositivo fechahora puede ser útil para el cronometraje de baja precisión y/o para las visualizaciones del tiempo.
tiene varios campos que podemos leer, todos ellos basados en la hora del sistema actual y la zona horaria:
```
|b0 @FechaHora [ &ano $2 &mes $1 &dia $1 &hora $1 &minuto $1 &segundo $1 &ddls $1 &dda $2 &eshdv $1 ]
```
* el byte año corresponde al número de año de la llamada era común
* el byte mes cuenta los meses desde enero (es decir, enero es 0, febrero 1, etc.)
* el byte día cuenta los días del mes a partir del 1
* Los bytes hora, minuto y segundo corresponden a lo que se espera: sus valores van de 0 a 23, o de 0 a 59 respectivamente.
* ddls (día de la semana) es un byte que cuenta los días desde el domingo (es decir, el domingo es 0, el lunes es 1, el martes es 2, etc.).
* dda (día del año) es un byte que cuenta los días desde el 1 de enero (es decir, el 1 de enero es 0, el 2 de enero es 1, etc.)
* eshdv ( es horario de verano) es una bandera, 01 si es horario de verano y 00 si no lo es.
basándonos en esto, debería ser sencillo utilizarlos. por ejemplo, para leer la hora del día en la pila, haríamos:
```
.FechaHora/hora DEI
```
## algunas posibilidades basadas en el tiempo
¡te invito a desarrollar una visualización creativa del tiempo!
tal vez puedas usar estos valores como coordenadas para algunos sprites, o tal vez puedas usarlos como tamaños o límites para figuras creadas con bucles.
o ¿qué tal dibujar sprites condicionalmente, y/o cambiar los colores del sistema dependiendo de la hora? :)
¡también puedes utilizar los valores de la fecha y la hora como semillas para generar alguna pseudo-aleatoriedad!
por último, recuerda que para cronometrar eventos con más precisión que segundos puedes contar las veces que se ha disparado el vector pantalla.
# el dispositivo de audio
por fin, ¡el dispositivo de audio! o debería decir, ¡los dispositivos de audio!
varvara tiene cuatro dispositivos estéreo idénticos (o "canales"), que se mezclan antes de pasar a los altavoces/auriculares:
```
|30 @Audio0 [ &vector $2 &posicion $2 &salida $1 &pad $3 &adsr $2 &largo $2 &direc $2 &volumen $1 &pitch $1 ]
|40 @Audio1 [ &vector $2 &posicion $2 &salida $1 &pad $3 &adsr $2 &largo $2 &direc $2 &volumen $1 &pitch $1 ]
|50 @Audio2 [ &vector $2 &posicion $2 &salida $1 &pad $3 &adsr $2 &largo $2 &direc $2 &volumen $1 &pitch $1 ]
|60 @Audio3 [ &vector $2 &posicion $2 &salida $1 &pad $3 &adsr $2 &largo $2 &direc $2 &volumen $1 &pitch $1 ]
```
de forma similar a como en el dispositivo de pantalla podemos dibujar apuntando a direcciones con datos de sprite, en los dispositivos de audio podremos reproducir sonidos apuntando a direcciones con datos de audio (muestras o "samples").
extendiendo la analogía: de forma similar a como podemos dibujar sprites en diferentes posiciones en la pantalla, podemos reproducir nuestras muestras a diferentes velocidades, volumen y envolventes.
supondremos que no estás familiarizado con estos conceptos, así que los discutiremos brevemente.
## muestras
como hemos mencionado anteriormente, podemos pensar en los datos de las muestras como el equivalente a los datos de los sprites.
tienen que estar en la memoria del programa, tienen una longitud que debemos conocer, y podemos referirnos a ellos mediante etiquetas.
el ejemplo piano.tal en el repositorio uxn, tiene varios de ellos, todos de 256 bytes de largo:
```
@piano-pcm
8182 8588 8d91 959b a1a6 aaad b2b5 b8bd
c1c7 cbd0 d5d9 dde1 e5e5 e4e4 e1dc d7d1
cbc5 bfb8 b2ac a6a2 9c97 928d 8884 807c
7977 7574 7372 7272 7273 7372 706d 6964
605b 5650 4d49 4643 4342 4244 4548 4a4d
5052 5556 5758 5554 5150 4c4a 4744 423f
3d3c 3a38 3835 3431 3030 2f31 3336 393e
4449 4e54 5a60 666b 7175 7b82 8990 989e
a6ab b1b6 babd bebf bfbe bbb9 b6b3 b0ae
aaa8 a6a3 a19e 9c9a 9997 9696 9798 9b9e
a1a4 a6a9 a9ac adad adae aeaf b0b0 b1b1
b3b3 b4b4 b4b3 b3b1 b0ad abab a9a9 a8a8
a7a5 a19d 9891 8b84 7e77 726e 6b6b 6b6c
6f71 7477 7776 7370 6c65 5e56 4e48 423f
3d3c 3b3a 3a39 3838 3839 393a 3c3e 4146
4a50 575b 6064 686a 6e70 7274 7677 7a7d
@violin-pcm
8186 8d94 9ba0 a3a7 acb1 b5bc c2c7 cacc
cecf d0d1 d3d5 d8db dee1 e3e5 e6e5 e5e3
dfdc d7d0 c8c2 bbb2 a99f 968c 847c 746e
675f 5851 4b43 3e3a 3533 312e 2c2b 2826
2422 2122 2327 2d34 3c44 4c57 5f68 7075
7b80 8487 8789 8a8c 8d90 9397 999c 9ea0
a2a2 a2a0 9c97 9491 8f8e 908f 918f 8e88
827a 726a 6058 5047 423f 3f40 4245 4748
4949 4746 4545 4a4f 5863 717f 8b9a a6b1
b8be c1c1 bfbd bab5 b1af acac aeb1 b7bc
c2c9 cfd3 d5d4 d3d3 d1ce cbc6 c0ba b3ab
a39a 8f85 7b72 6c67 6462 605f 5e5d 5b58
5550 4d49 4848 4949 4a4d 5052 5558 5b5e
6164 686c 7074 7677 7979 7a7b 7b7a 7977
7473 6f6e 6b69 696b 6f72 7576 7574 716b
655d 554e 4742 3f3f 4045 4b52 5a62 6b74
@sin-pcm
8083 8689 8c8f 9295 989b 9ea1 a4a7 aaad
b0b3 b6b9 bbbe c1c3 c6c9 cbce d0d2 d5d7
d9db dee0 e2e4 e6e7 e9eb ecee f0f1 f2f4
f5f6 f7f8 f9fa fbfb fcfd fdfe fefe fefe
fffe fefe fefe fdfd fcfb fbfa f9f8 f7f6
f5f4 f2f1 f0ee eceb e9e7 e6e4 e2e0 dedb
d9d7 d5d2 d0ce cbc9 c6c3 c1be bbb9 b6b3
b0ad aaa7 a4a1 9e9b 9895 928f 8c89 8683
807d 7a77 7471 6e6b 6865 625f 5c59 5653
504d 4a47 4542 3f3d 3a37 3532 302e 2b29
2725 2220 1e1c 1a19 1715 1412 100f 0e0c
0b0a 0908 0706 0505 0403 0302 0202 0202
0102 0202 0202 0303 0405 0506 0708 090a
0b0c 0e0f 1012 1415 1719 1a1c 1e20 2225
2729 2b2e 3032 3537 3a3d 3f42 4547 4a4d
5053 5659 5c5f 6265 686b 6e71 7477 7a7d
@tri-pcm
8082 8486 888a 8c8e 9092 9496 989a 9c9e
a0a2 a4a6 a8aa acae b0b2 b4b6 b8ba bcbe
c0c2 c4c6 c8ca ccce d0d2 d4d6 d8da dcde
e0e2 e4e6 e8ea ecee f0f2 f4f6 f8fa fcfe
fffd fbf9 f7f5 f3f1 efed ebe9 e7e5 e3e1
dfdd dbd9 d7d5 d3d1 cfcd cbc9 c7c5 c3c1
bfbd bbb9 b7b5 b3b1 afad aba9 a7a5 a3a1
9f9d 9b99 9795 9391 8f8d 8b89 8785 8381
7f7d 7b79 7775 7371 6f6d 6b69 6765 6361
5f5d 5b59 5755 5351 4f4d 4b49 4745 4341
3f3d 3b39 3735 3331 2f2d 2b29 2725 2321
1f1d 1b19 1715 1311 0f0d 0b09 0705 0301
0103 0507 090b 0d0f 1113 1517 191b 1d1f
2123 2527 292b 2d2f 3133 3537 393b 3d3f
4143 4547 494b 4d4f 5153 5557 595b 5d5f
6163 6567 696b 6d6f 7173 7577 797b 7d7f
@saw-pcm
8282 8183 8384 8685 8888 8889 8a8b 8c8c
8e8e 8f90 9092 9193 9494 9596 9699 9899
9b9a 9c9c 9c9d 9ea0 a1a0 a2a2 a3a5 a4a6
a7a7 a9a8 a9aa aaac adad aeae b0b0 b1b3
b2b4 b5b5 b6b7 b9b8 b9bb babc bdbc bdbe
bfc1 bfc1 c3c1 c4c5 c5c6 c6c7 c9c7 cbca
cbcc cdcd cfcf d2d0 d2d2 d2d5 d4d5 d6d7
d8d8 d9dc d9df dadf dce1 dde5 dce6 dceb
cb1f 1b1e 1c21 1c21 1f23 2025 2127 2329
2529 2829 2a2b 2b2e 2d2f 302f 3231 3234
3334 3536 3836 3939 3a3b 3b3d 3e3d 3f40
4042 4242 4444 4646 4748 474a 4a4b 4d4c
4e4e 4f50 5052 5252 5554 5557 5759 5959
5b5b 5c5d 5d5f 5e60 6160 6264 6365 6566
6867 6969 6a6c 6c6d 6d6e 706f 7071 7174
7475 7576 7777 797a 7a7c 7b7c 7e7d 7f7f
```
=> https://git.sr.ht/~rabbits/uxn/tree/main/item/projects/examples/demos/piano.tal piano.tal código fuente
¿y qué significan estos números?
en el contexto de varvara, podemos entenderlos como múltiples bytes sin signo (u8) que corresponden a las amplitudes de la onda sonora que componen la muestra.
un "cabezal de reproducción" visita cada uno de estos números durante un tiempo determinado, y los utiliza para establecer la amplitud de la onda sonora.
las siguientes imágenes muestran la forma de la onda (o "waveform") de cada una de estas muestras.
cuando hacemos un bucle con estas formas de onda, ¡obtenemos un tono basado en su forma!
piano-pcm:
=> ./img/screenshot_uxn-waveform_piano.png forma de onda de la muestra de piano
violín-pcm:
=> ./img/screenshot_uxn-waveform_violin.png forma de onda de la muestra de violín
sin-pcm:
=> ./img/screenshot_uxn-waveform_sin.png forma de onda de la muestra de sin
tri-pcm:
=> ./img/screenshot_uxn-waveform_tri.png forma de onda de la muestra de sin
saw-pcm:
=> ./img/screenshot_uxn-waveform_saw.png forma de onda de la muestra de sin
de forma similar a como hemos tratado los sprites, y de forma parecida al dispositivo de archivo comentado anteriormente, para fijar una muestra en el dispositivo de audio sólo tenemos que escribir su dirección y su longitud:
```
;saw-pcm .Audio0/direc DEO2 ( establecer dirección de muestra )
#0100 .Audio0/largo DEO2 ( establecer longitud de muestra )
```
la frecuencia a la que se reproduce esta muestra (es decir, a la que la amplitud de la onda toma el valor del siguiente byte) viene determinada por el byte pitch.
## pitch
el byte pitch hace que la muestra comience a reproducirse cada vez que le escribimos, de forma similar a como el byte de sprite realiza el dibujo del sprite cuando le escribimos.
los primeros 7 bits (de derecha a izquierda) del byte corresponden a una nota midi, y por tanto a la frecuencia a la que se reproducirá la muestra.
el octavo bit es una bandera: cuando es 0 la muestra se reproducirá en bucle, y cuando es 1 la muestra se reproducirá sólo una vez.
normalmente querremos hacer un bucle de la muestra para generar un tono basado en ella. sólo cuando la muestra sea lo suficientemente larga tendrá sentido no hacer un bucle y reproducirla una vez.
con respecto a los bits para la nota midi, es una buena idea tener una tabla midi alrededor para ver los valores hexadecimales correspondientes a las diferentes notas.
=> https://wiki.xxiivv.com/site/midi.html tabla midi
el Do medio (C4, o 3c en midi) se asume como el tono por defecto de las muestras.
### un programa de "muestra"
en teoría, parecería que el siguiente programa debería reproducir nuestra muestra a esa frecuencia, ¿o no?
```
( hola-sonido.tal )
( dispositivos )
|30 @Audio0 [ &vector $2 &posicion $2 &salida $1 &pad $3 &adsr $2 &largo $2 &direc $2 &volumen $1 &pitch $1 ]
( programa principal )
|0100
;saw-pcm .Audio0/direc DEO2 ( establecer dirección de muestra )
#0100 .Audio0/largo DEO2 ( establecer longitud de muestra )
#3c .Audio0/pitch DEO ( establecer el tono como Do medio )
BRK
```
¡no realmente!
para poder escuchar el sonido, necesitamos dos cosas más: ajustar el volumen del dispositivo y ajustar la envolvente ADSL.
## volumen
el byte de volumen se divide en dos nibbles: el nibble alto corresponde al volumen del canal izquierdo, y el nibble bajo corresponde al volumen del canal derecho.
por lo tanto, cada canal tiene 16 niveles posibles: 0 es el mínimo, y f el máximo.
lo siguiente establecería el volumen máximo en el dispositivo:
```
#ff . Audio0/volumen DEO ( establecer volumen máximo en izquierda y derecha )
```
¡aunque las muestras son mono, podemos panoramizarlas con el byte de volumen para obtener un sonido estéreo!
## envolvente ADSR
el último componente que necesitamos para reproducir audio es la envolvente ADSR.
ADSR son las siglas de ataque, decaimiento, sostenimiento y relajación. es el nombre de una "envolvente" común que modula la amplitud de un sonido de principio a fin.
en el ordenador varvara, los componentes ADSR funcionan de la siguiente manera:
* la sección de ataque es el tiempo que tarda en pasar la amplitud del sonido que se está reproduciendo de 0 a 100%.
* luego, la sección de decaimiento es el tiempo que se necesita para llevar la amplitud del 100% al 50%.
* luego, durante la sección de sostenimiento la amplitud se mantiene al 50%
* y finalmente, en la sección de relajación la amplitud pasa del 50% al 0%.
cada una de estas transiciones se realiza de forma lineal.
en el corto ADSR del dispositivo de audio, hay un nibble para cada uno de los componentes: por lo tanto, cada uno puede tener una duración de 0 a f.
las unidades para estas duraciones son 15vos de segundo.
como ejemplo, si la duración del componente de ataque es 'f', entonces durará un segundo (15/15 de segundo, en decimal).
lo siguiente establecerá la duración máxima de cada uno de los componentes, haciendo que el sonido dure 4 segundos en total:
```
#ffff .Audio0/adsr
```
ok, ¡ahora estamos listos para reproducir el sonido!
## reproduciendo la muestra
¡el siguiente programa tiene ahora los cinco componentes que necesitamos para reproducir un sonido: una dirección de muestra, su longitud, las duraciones de adsr, el volumen, y su pitch!
```
( hola-sonido.tal )
( dispositivos )
|30 @Audio0 [ &vector $2 &posicion $2 &salida $1 &pad $3 &adsr $2 &largo $2 &direc $2 &volumen $1 &pitch $1 ]
( programa principal )
|0100
;saw-pcm .Audio0/direc DEO2 ( establecer dirección de muestra )
#0100 .Audio0/largo DEO2 ( establecer longitud de muestra )
#ffff .Audio0/adsr DEO2 ( establecer envolvente )
#ff .Audio0/volumen DEO ( establecer volumen máximo )
#3c .Audio0/pitch DEO ( establecer pitch como Do central )
BRK
```
nota (!) que sólo se reproducirá el sonido una vez, y lo hace cuando se inicia el programa.
### algunos experimentos sugeridos
te invito a que experimentes modificando los valores del ADSR: ¿cómo cambia el sonido cuando sólo hay uno de ellos? ¿o cuando todos son números pequeños o con diferentes combinaciones de duraciones?
también, prueba a cambiar el byte pitch: ¿corresponden con tus oídos los valores midi que esperas?
¿y cómo cambia el sonido cuando usas una muestra diferente? ¿puedes encontrar o crear otras diferentes?
## tocar más de una vez
una vez que hemos configurado nuestro dispositivo de audio con una muestra, longitud, envolvente ADSR y volumen, podríamos reproducirlo una y otra vez (re)escribiendo un tono en un momento diferente; los demás parámetros pueden dejarse intactos.
por ejemplo, una macro como la siguiente podría permitirnos reproducir una nota de nuevo según el pitch dado en la parte superior de la pila:
```
%REPR-NOTA { .Audio0/pitch DEO } ( pitch -- )
```
cuando ocurriera un evento específico, podrías llamarlo:
```
#3c REPR-NOTA ( reproducir Do central )
```
ten en cuenta que cada vez que escribes un pitch, la reproducción de la muestra y la forma de la envolvente vuelve a empezar, independientemente de dónde se encuentre.
### algunas ideas
¿qué tal si implementas la reproducción de diferentes tonos presionando diferentes teclas en el teclado? podrías usar nuestros ejemplos anteriores, pero escribiendo un tono en el dispositivo en lugar de, por ejemplo, incrementar una coordenada :)
¿o qué tal si complementas nuestro programa pong de {tutorial de uxn día 6} con efectos de sonido, haciendo que el dispositivo toque una nota cada vez que la pelota rebote?
¿o qué tal si utilizas el vector de la pantalla para cronometrar la reproducción repetitiva de una nota? ¿o qué tal si haces que toque una melodía siguiendo una secuencia de notas? ¿podría venir esta secuencia de un archivo de texto? :)
## información de la reproducción
el dispositivo de audio nos proporciona dos formas de comprobar el estado de la reproducción durante el tiempo de ejecución:
* el corto de posición
* el byte de salida
cuando leemos el corto de posición, obtenemos la posición actual de la "cabeza lectora" en la muestra, empezando por 0 (es decir, la cabeza lectora está al principio de la muestra) y terminando en la longitud de la muestra menos uno.
el byte de salida nos permite leer la amplitud de la envolvente. devuelve 0 cuando la muestra no se está reproduciendo, por lo que se puede utilizar como una forma de saber que la reproducción ha terminado.
## polifonía
la idea de tener cuatro dispositivos de audio es que podemos tenerlos todos sonando a la vez, y cada uno puede tener una muestra, envolvente ADSR, volumen y tono diferentes.
esto nos da muchas más posibilidades:
¿quizás en un juego podría haber una melodía sonando de fondo junto con sonidos incidentales relacionados con la jugabilidad?
¿tal vez se pueda construir un secuenciador en el que se puedan controlar los cuatro dispositivos como pistas diferentes?
¿o tal vez crear una plataforma de livecoding para tener un diálogo con cada uno de los cuatro instrumentos?
en cualquier caso, ¡no dudes en compartir lo que crees! :)
# el final
aunque no lo creas, ¡este es el final!
¡has llegado al final de la serie del tutorial! ¡felicidades!
¡espero que lo hayas disfrutado y que lo veas como el comienzo de tu viaje uxn!
¡nos encantaría ver lo que creas! no dudes en compartirlo en mastodon, en el foro o en el canal irc (¡o incluso por correo electrónico!)
=> https://llllllll.co/t/uxn-virtual-computer/ uxn en el foro lines (inglés)
=> ./contacto.gmi {contacto}
canal irc: #uxn en irc.esper.net
pero antes de hacer todo esto, ¡no te olvides de tomar un descanso! :)
¡nos vemos pronto!
# apoyo
si te ha gustado este tutorial y te ha resultado útil, considera compartirlo y darle tu {apoyo} :)