Hilos

Así que hiciste una gran línea de bajo y un gran pulso. ¿cómo los tocas al mismo tiempo? Una manera de hacerlo es coserlos juntos manualmente - toca bajo, después un poco de batería y así… Sin embargo, cada vez se vuelve más complicado mantener el timing, especialmente Si’coses’ más y más elementos.

¿qué tal si Sonic Pi pudiese coser todo automáticamente para tí? Bueno, puede y lo hace con algo especial llamado thread.

Bucles infinitos

Para mantener este ejemplo sencillo, vas a tener que imaginar que es un gran pulso y bajo:

loop do
  sample :drum_heavy_kick
  sleep 1
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end

Como vimos anteriormente, bucles son como ‘hoyos negros’ para el programa, una vez entras a uno, sólo puedes salir de él con el botón ‘stop’. Así que para tocar ambos bucles al mismo tiempo, debemos indicarle a Sonic Pi que queremos comenzar algo al mismo tiempo que el resto del código, aquí es cuando los hilos vienen al rescate.

Hilos al rescate

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end

Al envolver el primer bucle de bloque do/end con in_thread le decimos a Sonic Pi que corra los contenidos del bloque do/end exactamente al mismo tiempo que el siguiente bloque do/end (que es nuestro segundo bucle) ¿Inténtalo y escucharás ambos, el bajo y la batería conectados!

Ahora, si quisiésemos añadir un sintetizador, haríamos algo así:

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end
loop do
  use_synth :zawa
  play 52, release: 2.5, phase: 2, amp: 0.5
  sleep 2
end

Ahora volvemos a tener el mismo problema que antes, ya que los primeros dos bucles se tocan al mismo tiempo, gracias a in_thread. Sin embargo, el tercer bucle nunca se alcanza. Por lo tanto, necesitamos otro hilo:

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
in_thread do
  loop do
    use_synth :fm
    play 40, release: 0.2
    sleep 0.5
  end
end
loop do
  use_synth :zawa
  play 52, release: 2.5, phase: 2, amp: 0.5
  sleep 2
end

Ejecutar como hilos

Puede sorprenderte que cuando aprietas el botón de Correr (Run), de hecho estás creando un nuevo hilo para que corra el código. Esta es la razón por la que al apretar el botón múltiples veces, suenan las capas de sonido una encima de la otra, ya que las corridas son de hecho hilos cosidos automáticamente para sonar.

Ámbito

En cuanto más aprendas Sonic Pi, apreciarás que los hilos son los bloques de construcción más importantes para tú música. Uno de los trabajos más importantes que realiza es aislar la noción de seteos actuales respecto a otros hilos. ¿qué significa eso? Bien, cuando cambias sintetizadores por medio de use_synth realmente estás cambiando el sintetizdor en el hilo actual, ya que ningún otro hilo cambiarás su sintetizador. Veamos esto en acción:

play 50
sleep 1
in_thread do
  use_synth :tb303
  play 50
end
sleep 1
play 50

¿Notaste que el sonido de en medio era diferente a los otros? el use_synth solamente afectó el hilo en el que se encontraba, no así el hilo externo principal.

Herencia

Cuando creas un nuevo hilo con in_thread, este automáticamente hereda la configuración del hilo actual. Veamos:

use_synth :tb303
play 50
sleep 1
in_thread do
  play 55
end

¿Notaste que la segunda nota es tocada por el sintetizador :tb303 aunque era de un hilo separado? Cualquier seteo modificado con las funciones use_* se comportará de igual manera.

Cuando se crean hilos, ellos heredan todos los seteos de su padre, pero no los comparten a su vez.

Nombres para los Hilos

Por último, podemos darles nombre a los hilos:

in_thread(name: :bass) do
  loop do
    use_synth :prophet
    play chord(:e2, :m7).choose, release: 0.6
    sleep 0.5
  end
end
in_thread(name: :drums) do
  loop do
    sample :elec_snare
    sleep 1
  end
end

Mira el panel de bitácora cuando corras este código. ¿ves que reporta el nombre del hilo?

[Run 36, Time 4.0, Thread :bass]
 |- synth :prophet, {release: 0.6, note: 47}

Sólo es permitido un nombre por hilo

Una cosa más al respecto de nombrar hilos es que sólo un hilo con su nombre puede estar corriendo a la vez. Exploremos esto, considerando el código:

in_thread do
  loop do
    sample :loop_amen
    sleep sample_duration :loop_amen
  end
end

Pega eso en un buffer y córrelo. Presiona Correr un par de veces. Escucha la cacofonía de los múltiples amen breaks bucleando desincronizadamente. Ok, ya puedes pararlo.

Esta es la conducta que hemos visto innumerables veces - si presionas el botón Correr, capas de sonidos suenan encima de otras. Así que si tienes un loop y presionas el botón Correr tres veces, obtendrás tres capas de bucles sonando simultáneamente.

sin embargo, con hilos nombrados, es diferente:

in_thread(name: :amen) do
  loop do
    sample :loop_amen
    sleep sample_duration :loop_amen
  end
end

Intenta presionando el botón Correr múltiples veces con este código. Sólo escucharás un bucle del amen break. También verás lo siguiente en la bitácora:

==> Omitiendo creación de hilo: ya existe un hilo con el nombre :amen.

Sonic Pi te está diciendo que un hilo con el nombre :amen ya existe, así que no creará otro.

Esta conducta puede no aparentar utilidad para tí - pero verás que la tiene cuando comencemos a hacer Código-vivo…