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"
////////////////////////////////////////////////////////////////////////////////