Cuando estés lo suficientemente avanzado en live-coding con un número de funciones e hilos simultáneamente, notarás que es muy fácil cometer un error en uno de los hilos y eso lo mata. Eso no es gran cosa, porque puedes fácilmente recomenzar el hilo con apretar Run. Sin embargo, cuando recomiences el hilo estará out of time con los hilos actuales.
Como discutíamos anteriormente, nuevos hilos creados con in_thread
heredan todos los seteos del hilo padre. Esto incluye el tiempo actual, lo que significa que los hilos estarán siempre en el tiempo con los demás cuando comenzados simultáneamente.
Sin embargo, cuando comienzas un hilo aparte, comienza con su propio tiempo que difícilmente estará sincronizado con alguno de los otros que estén siendo corridos.
Sonic Pi provee una solución a este problema con las funciones cue
y sync
.
cue
permite enviar mensajes de pulso a todos los otros hilos, los cuales, en principio no están interesados e ignoran estos mensajes. Sin embargo. puedes registrar fácilmente su interés con la función sync
.
Lo importante de notar es que sync
es similar a sleep
en que para el hilo actual por un tiempo. Sin embargo, con sleep
tu especificas cuánto tiempo va a esperar, en cambio con sync
no sabes cuánto tiempo esperará - ya que sync
espera por el siguiente cue
de otro hilo.
Exploremos esto en más detalle:
in_thread do
loop do
cue :tick
sleep 1
end
end
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Aquí tenemos dos hilos - uno actuando como un metrónomo, no haciendo sonidos sino que enviando :tick
mensajes de pulso. El segundo hilo está sincronizandose con los mensajes de tick
y cuando recibe uno, hereda el tiempo del hilo de cue
y continúa tocando.
El resultado es que escuchamos el sample de :drum_heavy_kick
exactamente cuando el otro hilo envía el mensaje :tick
, aunque ambos hilos no comenzaron su ejecución al mismo tiempo:
in_thread do
loop do
cue :tick
sleep 1
end
end
sleep(0.3)
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Esa llamada sleep
típicamente haría que el segundo hilo vaya fuera de fase con el primero. Sin embargo, por estar usando cue
y sync
, sincronizamos ambos hilos automáticamente.
Eres libre de utilizar cualquier nombre que quieras a los mensajes de cue
- no sólo :tick
. Sólo debes asegurarte que los otros hilos estén sync
sincronizándose en el nombre correctoe - de otro modo se quedarán esperando por siempre (o hasta presionar el botón de Parar)
Juguemos con unos cuantos nombres para cue
:
in_thread do
loop do
cue [:foo, :bar, :baz].choose
sleep 0.5
end
end
in_thread do
loop do
sync :foo
sample :elec_beep
end
end
in_thread do
loop do
sync :bar
sample :elec_flip
end
end
in_thread do
loop do
sync :baz
sample :elec_blup
end
end
Aquí tenemos un cue
principal bucleado, el cual envía aleatoriamente uno de los nombres de pulso :foo
, :bar
o :baz
. Después tenemos también tres bucles de hilos sincronizándose entre ellos independientemente y tocando un sampleo diferente. El efecto es que escuchamos un sonido cada 0.5 pulsos que cada uno de los hilos está aleatoriamente sincronizándose sync
con el hilo de cue
y toca su sampleo.
Por supuesto que esto también funciona si ordenas los hilos en reversa, ya que los hilos sync
siempre esperarán al siguiente cue
.