SuperCollider

8 clase

s = 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