Taller de Audio del Centro Multimedeia del CNA

Clase 6 - Tdef

Curso de SuperCollider Principiantes

Tdef

.do

Primero necesitamos conocer una herramienta que nos sirve como núcleo de nuestro Tdef. Estamos hablando del   n.do. Veamos un ejemplo:

"gggggg9g9g9g".postln

2.do{ "ggggggggggggggggg9999ggg999ggg999gg".postln}

Intuitivamente podemos pensar que la línea anterior escribe 2 veces el string "ggggggggggggggggg9999ggg999ggg999gg". En realidad así es. Entonces definamos .do como un método que nos hace n veces lo que le pongamos dentro de las llaves {}. Para hacer más interesante la cosa agregemos el mensaje .scramble que desordena una cadena de caracteres o los elementos de un array. Mira:

[0,1,2,3,4,5];
[0,1,2,3,4,5].scramble

"ggggggggggggggggg9999ggg999ggg999gg".postln
"ggggggggggggggggg9999ggg999ggg999gg".scramble.postln


Ahora con el .do

50.do{"ggggggggggggggggg9999ggg999ggg999gg".scramble.postln}

50.do{ [0,1,2,3,4,5].scramble.postln}

Podemos poner mas de una acción dentro de la función. Solo hay que escribir punto y coma ; entre cada acción distinta.

50.do{
        "ggggggggggggggggg9999ggg999ggg999gg".scramble.postln;
        [0,1,2,3,4,5].scramble.postln;
        [1,2,3,4,5,6].choose.postln;
        }

Podemos poner cualquier cosa dentro de las llaves del .do. Pongamos un oscilador:

{SinOsc.ar(rrand(300,5000),0,1/10)}.play

10.do{{SinOsc.ar(rrand(300,5000),0,1/10)}.play}

O podemos llamar a un Synth. Primero hagamos el SynthDef y luego lo llamamos dentro de un .do.

SynthDef(\hacer, {|freq=400| Out.ar(0,SinOsc.ar(freq,0,1/10)*EnvGen.kr(Env.perc(0.01,5),doneAction:2))}).send(s)

10.do{Synth(\hacer, [\freq, rrand(300,5000)])}

Otro ejemplo de cómo usar el .do lo tenemos dentro de un SynthDef con reverb:

(
SynthDef(\rev, {|gate=1|
                        var sen, env;
                        sen=Impulse.ar(1);
                        5.do{sen=AllpassN.ar(sen, 0.1, rrand(0.03,0.04), 1.5)};
                        env=EnvGen.kr(Env.asr(0,1,0),gate, doneAction:2);
                        Out.ar(0,sen*env);
                        }).send(s);
)

r=Synth(\rev)
r.set(\gate, 0)


Tdef
 
¿Qué es?, ¿Para qué sirve?

1- Tdef es el nombre que se le da a la estructura que nos permite generar loop's o repeticiones.
2- Es de gran utilidad para la creación de patrones rítmicos o para modificar, de manera automática, los argumentos de nuestros Synth's.
3- Los Tdef funcionan por medio de un reloj al que podemos cambiar su velocidad.
4- Los Tdef pueden modificarse sin necesidad de ser apagados.

Como vimos en los ejemplos anteriores el .do realiza n veces una acción que está dentro de las llaves de función {} y lo hace inmediatamente. Pero, ¿Qué pasa si queremos que lo haga con una pausa entre cada vez? Para eso necesitamos recurrir a otra de las estructuras o Templates que SuperCollider nos brinda: Tdef.

Tdef viene de las palabras Task definition y es similar en su construcción al SynthDef. Veamos como se construye y para que sirve cada una de sus partes.

(
Tdef(\x, {     // Escribimos Tdef, abrimos paréntesis y ponemos un string con el nombre con el que queremos identificar el Tdef.              // Ponemos coma y abrimos una llave que englobará todo el contenido de nuestro Tdef.
             50.do{                                    // Después ponemos un .do como hemos hecho anteriormente.
                       [0,1,2,3,4].scramble.postln;  //ponemos una acción que sera ejecutada 50 veces
                       0.05.wait;                         // Añadimos otra acción mas que será un número con el mensaje .wait, este número
                                                           // representa el tiempo en segundos que esperará antes de volver a hacer la acción.
                       }
             });  // Cerramos la llave englobadora del Tdef y el paréntesis.
             )

