Is = Server.internal; //prendemos el Servidor de esta manera para
correr los ejemplos de la clase 8
s.boot;
BUFFER
Los Buffers son arrays de números de punto flotante (con
decimales) con un pequeño encabezado descriptivo.
Son colocados en un array global y están indexados por
números enteros, empezando por el cero.
Los vamos a utilizar para accesar o escribir: archivos de audio,
tablas, líneas de delay, envolventes o para cualquier otra cosa
que pueda utilizar un array de números de punto flotante.
Solo vamos a ver una de las dos formas de cargar un archivo de audio:
1.- Object style con Buffer.read
Buffer.read asigna un buffer e inmediatamente lee un
archivo de audio en él.
Buffer.read(server, path, startFrame = 0, numFrames = -1,
completionMessage);
server -
el servidor en donde crearemos el buffer. Generalmente pondremos: s
path - la
dirección del archivo de audio
startFrame - a partir de
qué cuadro del archivo vamos a leer. 0 si queremos leerlo
desde el principio (éste es el default).
numFrames - número de
cuadros que vamos a leer. -1 si queremos que lea todo el archivo.
(éste es el default).
completionMessage - una función que
será evaluada al terminar de cargar el archivo de audio.
path
Hay tres formas de indicar la dirección de un
archivo de audio:
1.- Si el archivo de audio se
encuentra en el directorio sounds que se halla dentro del directorio
SuperCollider:
"sounds/nombre_del_archivo"
2.- Si el archivo se encuentra en algún
subdirectorio de tu directorio de usuario:
"~/Documents/Audios/nombre_del_archivo".standardizePath
3.- Si prefieres escribir la dirección
completa:
"/Users/s/Documents/Audios/nombre_del_archivo"
(
b
=
// asignamos la variable b
// al objeto que será
// creado por la clase
// Buffer, para después poder
// mantener la comunicación
// con él
Buffer.read(
s,
// el servidor
"sounds/a11wlk01-44_1.aiff" // la dirección
del archivo de
// audio.
// (este archivo de audio
// viene con el programa)
// generalmente vamos a
// utilizar los valores
// default de los demás
// argumentos
)
)
b = Buffer.read(s,"sounds/a11wlk01-44_1.aiff")
Si mandamos el mensaje .bufnum al objeto que
acabamos de crear con Buffer, éste nos responderá el
número de buffer que fue asignado a nuestro archivo de audio:
b.bufnum
Si no estamos seguros del número de canales
de nuestro archivo de audio, podemos mandar el mensaje .numChannels a
nuestro buffer.
b.numChannels
Para tocar nuestro buffer vamos a utilizar el UGen
PlayBuf:
PLAYBUF
Con PlayBuf leemos un sample que ya se encuentre cargado en la memoria.
PlayBuf.ar(numChannels, bufnum, rate, trigger,
startPos, loop)
numChannels - número de canales del sample que
va a ser leído. Hay que tener cuidado, ya que si ponemos un
número de canales erróneo, PlayBuf va a fallar
silenciosamente, esto es, no va a marcar error, pero tampoco
generará señal alguna.
bufnum
- el número de buffer del sample
rate
- la velocidad a la que será reproducido el sample:
1.0 - velocidad normal
0.5 - mitad de velocidad, por lo que el
sample sonará una octava abajo
2.0 - doble de velocidad (una octava
arriba)
-1.0 - el sample será leído al
revés, con la velocidad normal
Si nuestro archivo de audio tiene una velocidad de sampleo distinta a
44100, para que la velocidad de reproducción sea la correcta
tendremos que utilizar el UGen BufRateScale.
trigger
- cuando recibe una señal que cambie de 0.0, o menos que 0.0, a
mayor que 0.0, PlayBuf brinca a la startPos
startPos
- el número de cuadro en donde se iniciará la
reproducción del sample. Cada segundo tienen 44100 cuadros
(también conocidos como samples).
loop
- si ponemos 1, cada vez que PlayBuf llegue al final del sample
regresará al principio. Si ponemos 0, cuando llegue al final del
sample se detendrá.
Primero cargamos un archivo de audio en la memoria:
b = Buffer.read(s,
"sounds/a11wlk01-44_1.aiff")
(
{
var numeroDeCanales, numeroDeBuffer;
numeroDeCanales =
b.numChannels; //al mandar el mensaje
//.numChannels al objeto que
//representa a nuestro buffer,
//éste nos responderá
//el número de canales del
//archivo de audio que cargamos
//en la memoria
numeroDeBuffer =
b.bufnum;
//con el mensaje .bufnum, pedimos
//el número de buffer en donde se
//encuentra el archivo de audio
PlayBuf.ar(numeroDeCanales, numeroDeBuffer)
}.scope
)
//Evalúa las siguientes líneas:
b.bufnum
b.numChannels
Si quisiéramos ver toda la información del buffer,
mandamos el mensaje .query:
b.query
Para que PlayBuf toque nuestro archivo de audio en loop, hay que
asignar el valor 1 al argumento loop:
(
{
var numeroDeCanales, numeroDeBuffer;
numeroDeCanales =
b.numChannels;
numeroDeBuffer = b.bufnum;
PlayBuf.ar(numeroDeCanales, numeroDeBuffer, loop: 1)
}.scope
)
Si queremos tocar nuestro archivo de audio a la mitad de velocidad, hay
que poner 0.5 en el argumento rate:
(
{
var numeroDeCanales, numeroDeBuffer, velocidad;
numeroDeCanales =
b.numChannels;
numeroDeBuffer =
b.bufnum;
velocidad = 0.5;
PlayBuf.ar(numeroDeCanales, numeroDeBuffer, velocidad, loop: 1)
}.scope
)
Si queremos reproducir el sample al revés, a velocidad normal,
ponemos -1.0 en el argumento rate:
(
{
var numeroDeCanales, numeroDeBuffer, velocidad;
numeroDeCanales =
b.numChannels;
numeroDeBuffer =
b.bufnum;
velocidad = -1.0;
PlayBuf.ar(numeroDeCanales, numeroDeBuffer, velocidad, loop: 1)
}.scope
)
Ahora vamos a controlar la velocidad con el mouse:
(
{
var numeroDeCanales, numeroDeBuffer, velocidad;
numeroDeCanales =
b.numChannels;
numeroDeBuffer =
b.bufnum;
velocidad =
MouseX.kr(0.125, 2.0);
PlayBuf.ar(numeroDeCanales, numeroDeBuffer, velocidad, loop: 1)
}.scope
)
Vamos a utilizar un Impulse.kr como trigger para el argumento que lleva
el mismo nombre. Cada vez que PlayBuf reciba un trigger, va a regresar
al número de cuadro especificado en startPos, cuyo valor default
es 0 (el primer cuadro o sample del buffer).
(
{
var numeroDeCanales, numeroDeBuffer, velocidad, trigger;
numeroDeCanales =
b.numChannels;
numeroDeBuffer =
b.bufnum;
velocidad
= 1.0;
trigger
= Impulse.kr(MouseX.kr(0.7,4));
//vamos a mandar un trigger
//cada segundo.
PlayBuf.ar(numeroDeCanales, numeroDeBuffer, velocidad, trigger)
/* ya no va a ser necesario poner 1 en el argumento loop */
}.scope
)
Con el mensaje .query podemos saber el número de cuadros o
samples de nuestro archivo de audio:
b.query
Entre los datos que fueron desplegados en la Post Window vemos:
numFrames : 107520
Este es el número de cuadros de nuestro archivo.
Ahora vamos a hacer que cada vez que PlayBuf reciba un trigger,
éste brinque a la mitad del buffer y no al principio de
éste:
(
{
var numeroDeCanales, numeroDeBuffer, velocidad, trigger,
posicionInicial;
numeroDeCanales
=
b.numChannels;
numeroDeBuffer
= b.bufnum;
velocidad
= 1.0;
trigger
= Impulse.kr(1);
posicionInicial =
107520/2; // vamos a dividir el
// el número total de
// cuadros entre dos,
// para obtener el
// número de cuadro que
// se encuentra a la
// mitad del buffer
PlayBuf.ar(numeroDeCanales, numeroDeBuffer, velocidad,
trigger,
posicionInicial)
}.scope
)
En el ejemplo anterior escuchamos un click cada vez que el audio
regresa a la mitad del buffer. Esto es causado por las diferencia entre
la amplitud del audio antes de recibir el trigger y la amplitud
después del trigger, después de que PlayBuf brincó
a la mitad del archivo.
Para quitar el click tenemos que poner un envolvente a la señal,
que inicie con una amplitud de cero y que regrese a cero justo
antes de que el trigger cambié la posición del buffer.
2.reciprocal
(
{
var numeroDeCanales, numeroDeBuffer, velocidad, trigger,
posicionInicial, sig, env, duracionEnSegundos,frecuenciadeltrigger;
numeroDeCanales
=
b.numChannels;
numeroDeBuffer
= b.bufnum;
velocidad
= 1.0;
frecuenciadeltrigger = 10;
trigger
= Impulse.kr(frecuenciadeltrigger);
posicionInicial
= 107520/2;
duracionEnSegundos =
1/frecuenciadeltrigger;
/* como regresamos a la startPos antes de que PlayBuf
haya
llegado al final del archivo, nuestro envolvente deberá
durar el tiempo en segundos que haya entre dos triggers */
sig = PlayBuf.ar(numeroDeCanales,
numeroDeBuffer, velocidad,
trigger, posicionInicial);
env = EnvGen.kr(Env([ 0.0, 1.0, 1.0, 0.0 ],
duracionEnSegundos * [ 0.025, 0.95,0.025
]),
trigger);
/* también vamos a utilizar al trigger
del PlayBuf,
como trigger para el argumento gate del EnvGen. EnvGen
generará un envolvente cada vez que reciba un trigger
*/
sig * env
}.scope
)
BufFrames.kr
Este UGen calcula el número de cuadros de un buffer y con
él es más fácil calcular la posición incial
(startPos) de PlayBuf.
BufFrames.kr(bufnum)
bufnum - el número del
buffer
Este UGen no nos va a dar directamente el número de cuadros de
un buffer, sino que se lo comunicará a otros UGens.
Si quisieramos utilizarlo para que PlayBuf regrese al primer tercio del
archivo de audio, tendremos que poner lo siguiente en el argumento
startPos:
BufFrames.kr(bufnum) * (1/3)
(
{
var numeroDeCanales, numeroDeBuffer, velocidad, trigger,
posicionInicial, sig, env, duracionEnSegundos;
numeroDeCanales
=
b.numChannels;
numeroDeBuffer
= b.bufnum;
velocidad
= 1;
trigger
= Impulse.kr(MouseY.kr(30,0.5));
posicionInicial
= BufFrames.kr(numeroDeBuffer) * MouseX.kr(0,0.9999);
duracionEnSegundos = 1;
sig = PlayBuf.ar(numeroDeCanales,
numeroDeBuffer, velocidad,
trigger, posicionInicial);
env =
EnvGen.kr(Env( [ 0.0, 1.0, 1.0, 0.0 ],
duracionEnSegundos * [ 0.05, 0.9, 0.05
]),
trigger);
sig * env
}.scope
)
Ahora vamos a utilizar el mouse para cambiar la posición inicial
del archivo de audio y la velocidad de reproducción:
(
{
var trigger, sig, env, frecuencia = 6;
trigger = Impulse.kr(frecuencia);
sig = PlayBuf.ar(
b.numChannels,
b.bufnum,
MouseY.kr(-1.0, 1.0),
trigger,
MouseX.kr(0, BufFrames.kr(b.bufnum))
);
env
= EnvGen.kr(Env( [ 0.0, 1.0, 1.0, 0.0 ],
frecuencia.reciprocal * [ 0.05, 0.9, 0.05
]),
trigger);
sig * env
}.scope
)
///////////////////////////////////////////////////
Ahora con un SynthDef
a=Buffer.read(s,"sounds/a11wlk01-44_1.aiff")
a.numFrames
(
SynthDef(\sample,{|frecuencia=1,posc=0,trigger=1,rate=1|
var sen,env;
sen=PlayBuf.ar(1,a.bufnum,rate,Impulse.kr(frecuencia),posc);
sen=sen*SinOsc.ar(MouseY.kr(20,1));
sen=Pan2.ar(sen,LFNoise2.kr(10),0.9);
env=EnvGen.kr(Env([ 0.0, 1.0, 1.0, 0.0 ],
frecuencia.reciprocal * [ 0.05, 0.9, 0.05
]),
trigger,doneAction:2);
Out.ar(0,sen*env)
}).send(s)
)
Synth(\sample)
s.scope
(
Tdef(\hu,{var suma=0;
inf.do{suma=suma+1;
Synth(\sample,[\frecuencia,rrand(2,5),\posc,rrand(0,107520),
\rate,(suma%2+0.5)*1.2]);
0.2.wait
}}
)
)
Tdef(\hu).quant_(0).play
Tdef(\hu).stop
.
(
Tdef(\hu,{var suma=0;
inf.do{suma=suma+1;
Synth(\sample,[\frecuencia,0.1,\posc,suma%50*10,
\rate, (suma%10 -5)*0.5 ]);
0.5.wait
}}
)
)
(
Tdef(\hu,{var suma=0;
inf.do{suma=suma+1;
Synth(\sample,[\frecuencia,(suma%7+0.3)*1.3,\posc,suma%50*14,
\rate,1.3 ]);
0.25.wait
}}
)
)
s.quit; //apagamos el servidor