5.4 Threads

# Threads

("thread" = terme technique intraduisible et dont la traduction 
la plus proche est "fil")

Ainsi vous avez fait votre géniale ligne de basse et un super motif de 
batterie. Comment les jouez-vous en même temps ? Une solution est de 
les intercaler manuellement - joue quelques basses, puis quelques sons de 
batterie, puis encore des basses... Cependant, la synchronisation 
devient rapidement dure à concevoir, en particulier quand vous 
commencez à intercaler plus d'éléments.

Et si Sonic Pi pouvait vous synchroniser les choses automatiquement... 
Eh bien, il le peut, et vous le faites avec une chose spéciale appelée 
*thread*.

## Boucles infinies

Pour garder cet exemple simple, vous devez imaginer que ceci est un 
super motif de batterie et une géniale ligne de basse :

```
loop do
  sample :drum_heavy_kick
  sleep 1
end

loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end
```

Comme nous en avons parlé précédemment, les boucles sont comme des 
*trous noirs* pour un programme. Dès que vous êtes entré dans une 
boucle, vous ne pouvez jamais en sortir à moins de presser stop. 
Comment pouvons-nous jouer les deux boucles en même temps ? Nous devons 
dire à Sonic Pi que nous voulons démarrer quelque chose en même temps 
que le reste du code. C'est là que les threads arrivent à la rescousse.

## Threads à la rescousse

```
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
```

En encadrant la première boucle dans un bloc `in_thread` do/end, nous 
disons à Sonic Pi d'exécuter le contenu du bloc do/end *exactement* 
en même temps que l'ordre suivant le bloc do/end (qui se trouve être 
la seconde boucle). Essayez-le et vous entendrez à la fois la batterie 
et la ligne de basse synchronisées !

Maintenant, que faire si nous voulons ajouter un synthé par-dessus. 
quelque chose comme :

```
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
```

Maintenant, nous avons le même problème qu'avant. La première boucle 
est jouée en même temps que la seconde grâce au `in_thread`. 
Toutefois, *la troisième boucle n'est jamais atteinte*. Nous avons donc 
besoin d'un nouveau thread :

```
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
```

## Runs en tant que threads

Ce qui peut vous surprendre est que quand vous pressez le bouton Run, 
vous êtes réellement en train de créér un nouveau thread pour 
l'exécution du code. C'est pour cela qu'en le pressant de 
multiples fois, vous superposerez des couches de sons les unes sur les 
autres. Comme les "runs" sont eux-même des threads, ils intercaleront 
les sons automatiquement pour vous.

## Portée

Etudiant comment maîtriser Sonic Pi, vous apprendrez que les threads 
sont les composants les plus importants de votre musique. 
L'une des responsabilités importantes qu'ils ont est d'isoler la notion 
de *paramètres courants* vis à vis des autres threads. Qu'est-ce que 
cela signifie ? Eh bien, quand vous commutez les synthés avec `use_synth`, 
vous ne commutez réellement que le synthé dans le *thread courant* - 
aucun autre thread n'aura son synthé commuté. Voyons cela en action :

```
play 50
sleep 1

in_thread do
  use_synth :tb303
  play 50
end

sleep 1
play 50

```

Notez comme que le son du milieu était différent des autres. L'ordre 
`use_synth` affecte uniquement le thread dans lequel il était et pas le 
thread principal et extérieur du run.

## Héritage 

Quand vous créez un nouveau thread avec `in_thread`, le nouveau thread 
hérite automatiquement de tous les paramètres courants du thread 
courant. Voyons cela :

```
use_synth :tb303
play 50
sleep 1

in_thread do
  play 55
end
```

Notez que la seconde note est jouée avec le synthé `:tb303` bien 
qu'elle soit jouée depuis un thread distinct. L'un quelconque des 
paramètres modifiés avec les différentes fonctions `use_*` se 
comportera exactement de la même manière.

Quand les threads sont créés, ils héritent de tous les paramètres de 
leur parent mais dès lors, ils ne partagent plus aucun changement.

## Nommage des Threads

Finalement, nous pouvons donner des noms à nos threads :

```
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
```

Regardez le panneau "trace" quand vous exécutez ce code. Regardez comment 
le "trace" rapporte le nom du thread avec le message.

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

## Seulement un thread autorisé par nom

Une dernière chose à savoir au sujet des threads nommés est que 
seul un thread d'un nom donné peut être en cours d'exécution au 
même moment. Explorons ceci. Considérez le code suivant :

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

Allez de l'avant et collez cela dans un buffer et pressez le 
bouton "run". Pressez-le encore quelquefois. Ecoutez la cacaphonie des 
échantillons amen bouclant de façon désynchronisée. Ok, vous pouvez 
maintenant presser "stop".

C'est le comportement que nous avons vu encore et encore - si vous 
pressez le bouton "run", le son s'étend au dessus de tout son existant. 
Donc, si vous avez une boucle et que vous pressez le bouton "run" trois 
fois, vous aurez trois couches de boucles jouant simultanément. 

Cependant, avec les threads nommés, c'est différent :

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

Essayez de presser le bouton "run" plusieurs fois avec ce code. Vous 
entendrez seulement une boucle de l'échantillon amen. Vous allez aussi 
voir ceci dans la trace :

```
==> Skipping thread creation: thread with name :amen already exists.
   (sautant la création d'un thread : le thread avec le nom :amen existe déjà.)
```

Sonic Pi vous dit qu'un thread avec le nom `:amen` est déjà en train 
d'être joué, donc il ne va pas en créer un autre.

Ce comportement peut ne pas vous sembler utile immédiatement - mais il 
sera très pratique quand nous commencerons à coder en "live"...