Después para hechar a andar el Tdef lo hacemos refiriéndonos al Tdef por su nombre  con el mensaje .play como se muestra a continuación:

Tdef(\x).play
Tdef(\x).stop

Para detener el Tdef usamos el mensaje .stop. Si queremos que el Tdef tenga un .do con un número infinito de repeticiones utilizamos la palabra inf en vez de un número finito

(
Tdef(\x, {
            inf.do{
                    "ggggg_____ggggsupercollider rules!gggggg****gg9999ggg999ggg999gg".scramble.postln;
                    0.15.wait;
                    }
            });
            )
           

Tdef(\x).play
Tdef(\x).stop


Es MUY IMPORTANTE  que cuando usemos inf.do nos aseguremos de escribir un .wait dentro por que si no le estaremos pidiendo al SuperCollider que haga un número infinito de acciones en una cantidad infinitamente pequeña de tiempo.

Un sinónimo de inf.do es loop.

(
Tdef(\x, {
            loop{
                    "ggggggggggggggggg9999ggg999ggg999gg".scramble.postln;
                    0.05.yield;
                    }
            });
            )
           
un sinónimo de .wait es .yield

Tdef(\x).play
Tdef(\x).stop

Dentro de un .do podemos poner otros .do en lo que llamamos un arreglo anidado.

(
1.do{
     4.do{ "---------////----------------------".postln;};
     10.do{"======;;;;;=======".postln;};
     5.do{"*******////#######".postln;}
     }
     )

Observemos cómo se comporta el arreglo anidado dentro de un Tdef con inf.do. Nótese que cada .do tiene su propio .wait.

(
Tdef(\x, {
   inf.do{
           4.do{
                 "---------////----------------------".scramble.postln;
                    0.25.wait;
                    };
          10.do{
                    "======;;;;;=======".scramble.postln;
                    0.05.wait;
                    };
           5.do{
                   "*******////#######".scramble.postln;
                   0.15.wait;
                   }
           }
          });
)
             
Tdef(\x).play
Tdef(\x).stop

Ahora viene lo bueno. Podemos llamar a un Synth dentro de un Tdef para que no tengamos que estar picandole como locos con el mouse. Mirá:

(
SynthDef(\uno,{|out=0|
                    var sen, env;
                sen=SinOsc.ar(820,0,0.8)!2;
                   env=EnvGen.kr(Env.perc(0,0.1),doneAction:2);
               Out.ar(out,sen*env)
               }).send(s)
)
             
Synth(\uno)

Este Tdef dispara el Synth(\uno) dos veces por segundo o cada 0.5 segundos.

(
Tdef(\x,{
         inf.do{
                  Synth(\uno);
               0.5.wait;
               }
        })
)

Tdef(\x).play
Tdef(\x).stop

Probablemente se habrán dado cuenta de que al darle play al Tdef comienza a funcionar con una pequeña latencia. Para evitar esto escribimos el mensaje .quant . Ejemplo:

Tdef(\x).quant_(0).play
Tdef(\x).stop

Como pueden ver el mensaje .quant lleva escrito un argumento que en este caso es 0 indicando que no haya latencia al comenzar el Tdef. Notar el guión bajo antes de los paréntesis para el argumento.

Otro ejemplo sencillo incorporando un XLine dentro del Synth. El XLine hace una linea de numeros en base a tres argumentos:

XLine.kr(punto de partida, punto final, tiempo que se tarda en ir de un punto a otro)

(
SynthDef(\cuatro2,{|out=0,gate=1,frecuencia=100,mul=0.6|
    var sen, env;
       sen=Saw.ar(XLine.kr(12200,120,0.13),mul)!2;
          env=EnvGen.kr(Env.perc(0,0.15),gate,doneAction:2);
              Out.ar(out,sen*env)
              }).send(s)
              )
             
Synth(\cuatro2)
             
(
Tdef(\gh,{
     inf.do{
              Synth(\cuatro2);
             0.58.wait;
             }}
             )
            )
           
 Tdef(\gh).play
 Tdef(\gh).stop

Hagamos otro Synth con la capacidad de cambiar su frecuencia desde afuera con un argumento "frecuencia".

