Cómo Crear un Secuenciador Rítmico en Sonic Pi con una sola línea de código (Patrón por Anillos)

Si alguna vez has intentado armar ritmos en Sonic Pi usando la forma tradicional, probablemente terminaste con bloques gigantescos de código llenos de sample, sleep y condicionales repetitivas.

Existe una forma mucho más limpia, elegante y expresiva de programar secuencias rítmicas inspirada en el paradigma funcional: convirtiendo texto plano en anillos circulares (rings).

Hoy vamos a destripar paso a paso este patrón para que puedas incorporarlo a tus sesiones de Live Coding o a tus proyectos.

Pruébalo tú mismo (Copia y Pega)

Abre Sonic Pi, pega el siguiente fragmento en un Workspace limpio y dale a Run:

Ruby

# ======================================================
# SECUENCIADOR RÍTMICO POR ANILLOS EN SONIC PI
# Copia este código, pégalo en un Workspace y dale a RUN
# ======================================================

use_bpm 120 # Establecemos el tempo base

live_loop :fast_pattern do
  # 1. Convertimos la cadena de texto en un anillo (.ring)
  # 2. Avanzamos un paso en la secuencia con cada repetición (.tick)
  pat = "xdxx-dxdx".ring.tick

  # Mapa de ejecución según el carácter activo:
  # "x" = Golpe principal fuerte
  sample :drum_snare_hard, rate: 1.0, amp: 0.8 if pat == "x"

  # "d" = Golpe secundario o 'ghost note' (pitch agudo y más suave)
  sample :drum_snare_hard, rate: 1.4, amp: 0.25 if pat == "d"

  # "-" = Silencio (ningún 'if' coincide, solo espera el sleep)
  sleep 0.25 # Semicorchea
end

Destripando el Código Paso a Paso

¿Por qué funciona esto y por qué es tan poderoso? Vamos a analizar qué ocurre en cada línea como si estuviéramos mirando bajo el capó de la máquina.

1. El lienzo rítmico: "xdxx-dxdx"

En lugar de definir listas complejas, representamos el ritmo como una cadena de texto (String) donde cada carácter es un paso de tiempo (step):

  • x representa un golpe principal (fuerte y con carácter).
  • d representa una ghost note (golpe secundario, suave y con un tono diferente).
  • - representa un silencio (un descanso en el tiempo).

Esta representación visual te permite "ver" el groove antes de escucharlo.

2. La magia del .ring

Ruby

pat = "xdxx-dxdx".ring

En Ruby puro, un String es una secuencia de texto lineal con principio y fin. Pero al aplicarle el método .ring nativo de Sonic Pi, convertimos la cadena en una estructura de datos circular (un anillo).

Esto significa que no hay un "final". Cuando llegas al último carácter (x), la secuencia vuelve automáticamente al inicio sin arrojar errores ni detener la ejecución.

3. El reloj interno: .tick

Ruby

pat = "xdxx-dxdx".ring.tick

El método .tick es una de las funciones más brillantes de Sonic Pi. Cada live_loop mantiene su propio contador interno que se incrementa automáticamente en 1 cada vez que el bucle vuelve a girar:

Repetición del LoopValor de .tickÍndice en el RingCarácter evaluado en pat
Vuelta 100"x"
Vuelta 211"d"
Vuelta 322"x"
............
Vuelta 988"x" (último carácter)
Vuelta 1090"x" (¡vuelve al inicio!)

El contador avanza solo, toma el carácter correspondiente a ese milisegundo de tiempo y lo almacena en la variable pat.

4. Mapeo de Expresividad (if pat == ...)

Ruby

sample :drum_snare_hard, rate: 1.0, amp: 0.8 if pat == "x"
sample :drum_snare_hard, rate: 1.4, amp: 0.25 if pat == "d"

Usando la sintaxis if al final de la instrucción en Ruby, condicionamos el sonido:

  • Si pat contiene "x", dispara la caja con volumen alto (amp: 0.8) y afinación normal (rate: 1.0).
  • Si pat contiene "d", dispara el mismo instrumento pero más rápido y agudo (rate: 1.4) y con volumen tenue (amp: 0.25), emulando la técnica de redoble o nota fantasma que usan los bateristas reales.
  • Si pat contiene "-", ninguna de las dos condiciones se cumple, por lo que no suena ningún sample.

5. El pulso constante: sleep 0.25

Ruby

sleep 0.25

Esta línea marca la velocidad de cada paso. Un valor de 0.25 equivale a una semicorchea (dividir cada compás de 4 tiempos en 16 pasos).

Como la instrucción sleep está al final del bucle (fuera de los if), el tiempo avanza exactamente a la misma velocidad independientemente de si el paso actual tuvo sonido o silencio.

¿Por qué deberías usar este patrón?

  1. Perfecto para Live Coding: Puedes cambiar el ritmo entero en vivo simplemente modificando las letras dentro del texto ("x-d-xdxx") y presionando Run. No tienes que rehacer la lógica del sintetizador.
  2. Textura y Orgánica: Al usar diferentes letras (x, d) para el mismo sonido pero con matices de velocidad (rate) y volumen (amp), le quitas la rigidez robótica al secuenciador.
  3. Escalable: Puedes crear múltiples live_loop en paralelo (uno para el bombo, otro para el hi-hat y otro para la caja), cada uno controlando su propio anillo de texto a la perfección.