Quando te tornares suficientemente avançado em live coding com uma serie de funções e threads simultaneamente, irás notar que é bastante fácil fazer em erro num dos threads e o matar. Isso não é muito importante porque o podes reiniciar carregando no Run. No entanto, quando reinicias o thread ele está fora de tempo com os threads originais.
Como discutimos anteriormente, novos threads criados com in_thread
herdam todas as definições do thread pai. Isto inclui o tempo corrente. Isto significa que os threads estarão sempre sincronizados uns com os outros quando começarem simultaneamente.
No entanto, quando começas um thread por si só, o seu tempo é improvável estar sincronizado com qualquer dos outros threads em execução.
O Sonic Pi oferece uma solução para este problema com as funções cue
e sync
.
cue
permite-nos enviar uma mensagem de “batimento cardiaco” para todos os outros threads. Por padrão os outro threads não estão interessados na mensagem. No entanto, podes registar interesse com a função sync
.
A coisa importante a saber é que sync
é similar a sleep
na medida que pára o thread corrente de fazer alguma coisa por um período de tempo. No entanto, com sleep
especificas o tempo de espera enquanto com sync
não sabes quanto tempo tens de esperar - uma vez que sync
espera pelo próximo cue
de outro thread que pode ser logo ou após um longo tempo.
Vamos explorar isto em mais detalhe:
in_thread do
loop do
cue :tick
sleep 1
end
end
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Aqui temos 2 threads - um actuando como um metronomo, não tocando nenhum som mas enviando a mensagem de batimento:tick
a cada beat. O segundo thread está sincronizado na mensagem tick
e quando recebe um herda o tempo do thread do cue
e continua a correr.
Como resultado, ouviremos o sample :drum_heavy_kick
exactamente quando o outro thread envia a mensagem :tick
, mesmo que o dois threads não começaram o seu tempo de execução ao mesmo tempo:
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
A chamada maldosa sleep
tipicamente faria o segundo thread fora de fase com o primeiro. No entanto, como estamos a usar cue
e sync
, automaticamente sincronizamos os threads evitando qualquer offset de tempo acidental.
És livre de usar qualquer nome que queiras para as tuas mensagens de cue
- não apenas :tick
. Só tens que assegurar que tal como os outros threads estão sync
ronizados no nome correcto - ou então ficarão à espera para sempre (ou até carregares no botão Stop).
Vamos jogar com alguns nomes de cues
:
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
Aqui temos um cue
loop principal que está aleatoriamente a enviar um batimento chamado :foo
,:bar
ou :baz
. Temos também 3 loop threads sincronizando a cada um desses nomes independentemente e tocando um sample diferente. O efeito total é que ouvimos um som cada 0.5 batida porque cada sync
thread é aleatoriamente sincronizado com a thread cue
e toca o seu sample.
Isto claro que também funciona se inverteres a ordem dos threads pois eles os threads sync
simplesmente esperam pela próxima cue
.