(
SynthDef(\dos,{|out=0,frecuencia=100|
                var sen, env;
               sen=SinOsc.ar(frecuencia,0,0.8)!2;
                env=EnvGen.kr(Env.perc(0,0.1),doneAction:2);
              Out.ar(out,sen*env)
              }).send(s)
)

Este Tdef es como un LFNoise0.kr modulando a un SinOsc.ar cambiando su frecuencia cada 0.18 seg.

(
Tdef(\x1,{
           inf.do{
                      Synth(\dos,[\frecuencia,rrand(100,4000)]);
                 0.18.wait
                 }
         })
)

Tdef(\x1).play
Tdef(\x1).stop

///////////////////////////////////////////////

Ahora fíjense como se comporta un Tdef con .do anidados disparando Synth relacionados con strings que se escriben en la post window.

(
SynthDef(\tres,{|out=0,frecuencia=100,mul=0.8|
                  var sen, env;
                sen=SinOsc.ar(frecuencia,0,mul);
                env=EnvGen.kr(Env.perc(0,0.1),doneAction:2);
                Out.ar(out,sen*env)
                }).send(s)
)

(
Tdef(\x2,{
             inf.do{
                     3.do{
                          Synth(\tres,[\frecuencia,rrand(200,300),\mul,rrand(0,0.8)]);
                         "---------////----------------------".scramble.postln;                          0.1.wait;
                         };
                     3.do{
                          Synth(\tres,[\frecuencia,1300,\mul,rrand(0,0.8)]);
                         "======;;;;;=======".scramble.postln;
                          0.07.wait;
                          };
                     5.do{
                          Synth(\tres,[\frecuencia,rrand(2700,3500),\mul,rrand(0,0.8)]);
                         "***////##".scramble.postln;                         0.17.wait;
                         }
            
                }
                })
)

Tdef(\x2).play
Tdef(\x2).stop

////////////////////////////////////////////////

Lo mismo pero solo los Synth

(
SynthDef(\cuatro,{|out=0,gate=1,frecuencia=100,mul=0.8|
                  var sen, env;
                  sen=Saw.ar(frecuencia,mul)!2;
                  env=EnvGen.kr(Env.perc(0.06,0.15),gate,doneAction:2);
                  Out.ar(out,sen*env)
                  }).send(s)
)

(
Tdef(\x2,{
             inf.do{
                     3.do{
                          Synth(\cuatro,[\frecuencia,rrand(200,300),\mul,rrand(0,0.4)]);                       0.1.wait;
                          };
                  12.do{
                        Synth(\cuatro,[\frecuencia,130,\mul,rrand(0,0.4)]);
                        0.06.wait;
                        };
                  4.do{
                       Synth(\cuatro,[\frecuencia,rrand(270,350),\mul,rrand(0,0.4)]);                        0.17.wait;
                       }
                }
         })
)

Tdef(\x2).play
Tdef(\x2).stop

//--
(
Tdef(\x2,{
            inf.do{
                 3.do{
                     Synth(\cuatro,[\frecuencia,4000,\mul,rrand(0,0.4)]);
                     0.071.wait;
                     };
                 8.do{
                      Synth(\cuatro,[\frecuencia,1300,\mul,rrand(0,0.4)]);
                      0.057.wait;
                      };
                 4.do{
                      Synth(\cuatro,[\frecuencia,345,\mul,rrand(0,0.4)]);
                      0.17.wait;
                      };
                 14.do{
                       Synth(\cuatro,[\frecuencia,45,\mul,rrand(0,0.4)]);
                       0.07.wait;
                       }
                 }
           })
)
          

Tdef(\x2).play
Tdef(\x2).stop



////////////////////////////////////////////////
***********************************************
////////////////////////////////////////////////

Hasta ahora hemos trabajado con Tdef´s que disparan y controlan los argumentos de Synth´s con envolventes percusivas. Esto implica que nuestros Tdef´s tienen que disparar los Synth´s. Si queremos usar un Tdef para controlar un Synth con envolvente del tipo ASR entonces tenemos que disparar el Synth solo una vez al principio y luego el Tdef modificará los argumentos de nuestro Synth mientras este prendido. Para detenerlo hay que apagar el Tdef y luego el SynthDef.


