Une fois que vous êtes suffisamment avancés en codage “live” avec un certain nombre de fonctions et de threads en simultanéité, vous avez probablement remarqué que c’est plutôt facile de faire une faute dans l’un des threads et qui lui met fin. Ce n’est pas un gros problème car vous pouvez facilement redémarrer le thread en pressant Run. Toutefois, quand vous redémarrez le thread, il se trouve alors déphasé avec les threads d’origine.
Comme nous en avons discuté auparavant, les nouveaux threads créés
avec in_thread
héritent de tous les paramètres du thread parent.
Ceci inclut l’heure actuelle. Ce qui signifie que les threads sont
toujours en phase entre eux quand ils sont démarrés simultanément.
Toutefois quand vous démarrez un thread tout seul, il démarre avec sa propre heure qui n’est probablement pas en phase avec l’un quelconque des autres threads en cours d’exécution.
Sonic Pi fourni une solution à ce problème avec les fonctions cue
et
sync
.
cue
nous permet d’envoyer nos messages de battement de coeur à tous
les autres threads. Par défaut, les autres threads ne sont pas
intéressés et ignorent ces messages de battement de coeur. Cependant,
vous pouvez leur déclarer de l’intérêt avec la fonction sync
.
La chose importante à laquelle il faut être attentif est similaire à
sleep
, en ce sens que cela arrête le thread courant en l’empêchant de
faire quoi que ce soit pendant un moment. Toutefois, avec sleep
, vous
spécifiez combien de temps vous voulez attendre tandis qu’avec sync
,
vous ne savez pas combien de temps vous allez attendre - étant donné
que sync
attend le cue
suivant d’un autre thread, ce qui peut être
court ou long.
Explorons ceci en un peu plus de détail :
in_thread do
loop do
cue :tick
sleep 1
end
end
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Nous avons ici deux threads - l’un agissant comme un métronome, ne
jouant aucun son mais envoyant des messages de battement de coeur
tick
à chaque temps. Le second thread se synchronise sur les messages
tick
et quand il en reçoit un, il hérite de l’heure du thread cue
et continue de jouer.
Par conséquent, nous entendons l’échantillon :drum_heavy_kick
exactement quand l’autre thread envoie le message tick
, même si les
deux threads n’ont pas démarré leur exécution en même temps :
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
Ce vilain appel à sleep
mettrait typiquement le second thread en
déphasage avec le premier. Cependant, comme nous utilisons cue
et
sync
, nous synchronisons automatiquement les threads en évitant un
décalage de temps accidentel.
Vous êtes libre d’utiliser n’importe quel nom que vous aimeriez pour
vos messages cue
. Vous devez juste vous assurer que tout autre thread
se synchronise sur le bon nom - autrement il attendrait à jamais (au
moins jusqu’à ce que vous pressiez le bouton Stop).
Jouons avec quelques noms de 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
Ici, nous avons une boucle principale cue
qui envoie aléatoirement un
des battements de coeur nommés :foo
, :bar
ou :baz
. Nous avons
aussi ensuite trois boucles en thread se synchronisant sur ces noms
indépendamment et jouant un échantillon différent. Il est clair
que nous entendons un son à chaque demi-temps puisque chacun des
threads sync
est aléatoirement synchronisé avec le thread cue
et
joue son échantillon.
Ceci, bien entendu, marche aussi si vous ordonnez les threads en sens
inverse puisque les threads sync
restent en attente du cue
suivant.