Primero, voy a mostrar el código con un poco más de espacios en blanco para que se entienda un poco mejor:
SynthDef("anita",
{ Out.ar (0, Pan2.ar (FreeVerb.ar (LFTri.ar ([660,330]) * FsinOsc.ar (2), 0.3)) * LFSaw.ar ( [0.5, 0.5]) * LFSaw.ar ( [1.5, 1] ))}
).play
Voy a dejar la definición y utilidad de “SynthDef” para lo último, por una cuestión más que todo didáctica. Si nos fijamos, hay algo que se repite dentro de las llaves y es ese “.ar” luego de cada clase: Out.ar, Pan2.ar, FreeVerb.ar, etc.
Eso quiere decir que .ar realiza un procesamiento en todas las muestras de sonido, a diferencia de .kr, un método que controla el procesamiento reduciéndolo a 1/64 de las muestras de esos sonidos. Pueden leer más especificidades sobre estos métodos en esta sección de la documentación de SuperCollider.
Para empezar, utilizo la clase Out que sirve para especificar que vamos a escribir una señal como salida. A esa clase le agrego el .ar para que haga un procesamiento sobre el total de las muestras de esa señal que voy a escribir:
{ Out.ar
La señal es todo lo que está incluido dentro de los paréntesis que le siguen a esa primera clase. En realidad los únicos parámetros que le asigno a la señal Out son
- 0,
- Pan2.ar; y
- dos tipos diferentes de LFSaw.ar, o sea:
(0, Pan2.ar (...) * LFSaw.ar (...) * LFSaw.ar ( ...))
Si separamos en términos, son solamente dos parámetros: un bus y un “channelsArray”. Con esto determino cuál parte del hardware quiero utilizar (bus) y luego una lista de canales con sus respectivos parámetros (channelsArray). En mi ejemplo estoy utilizando un array integrado por la función Pan2 que me permite hacer un paneo de igual poder de la onda triangular reverberada en 2 canales. Esa onda triangular (*LFTri.ar* con dos frecuencias audibles de 660 y 330) con reverberación (*FreeVerb.ar*) que afecta a un 30% de sonido crudo (ya que se establece dentro de un rango dry/wet entre 0 y 1), se aproxima a su vez a una sinusoide de 2Hz de frecuencia (*FsinOsc(2)*). Eso es lo que especifico en este fragmento:
(FreeVerb.ar(LFTri.ar([660,330])*FSinOsc.ar(2), 0.3)
De esta forma, la señal sobre la cual realizo el paneo luego se va aproximando a otras dos señales “diente de sierra” (*LFSaw*) a las cuales les especifiqué diferentes frecuencias (lo que está entre corchetes) y que son las que completan el array:
Pan2.ar (FreeVerb.ar (LFTri.ar ([660,330]) * FsinOsc.ar (2), 0.3)) * LFSaw.ar ( [0.5, 0.5]) * LFSaw.ar ( [1.5, 1] )
Añadiendo algunas cosas más que vamos a explicar el código queda así:
SynthDef("anita", { Out.ar(0, Pan2.ar(FreeVerb.ar(LFTri.ar([660,330])*FSinOsc.ar(2), 0.3))*LFSaw.ar([0.5, 0.5]) * LFSaw.ar([1.5, 1]))}).play
Viendo las ondas en ejes, quedan más o menos así (no pude hacer un gif para que aprecien el movimiento, perdón!):
SynthDef toma todo lo que expliqué anteriormente como un tipo de sonido, el cual se representa como un nodo que utiliza ciertos métodos para cumplir una cierta especificidad, lo que permite apreciar este código de una manera más formal y reutilizable en otras implementaciones que piensen en características estructurales de la música. En este sentido utilizar el sinte “anita” como un tipo de sonido que puede formar parte dentro de conjuntos de sonidos con sus comportamientos puede resultar útil para quienes aprecian las posibilidades que ofrecen los sonidos dentro de estructuras musicales con sus complejidades, simplezas y formalidades.
Una sola cosa más: a la función FreeVerb se le pueden asignar más parámetros y eso es algo que descubrí justamente deconstruyendo mi sinte. Por eso me autoremixé y compartí esos resultados acá.
(Este posteo está absolutamente inspirado en el trabajo que hizo Schemawound en su blog , algo que me fue de mucha utilidad cuando empecé a experimentar con SuperCollider)