(
SynthDef(\cinco,{|out=0,frecuencia=100,cutoff,amp=0.3,gate=1|
     var sen,env;
       sen=Saw.ar(frecuencia,amp)!2;
           env=EnvGen.kr(Env.asr(0.3,1,2),gate,doneAction:2);
            Out.ar(out,sen*env)
            }).send(s)
            )
a=Synth(\cinco)
a.set(\gate,0)

Fijense como podemos prender el Synth desde el Tdef si lo colocamos antes del .do

(
Tdef(\x3, {  a=Synth(\cinco);
             inf.do{
                     a.set(\frecuencia,rrand(1000,120));
                     0.3.wait
                 }
          })
)

Tdef(\x3).play
Tdef(\x3).stop;a.set(\gate,0)
a.set(\gate,0) // Hay que apagar el Synth despues del Tdef si ya no queramos usarlo.

/////////////////////////////////////////////////////////

(
SynthDef(\cinco,{|out=0,frecuencia=100,cutoff=300,amp=0.3,gate=1|
     var sen,env,filtro;
       sen=Saw.ar(frecuencia,amp)!2;
         filtro=RLPF.ar(sen,cutoff,0.9);
           env=EnvGen.kr(Env.asr(0.3,1,2),gate,doneAction:2);
            Out.ar(out,filtro*env)
            }).send(s)
            )
d=Synth(\cinco)
d.set(\gate,0)

En este ejemplo prendemos el Synth desde afuera y antes de prender el Tdef.

a=Synth(\cinco);

(
Tdef(\x3,{
             inf.do{
                     a.set(\frecuencia,rrand(100,220),\cutoff,8000);
                     0.1.wait
                 }
         }
    )
)

Tdef(\x3).play
Tdef(\x3).stop;
a.set(\gate,0)


Observen que pasa si prendemos un Tdef que modifica los argumentos de un Synth que aun no ha sido prendido.

(
Tdef(\x3,{
             inf.do{
                     a.set(\frecuencia,rrand(200,420),\cutoff,[12000,8400,9600,7500,3500,6700,6000].choose);
                     0.1.wait;
                 }
          }
    )
)
   
  
Tdef(\x3).play

Nos dice que no encuentra el Synth : FAILURE /n_set Node not found.

Prendamos el Synth y la falla desaparece.

a=Synth(\cinco);
Tdef(\x3).stop;
a.set(\gate,0)

A continuación se muestran varios ejemplos de la mancuerna Tdef - SynthDef

(
Tdef(\x3,{
     inf.do{a.set(\frecuencia,[60,62,64,65,67,69,71].choose,\cutoff,[200,400,600,1400,1500,2700,3000].choose);0.1.wait
     }}
    )
    )  
   
a=Synth(\cinco);Tdef(\x3).play
Tdef(\x3).stop;a.set(\gate,0)


(
Tdef(\x3,{
     inf.do{
     3.do{a.set(\frecuencia,[60.3453,62.204,64.32333,65.5324,67.209,69.42,71].choose,\cutoff,[2300,2400,600,3400,1500,2700,3000].choose);0.21.wait};
     4.do{a.set(\frecuencia,[120,632,614,65,67,269,741].choose,\cutoff,[14200,4040,6500,8400,5500,6700,3000].choose);0.1.wait};
     12.do{a.set(\frecuencia,[610,622,64,635,367,69,71].choose,\cutoff,[2200,4400,6600,14040,1500,2700,3000].choose);0.071.wait};
     3.do{a.set(\frecuencia,[640,62,64,665,67,639,71].choose,\cutoff,[12200,400,600,1400,15300,2700,3000].choose);0.11.wait}
     }}
    )
    ) 

a=Synth(\cinco);
Tdef(\x3).play
Tdef(\x3).stop;
a.set(\gate,0)

///////////////////////////////////////////////////////////////////
(
SynthDef(\seis,{|out=0,frecuencia=60,cutoff=300,amp=0.21,gate=1|
     var sen,env,filtro;
       sen=Saw.ar(frecuencia,amp)!2;
         filtro=RLPF.ar(sen,MouseX.kr(200,15000),0.9);
           env=EnvGen.kr(Env.asr(0.3,1,2),gate,doneAction:2);
            Out.ar(out,filtro*env)
            }).send(s)
            )

