Manejando más información.


Uno de los problemas que surgen cuando se cominezan a automatizar diversos comportamientos, ya sea para diseñar un timbre activo o para secuenciar un comportamiento sonoro, es la cantidad de datos necesarios para controlar el patch. Por ejemplo, si tenemos el patch del gráfico 1 y deseamos modificar los valores en un tiempo largo, necesitaríamos definir todos los cambios necesarios y su envolventes. Al hacerlo notaríamos que se necesita enviar mensajes a cada una de las entradas que modifican el comportamiento sonoro en el tiempo.

Gráfico 1.

Como podemos observar, en este patch de síntesis FM, hay 8 casillas numéricas que ingresan información que permitirá obtener una diversa gama de timbres cambiantes, además del bang que activa la envolvente que moldeará el sonido. Lo cual quiere decir que para lanzar un sonido, debemos ingresar datos y luego pulsar el bang ¿Cuánto tiempo toma eso? ¿Y si queremos fijar una gama de 50 sonidos distintos para luego organizarlos? Puede convertirse en una tarea larga, lo cual está bien de cierta forma, conocer el material a través de la modificación directa de los parámetros es una forma de encontrar los sonidos que uno quiere, pero también es posible imaginar o determinar posibles comportamientos.

Contemplemos dos caminos posibles. El primero puede ser un subpatch con todos los mensajes necesarios y crear una cadena de delays que dispare uno cada mensaje necesario para controlar el comportamiento sonoro. Otra posibilidad es utilizar alguno de los siguientes tres objetos: |textfile|,  |qlist| o |coll|. Con estos objetos podemos crear listas de datos que como veremos a continuación pueden tener diferentes tipos de mensaje y que resultarán totalmente efectivas para controlar patches cuyo comportamiento es determinístico (osea que nosotros definimos completamente qué va a pasar).

Antes de ir al uso específico de los objetos mencionados previamente, pensemos en los mecanísmos que empleamos para enviar, procesar órdenes y continuar con las siguientes instrucciones. Para iniciar el proceso enviamos un mensaje de activación (en Pd un bang) el cual hará que la información fluya hacia "la máquina" que la procesará. Si es un sólo dato, es enviado a su destino, pero si tenemos un dato compuesto por varios "pedazos" de información, tenemos que anteponer algún elemento que clasifique y distribuya la información. Por un momento supongamos que no sólo estamos controlando el patch del gráfico 1, sino que controlamos tres de esos, sería necesario enrutar toda la información haciendo necesario un mecanismo que envíe a cada patch la información apropiadamente desde una fuente central.

Luego de que la información ha llegado a su destino y se ha producido la modificación al sonido, es necesario un tiempo de espera para el envío del siguiente conjunto de datos. Este proceso se continuará un cierto número de veces hasta que terminemos nuestro procesamiento.

También es posible que cada uno de los datos que queremos cambiar tenga su propio ritmo, su propio tiempo para cambiar. En ese caso no es necesario que creemos una lista para cada uno.

Voy a ejemplificar el uso de textfile enviando a cada parámetro en su propio tiempo. Para tal propósito voy a crear un subpatch en el que se puedan observar tres posibilidades de comportamientos asociados a los datos. El primero es cuando se desea crear un cambio desde un valor A hasta un valor B en un tiempo específico; el segundo cuando se desea cambiar linealmente del valor actual a uno nuevo en un tiempo que se especifica; y la última es cuando se desea cambiar abruptamente a un valor.

Es necesario explicar algunos objetos adicionales para lograr mi propósito. El primero es |route|, el cual recibe una lista (por ejemplo: 1 2 300 499 1999 o 4 1 250 600 1500) y a partir del primer elemento de la lista dirige el resto de la información después del primer elemento hacia la salida que le corresponde.

Subpatch 1.

En el subpatch1 aparece el objeto |route| con los valores 1 2 3, eso quiere decir que al recibir una lista que tenga como primer elemento alguno de los anteriores números, los enviará a sus salidas específicamente (de izquierda a derecha). Hay una cuarta salida, la cual siempre va a aparer siempre que usemos este objeto, su función es enviar a esa salida una lista cuyo primer elemento no corresponda a los valores que se determinaron al crear el objeto. Por ejemplo, si enviamos a este |route 1 2 3| una lista que comience con el número nueve, ésta va a salir por la última salida (la de más a la derecha).

El otro objeto que nos será útil, es |niagara| cuya función es separar los valores de una lista a partir del elemento que le especifiquemos. En este caso lo vemos inicializado con 3, 2 y 1. Si tomamos como ejemplo la lísta  2 300 499 1999 al llegar a |route 1 2 3| va a ser enviado a la segunda salida (de izquierda a derecha) sin el primer elemento de esa lista, es decir, nuestra nueva lista es: 300 499 1999. Luego al llegar a |niagara 2| la lista va a ser dividida en dos, como el argumento que está en el objeto es 2, la primera lista contiene los dos primeros elementos, osea: 300 400, y la segunda lista compuesta por 1999. Cada uno de estos va a salir a una salida de este objeto, a la izquierda la primera lista y a la derecha la segunda.

