// supercollider · live coding · reloj de servidor
Sesión 02 · Sistema de live coding rítmico
Laboratorio de Síntesis con SC
La serie entra en tiempo, secuencia y arquitectura de servidor
Tras el estudio tímbrico inicial, esta segunda sesión desplaza el foco hacia la estabilidad rítmica: relojes en scsynth, rejillas binarias y ruteo modular listos para directo.
Esta segunda sesión de nuestro laboratorio se enfoca en resolver uno de los mayores retos de la música por ordenador en directo: la sincronización libre de fluctuaciones (jitter). Para lograrlo, construimos un motor rítmico modular donde la temporización, el secuenciamiento por rejilla binaria y el ruteo de envíos de efectos ocurren **íntegramente dentro del servidor de audio (scsynth)**, permitiendo improvisaciones rítmicas robustas mediante ProxySpace.
01. El Motor de Tiempo (BPM y Reloj del Servidor)
La música rítmica por ordenador en tiempo real exige una estabilidad de reloj implacable. En SuperCollider, si programamos los disparos de los sintetizadores desde el cliente (sclang), la precisión temporal se ve afectada por el hilo del sistema operativo y los procesos internos del intérprete.
Para solucionar esto, creamos un reloj de tasa de control (kr) a través del UGen Impulse dentro de un NodeProxy maestro. De esta manera, el servidor se encarga de emitir impulsos en sincronía absoluta. A partir de ese reloj, implementamos un contador global que incrementa en cada tic para dictar el paso actual en nuestra rejilla temporal.
El "Gotcha" de la Sincronización Dinámica:
Las funciones en ProxySpace se compilan solo al ejecutarse. Si mapeamos operaciones fijas como t.tempo * 4 directamente en el sintetizador, se congelará un valor estático. Al usar un proxy dedicado como ~bpm de control, el servidor lee de forma continua su bus y reacciona de inmediato ante cualquier aceleración o frenado dinámico.
Diagrama del Sistema de Reloj
Código: El Reloj Maestro en ProxySpace
// 1) Declaramos la velocidad base en BPM en un proxy independiente
~bpm = { 100 };
// 2) Reloj maestro de control: calcula los Hz dinámicamente.
// Multiplicamos por 4 para obtener subdivisiones a Semicorcheas (16th notes)
~clkMaster = {
var hz = (~bpm.kr / 60) * 4;
Impulse.kr(hz);
};
// 3) Contador global de pasos (secuenciador de compases)
// Restamos 1 para que el primer tick del PulseCount corresponda al paso 0
~cnt16 = {
PulseCount.kr(~clkMaster.kr.first) - 1;
};
02. Las Fuentes de Sonido (Batería y Rejilla)
Para hacer que la secuenciación rítmica en directo sea ágil, implementamos un sistema de Rejilla Virtual (Grid). En lugar de recompilar la síntesis para cambiar el ritmo de una batería, exponemos un array binario de control (\pat.kr) con 16 pasos.
El UGen Select utiliza el paso del contador maestro (~cnt16 % 16) como índice de búsqueda en el array, decidiendo en nanosegundos si el pulso de reloj debe disparar la señal del generador de envolventes de cada instrumento.
Síntesis Especial: El Aplauso Analógico (Clap)
A diferencia de un bombo o hi-hat, el clap analógico clásico no es un simple impacto. Se emula encadenando tres disparos extremadamente rápidos de ataque (10ms cada uno) que representan micro-variaciones temporales de varias personas aplaudiendo juntas, seguidos de una cola de caída más larga de ruido.
Código: Instrumentos Secuenciados en el Servidor
// --- BD (Bombo / Bass Drum) ---
~bd = {
var sig, envAmp, envFreq, clk, cnt, pat, gat;
clk = ~clkMaster.kr.first;
cnt = ~cnt16.kr.first;
// Array de control que actúa como rejilla del secuenciador (1 = golpe)
pat = \pat.kr([1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0]);
gat = clk * Select.kr(cnt % 16, pat);
envAmp = EnvGen.kr(Env.perc(0.002, 0.3, curve: -4), gat);
envFreq = EnvGen.kr(Env.perc(0.001, 0.05, curve: -8), gat);
sig = SinOsc.ar(envFreq * 120 + 48, 0.5pi) * envAmp;
sig = sig.distort * 0.6; // Presencia armónica
sig ! 2;
};
// --- SNARE (Caja / Redoblante) ---
~snare = {
var sig, noise, tone, envAmp, envTone, clk, cnt, pat, gat;
clk = ~clkMaster.kr.first;
cnt = ~cnt16.kr.first;
pat = \pat.kr([0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0]);
gat = clk * Select.kr(cnt % 16, pat);
envAmp = EnvGen.kr(Env.perc(0.005, 0.18), gat);
envTone = EnvGen.kr(Env.perc(0.002, 0.06), gat);
noise = HPF.ar(WhiteNoise.ar, 1200) * envAmp * 0.5;
tone = SinOsc.ar(envTone * 180 + 160) * envAmp * 0.4;
sig = noise + tone;
sig ! 2;
};
// --- HH (Hi-hat Cerrado) ---
~hh = {
var sig, env, clk, cnt, pat, gat;
clk = ~clkMaster.kr.first;
cnt = ~cnt16.kr.first;
pat = \pat.kr([0,0,1,0, 0,0,1,0, 0,1,0,0, 0,0,1,0]);
gat = clk * Select.kr(cnt % 16, pat);
env = EnvGen.kr(Env.perc(0.002, 0.05, curve: -4), gat);
sig = BPF.ar(WhiteNoise.ar, 10000, 0.3) * env * 0.25;
sig ! 2;
};
// --- CLAP (Aplauso Analógico) ---
~clap = {
var sig, env, clk, cnt, pat, gat;
clk = ~clkMaster.kr.first;
cnt = ~cnt16.kr.first;
pat = \pat.kr([0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1]);
gat = clk * Select.kr(cnt % 16, pat);
// 3 pre-disparos rápidos + caída final
env = EnvGen.kr(
Env([0, 1, 0.1, 1, 0.1, 1, 0], [0.01, 0.005, 0.01, 0.005, 0.01, 0.12], -4),
gat
);
sig = BPF.ar(WhiteNoise.ar, 1100, 0.4) * env * 0.35;
sig ! 2;
};
03. El Mezclador General y Compresor
El proxy ~drums funciona como el sumador final o consola master de la sección rítmica. Este canal recibe las señales directas de las cuatro fuentes, aplicando una perilla de volumen a cada canal mediante controles kr dedicados (\bdVol.kr, etc.).
Para cohesionar la mezcla y darle una pegada comercial adecuada a los sistemas de sonido de clubes, pasamos la suma total por un limitador estricto (Limiter). Este proceso empasta los transitorios y eleva el nivel de presión sonora percibido, impidiendo cualquier posible distorsión digital o pico peligroso en los DAC físicos.
Código: Mezcla Final y Limitación
~drums = {
// Suma de señales directas multiplicadas por sus perillas de ganancia
var bd = ~bd.ar * \bdVol.kr(0.8);
var sn = ~snare.ar * \snVol.kr(0.7);
var hh = ~hh.ar * \hhVol.kr(0.6);
var cp = ~clap.ar * \cpVol.kr(0.7);
var mix = bd + sn + hh + cp;
// Limitación de salida para empastar la mezcla rítmica
Limiter.ar(mix * 1.2, 0.95);
};
// Iniciamos la reproducción del bus maestro de batería
~drums.play;
04. Envíos Auxiliares y Procesadores de Efectos
El verdadero dinamismo y la espacialidad en vivo se logran mediante el uso de canales de envío auxiliares paralelos. Creamos dos procesadores de efectos globales e independientes en el entorno: `~verb` y `~delay`.
Cada sintetizador se conecta a estos procesadores mediante perillas de envío independientes (por ejemplo, \snSend.kr(0.0)). De este modo, podemos inundar la sala enviando la caja a la reverb de catedral mientras mantenemos el bombo completamente seco para no emborronar los graves del sistema.
Sincronización Mágica de Delay:
El tiempo del delay en segundos se calcula dinámicamente escuchando en vivo a ~bpm.kr. Al emplear el UGen CombC (delay con interpolación), cualquier cambio dinámico del tempo estirará o encogerá la línea física de retardo suavemente, emulando la clásica modulación orgánica de los retardos analógicos de cinta.
Diagrama del Sistema de Ruteo Auxiliar
Código: Efectos Auxiliares
// --- BUS DE REVERB (~verb) ---
~verb = {
var bd = ~bd.ar(2) * \bdSend.kr(0.0);
var sn = ~snare.ar(2) * \snSend.kr(0.0);
var hh = ~hh.ar(2) * \hhSend.kr(0.0);
var cp = ~clap.ar(2) * \cpSend.kr(0.0);
var input = bd + sn + hh + cp;
var wet = GVerb.ar(
input,
roomsize: \room.kr(200),
revtime: \time.kr(3.5),
taillevel: \tail.kr(0.4)
);
wet = LPF.ar(wet, \lpf.kr(1800));
wet * \masterVol.kr(0.4);
};
~verb.play;
// --- BUS DE DELAY TIEMPO-SINCRONIZADO (~delay) ---
~delay = {
var bd = ~bd.ar(2) * \bdSend.kr(0.0);
var sn = ~snare.ar(2) * \snSend.kr(0.0);
var hh = ~hh.ar(2) * \hhSend.kr(0.0);
var cp = ~clap.ar(2) * \cpSend.kr(0.0);
var input = bd + sn + hh + cp;
var beatDuration = 60 / ~bpm.kr.max(20);
var delayTime = beatDuration * \div.kr(0.375);
var wet = CombC.ar(
input,
maxdelaytime: 2.0,
delaytime: delayTime,
decaytime: \decay.kr(3.0)
);
wet = HPF.ar(wet, \hpf.kr(300));
wet * \masterVol.kr(0.5);
};
~delay.play;
05. Guía Rápida para el Control en Directo
Durante una sesión de live coding, la agilidad en la manipulación es clave. Este cheatsheet resume los comandos clave que te permitirán alterar radicalmente la estructura armónica, temporal o espacial del sistema sin apagar ni detener los sintetizadores centrales.
Gestión del Tempo
~bpm = { 140 };
Cambia el tempo general a 140 BPM de inmediato. El reloj maestro y los ecos del delay CombC se ajustan solos de forma coherente.~bpm = { 80 };
Ralentiza la sesión. Notarás un estiramiento orgánico con cambio de tono (pitch slide) en las repeticiones del delay.~bpm = { LFNoise1.kr(0.05).range(80, 165) };
Modulación caótica: el tema acelera y frena solo de forma fluida y continua.
Envíos Auxiliares (Sends)
~verb.set(\cpSend, 0.8, \snSend, 0.3);
Envía un volumen alto de clap y sutil de caja hacia la reverberación auxiliar.~delay.set(\hhSend, 0.4, \snSend, 0.35);
Inunda la sala enviando los hi-hats y la caja hacia la línea de delay sincronizado.~delay.set(\bdSend, 0.0);
Mantiene el bombo completamente seco para preservar la contundencia rítmica limpia.
Parámetros de Efectos
~delay.set(\div, 0.25);
Cambia la métrica del delay a semicorcheas rápidas e intensas (0.25 de un compás).~delay.set(\decay, 15);
Aumenta el feedback del delay llevándolo casi a auto-oscilación infinita (tensión).~verb.set(\room, 320, \time, 8);
Simula un espacio acústico masivo y profundo para momentos etéreos del set.