b=Synth(\seis);
b.set(\gate,0)
Aqui vemos como el número que antecede al .do puede ser aleatorio y se define de modo diferente en cada vuelta. Utilizamos un +1 en cada .do para evitar el 0.

(
Tdef(\x4,{
     inf.do{
     1+(10.rand).do{b.set(\frecuencia,[60,65].choose);0.19.wait};
     1+(5.rand).do{b.set(\frecuencia,[66,67].choose*4);0.19.wait};
     1+(7.rand).do{b.set(\frecuencia,[61,65].choose*16);0.19.wait}
    
     }}
    )
    )
Tdef(\x4).play
Tdef(\x4).stop;
b.set(\gate,0)


////////////////////////////////////////////////////////////////////////////////////////////////////////////

Ahora veamos como podemos construir una batería acompañando a un instrumento melódico por medio de Tdef´s. Primero hacemos nuestros SynthDef´s para cada elemento de la batería como bombo, tarola y hi hat y también el SynthDef para nuestro instrumento melódico que aqui tiene el revelador nombre de "seis".

(
(
SynthDef(\bombo,{|out=0,gate=1,frecuencia=60|
    var sen, env;
       sen=Pan2.ar(SinOsc.ar(frecuencia,pi*0.25,0.8),0,0.9);
          env=EnvGen.kr(Env.perc(0,0.13),gate,doneAction:2);
              Out.ar(out,sen*env)
              }).send(s)
              );
            
           
(
SynthDef(\tarola,{|out=0,gate=1,frecuencia=660|
    var sen, env,ruido;
    ruido=LPF.ar(WhiteNoise.ar(0.34),XLine.kr(12000,200,0.2),0.9);
       sen=Pan2.ar(SinOsc.ar(frecuencia,0,0.114)+ruido,0,0.8);
          env=EnvGen.kr(Env.perc(0,0.153),gate,doneAction:2);
              Out.ar(out,sen*env)
              }).send(s)
              );


(
SynthDef(\hi,{|out=0,gate=1|
   var sen, env;
      sen=HPF.ar(WhiteNoise.ar(0.5),2000,0.9);
      env=EnvGen.kr(Env.perc(0,0.13),gate,doneAction:2);
      Out.ar(out,Pan2.ar(sen*env,0,0.5))
      }).send(s)
      )
    
      )
         
(
SynthDef(\seis,{|out=0,frecuencia=60,cutoff=300,amp=0.21,gate=1|
     var sen,env,filtro;
       sen=Saw.ar(frecuencia,amp);
         filtro=RLPF.ar(sen,MouseX.kr(200,15000),0.9);
           env=EnvGen.kr(Env.asr(0.3,1,2),gate,doneAction:2);
            Out.ar(out,filtro*env)
            }).send(s)
            )

Como ven los Synth de la batería tienen una envolvente percusiva y el de la melodía tiene envolvente ASR.


Prendemos el Synth "seis"...



Vamonos!!!

(
b=Synth(\seis);
(
Tdef(\bat,{
     inf.do{
     2.do{Synth(\bombo);0.19.wait};
     1.do{Synth(\tarola);(0.19*2).wait}
          }}
)
);
Tdef(\bat).play;
(
Tdef(\hihat,{
     inf.do{Synth(\hi);0.19.wait
              }}
             )
             );
Tdef(\hihat).play;
(
Tdef(\x4,{
     inf.do{
     1+(10.rand).do{b.set(\frecuencia,[60,65].choose);0.19.wait};
     1+(5.rand).do{b.set(\frecuencia,[66,67].choose);0.19.wait};
     1+(7.rand).do{b.set(\frecuencia,[61,65].choose);0.19.wait}
    
     }}
    )
    );
    Tdef(\x4).play
)           

// Bueno, ya.

Tdef(\bat).stop;Tdef(\hihat).stop;Tdef(\x4).stop;b.set(\gate,0)

/////////////////////////////////////////////////////////////////////////////////


Aparte de todo para grabar con un bitRate de 16 escriben

s.recSampleFormat="int16"

////////////////////////////////////////////////////////////////////////////////

 

Descargar Documento