# Threads1

Mal angenommen, Du hast eine Killer-Basslinie und einen krassen Beat gebaut. Wie kannst Du beides zur selben Zeit spielen lassen? Eine Möglichkeit ist es, beide Sounds per Hand ineinander zu weben - erst spielt der Bass ein bisschen, dann das Schlagzeug, dann der Bass etwas mehr… Beides aufeinander zeitlich abzustimmen wird jedoch immer schwieriger, vor allem, wenn noch mehr Sounds dazukommen sollen.

Was, wenn Sonic Pi Sounds automatisch für Dich ineinanderflechten könnte? Kann es auch, und zwar mit einem besonderen Ding, welches Thread heisst.

## Unendliche Schleifen

Damit das nächste Beispiel nicht zu kompliziert wird, musst Du Dir einfach vorstellen, dass dies Deine Killer-Basslinie und Dein krasser Beat sind.

    loop do
      sample :drum_heavy_kick
      sleep 1
    end

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

Wir haben das früher schon besprochen, Endlos-Schleifen sind wie schwarze Löcher für ein Programm; läuft es einmal in die Schleife kommt es da nicht mehr raus, bis Du den `Stopp`-Button klickst. Wie also können wir beide Schleifen zur selben Zeit abspielen? Wir müssen Sonic Pi sagen, dass wir einen bestimmten Abschnitt gleichzeitig mit dem Rest des Codes starten möchten. Hierbei helfen uns Threads.

## Threads kommen zur Hilfe

Wenn wir die erste Schleife in einen `in_thread`-do/end-Block hineinpacken, sagen wir Sonic Pi, es soll den Inhalt dieses do/end-Blocks genau zur selben Zeit wie die nachfolgende Anweisung ausführen. Und das ist in diesem Fall die zweite Schleife. Probier es aus, und Du wirst den Beat zusammen mit der Basslinie hören!

    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

Angenommen, dass wir obendrauf noch einen Synth legen wollten. Ungefähr so:

    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

Jetzt haben wir das gleiche Problem wir vorhin. Die erste Schleife wird durch das `in_thread` zur selben Zeit wie die zweite gespielt. Aber die dritte Schleife wird nie erreicht. Also brauchen wir einen weiteren 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

## Ablauf in Threads

Was Dich vielleicht erstaunt: Wenn Du den Ausführen-Button klickst, erzeugst Du tatsächlich einen neuen Thread, innerhalb dessen der Code abläuft. Deshalb entstehen immer neue Soundschichten, wenn Du den Ausführen-Button wiederholt klickst. Weil die Abläufe Threads sind, werden sie automatisch die Sounds verflechten.

## Geltungsbereich2

Wenn Du Dich besser mit Sonic Pi auskennst, wirst Du herausfinden, dass Threads die wichtigsten Bausteine für Deine Musik sind. Eine wesentliche Funktion, die Threads haben, ist es, aktuelle Einstellungen, die für einen Thread gelten, von anderen Threads zu isolieren. Was genau bedeutet das? Wenn Du etwa einen Synths mit `use_synth` durch einen anderen austauschst, dann veränderst Du den Synth lediglich für den aktuellen Thread - kein anderer der laufenden Threads bekommt den neuen Synth. Sehen wir uns das mal in der Praxis an:

    play 50
    sleep 1

    in_thread do
      use_synth :tb303
      play 50
    end

    sleep 1
    play 50

Hast Du gehört, dass sich der mittlere Klang von den anderen beiden unterschieden hat? Die `use_synth`-Anweisung hat sich nur auf den Thread ausgewirkt, in dem sie auch stand und nicht auf den äußeren Haupt-Thread.

## Vererbung

Wenn Du einen neuen Thread mit `in_thread` erzeugst, wird dieser vom vorherigen alle Einstellungen automatisch erben. Sehen wir uns das an:

    use_synth :tb303
    play 50
    sleep 1

    in_thread do
      play 55
    end

Hast Du bemerkt, dass der zweite Ton mit dem `:tb303`-Synth gespielt wird, obwohl er in einem anderen Thread läuft? Jede der Einstellungen, die mit den unterschiedlichen `use_*`-Ausdrücken vorgenommen wird, verhält sich genauso.

Wenn neue Threads starten, erben sie alle Einstellungen von ihren Eltern. Wenn Du aber Einstellungen innerhalb dieser neuen Threads änderst, haben diese keine Einfluss auf die Eltern-Threads.

## Threads benennen

Schließlich kannst Du Deinen Treads Namen geben.

    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

Sieh Dir das Protokoll-Fenster an, wenn Du diesen Code laufen lässt. Siehst Du, wie die Namen der Threads ausgeben werden?

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

## Nur ein Name pro Thread erlaubt

Eine letzte Anmerkungen zu Threads mit Namen: Ein mit einem bestimmten Namen benannter Thread kann zur Zeit nur einmal laufen. Probieren wir das aus. Sieh Dir den folgenden Code an:

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

Kopiere das einmal in einen Buffer und klicke den `Ausführen`-Button. Klick in noch ein paarmal. Hör Dir diese Kakophonie mehrerer Amen Breaks an, die ryhtmisch nicht unbedingt passend zueinander ablaufen. Ok, jetzt kannst Du auf `Stopp` klicken.

Dieses Verhalten konnten wir schon woanders sehen - wenn Du den `Ausführen`-Button klickst, legen sich die neuen Klänge über die schon laufenden. Wenn eine Schleife abläuft, und Du den `Ausführen`-Button dreimal klickst, bekommst Du drei Ebenen mit Schleifen, die gleichzeitig ablaufen.

Mit benannten Threads ist das jedoch anders:

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

Versuche mit diesem Code den `Ausführen`-Button mehrmals zu klicken. Du wirst immer nur eine Amen-Break-Schleife hören. Das kannst Du auch im Protokoll sehen:

    ==> Skipping thread creation: thread with name :amen already exists.

Sonic Pi sagt Dir, dass ein Thread mit dem Namen `:amen` bereits läuft und es deshalb keinen neuen startet.

Vielleicht erscheint Dir dieses Verhalten im Moment noch nicht sinnvoll - aber es wird sehr nützlich sein, wenn wir ins Live-Coding einsteigen…

1. Im Deutschen bedeutet thread Kette, Faden oder Strang. Der Thread ist jedoch für Programmiersprachen eine so typische Idee, dass eine Übersetzung nur insoweit sinnvoll ist, dass Du Dir die Idee, die hinter diesem Begriff steht, besser merken kannst. Weil niemand beim Programmieren über eine Kette oder einen Faden spricht, werden wir hier nur den englischen Begriff benutzen. ↩

2. Scope bedeutet ins Deutsche übersetzt soviel wie Geltungsbereich. Für die Zukunft ist es aber ganz gut, sich den englischen Begriff zu merken, da auch dieser im Programmierbereich häufig vorkommt. ↩