Ahora que ya sabemos para qué sirven esos objetos, sigamos todo el camino de una lista que entra a este subpatch. Tomemos como primer ejemplo un mensaje que va a cambiar un valor desde uno inicial hasta uno final en un tiempo determinado. Para que esto ocurra debe ser enrutado a la salida de más a la izquierda de |route|, por tanto el primer elemento de la lista debe ser 1. Aclarado esto vamos a definir los demás valores. El primero corresponderá al valor inicial y será 500; el segundo corresponde al valor final y será 450; en tercer lugar el tiempo en el cual se ejecutará la orden que será 2000; finalmente un valor de tiempo que determinará el retardo para que se envíe la siguiente orden (siguiente lista, la cual puede ir a otro objeto de control, no necesariamente al mismo) el cual será 500.

Entonces nuestra lista es 1 500 450 2000 500. Al entrar a route será enviado a la salida de más a la izquierda y saldrá 500 450 2000 500. luego entra a niagara y será dividido a partir del tercer elemento, por tanto las salidas serán: a la izquierda 500 450 2000 y a la derecha 500. La lista 500 450 2000 va al mensaje |$1, $2 $3< que va a |line| y generará una serie de valores desde 500 hasta 450 en 2000 milisegundos. Simultáneamente, la salida de la derecha de niagara, 500 será enviado a un bang y a un |del|. Al entrar a la derecha de |del| se especificará que retrace 500 milisegundos la salida del bang que ha sido activado por esta misma salida.

Otro ejemplo, si necesitamos enviar una lista que haga que el valor salte inmediatamente a un valor requerido necesitamos que sea enrutado a la tercera salida, por tanto debe comenzar con 3, seguido del valor al cual deseamos cambiar y finalmente un tiempo para la siguiente instrucción. Esto puede ser 3 600 50.

Ahora, en un segundo subpatch que contiene al subpatch |pd control| que nos servirá para controlar cada uno de los datos del patch de síntesis FM.

Subpatch 2.


Ahora sí podemos ejemplificar el uso de |textfile|.  Este objeto nos permite tener listas de instrucciones como las que he ejemplificado anteriormente en un archivo de texto (archivo.txt) como el que se puede crear en notepad en Windows o gedit en Linux y en algún procesador de textos en OSX. Esos archivos son organizados con los datos en la siguiente forma:

9;
1 1 200 399 4000 500;
3 2 499 6000 50;
5 3 700;
etc...

Cada lista de datos debe terminar con un punto y coma (;). Para el caso que estamos analizando, el primer elemento de cada lista indica la salida a la que va a ser enrutada cada lista. y el resto de la lista entra a |pd control| que ya estudiamos antes.

Continuando con |textfile|, observemos que a su entrada tiene conectados varios objetos y mensajes. El primero que vamos a considerar es el siguiente:

El objeto |openpanel| activado con un bang nos permite buscar mediante una ventana de diálogo la ruta del archivo de texto que vamos a usar. Al finalizar la búsqueda señalamos el archivo y le damos abrir, lo cual simplemente le envía a la salida de este objeto la ruta en el disco duro, que en este caso irá al mensaje |read $1< donde $1 será la ruta que le enviemos. También podemos escribir la ruta directamente en el mensaje read, pero dependerá del sistema operativo que usemos. Otra opción que tenemos es guardar el archivo de texto en la misma carpeta que hemos guardado el patch en el que se encuentra textfile y lo único que necesitaremos es escribir un mensaje |read archivo.txt< y hacer clic sobre este para que abra dicho archivo.

En la programación que estamos viendo, del mensaje |read $1< se conecta a |textfile| y a un bang, el cual a su vez está conectado a un delay de 10 milisegundos que está conectado a un mensaje que dice rewind. Este último mensaje es necesario para que al enviarle bangs a |textfile| recorramos el archivo desde el principio. Al conectar de la forma que podemos observar lo que hacemos al enviar la ruta del archivo es pedirle a |textfile| que abra el archivo y 10 milisegundos después pedirle que vaya al principio del mismo (Para mayor referencia sobre el objeto |texfile| haga clic derecho sobre este y pulse Help).

Ya casi estamos listos para controlar nuestro patch de síntesis FM, sólo falta explicar qué ocurre con la última salida del |route| que está conectado a continuación de |textfile| y los objetos |s siguiente| y |r siguiente|.

La novena salida de |route| tomará cualquier lista que no comience con cualquiera de los números listado como parámetros iniciales. Podemos observar que esa salida está conectada a un bang cuya salida va a un |outlet| y a |s siguiente|.

Los objetos |s siguiente| y |r siguiente| son conexiones "inalambricas" dentro del patch. Todo lo que entre a |s siguiente| va a ser enviado a |r siguiente|. En este caso va a ser un bang que fue retrazado una cantidad de tiempo para que se envíe la siguiente instrucción.

Ahora veamos cómo quedó el patch con los subpatches que he explicado.

 Ya estamos listos para controlar el patch sin demora. Observemos que todo el proceso de modulación tiene una envolvente de 7000 milisegundos. Para activar esa envolvente se puede añadir en el archivo de texto un mensaje con cualquier número mayor a 8 y un punto y coma.

Ejercicios:

1- Propongo replicar el patch y sus respectivos subpatches y comenzar a probar con diferentes valores en un archivo de texto.

2- Modificar el generador de envolventes para que también pueda ser controlado por textfile. 


Comentarios

Entradas populares de este blog

Conociendo lo básico de Pure Data

Pure data - Vanilla, lo básico, añadir externos

Síntesis aditiva