1 - Hallo zusammen :-)

Willkommen bei Sonic Pi! Hoffentlich bist Du genauso aufgeregt, verrückte Sounds zu machen, denn ich will Dir zeigen, wie das geht. Wir werden viel Spaß dabei haben, alles über Musik, Synthese, Coding, Komposition, Aufführung und andere Dinge zu lernen.

Doch halt, wie unhöflich von mir. Ich sollte mich erst einmal vorstellen - ich bin Sam Aaron - der Typ, der Sonic Pi gebaut hat. Du kannst mich unter @samaaron auf Twitter finden, schau doch mal vorbei. Vielleicht interessierst Du Dich auch für meine Live-Coding-Band Meta-eX, wo ich den Code direkt vor dem Publikum schreibe und damit Musik mache. Du kannst einen Meta-eX-Track in den Beispielen finden.

Bitte schreibe mir, wenn Du irgendwelche Einfälle oder Ideen zur Verbesserung von Sonic Pi hast - Feedback ist sehr hilfreich. Man kann ja nie wissen, vielleicht ist Deine Idee das nächste große Feature!

Schließlich: Dieses Tutorial ist in Abschnitte aufgeteilt, die in Gruppen zu unterschiedlichen Themen aufgeteilt sind. Auch wenn ich es so geschrieben habe, dass man damit von Anfang bis zum Ende einfach lernen kann, kannst Du an jeder Stelle einsteigen, ganz wie es Dir gefällt. Wenn Du etwas im Tutorial vermisst, lass es mich wissen, und ich überlege, wie ich das in zukünftige Versionen einbauen kann.

Ok, dann legen wir los…


1.1 - Live-Coding

Mit Sonic Pi kannst Du etwas sehr aufregendes tun: Du kannst Musik aus Code live schreiben und verändern, während sie spielt. Fast so, als wenn Du mit einer Gitarre Musik machst. Mit anderen Worten: Du kannst Sonic Pi mit auf die Bühne nehmen und jammen!

Mach mal kurz den Kopf frei

Wir werden in diesem Tutorial in die Details von Sonic Pi eintauchen. Jetzt möchte ich Dir aber erst einmal zeigen, wie das ist, live Musik zu coden. Keine Sorge, Du wirst vielleicht nicht sofort alles verstehen. Aber das macht nichts. Genieße kurz diesen Einblick.

Eine Live-Loop

Lass uns loslegen. Kopiere den folgenden Code nach oben in einen leeren Arbeitsbereich:

live_loop :flibble do
  sample :bd_haus, rate: 1
  sleep 0.5
end

Jetzt drücke den Ausführen-Button und Du wirst eine schöne Bass-Drum hören, die schnell vor sich hin hämmert. Mit einem Druck auf den Stopp-Button hört die Musik wieder auf. Aber drücke bitte noch nicht darauf… sondern probiere die folgenden Veränderungen aus:

  1. Lass den Beat der Bass-Drum weiter laufen.
  2. Verändere die Zahl hinter sleep von 0.5 auf einen höheren Wert, etwa 1.
  3. Drücke wieder den Ausführen-Button.
  4. Gemerkt? Die Geschwindigkeit der Bass-Drum hat sich verändert.
  5. Merke Dir diesen Moment. Du hast mit Sonic Pi zum ersten Mal live Code geschrieben. Wahrscheinlich wird es nicht das letzte Mal sein…

Ok, das war einfach. Verändern wir also die Zutaten ein wenig. Vor sample :bd_haus kannst Du die Zeile sample :ambi_choir, rate: 0.3 einfügen. Dein Code müsste dann so aussehen:

live_loop :flibble do
  sample :ambi_choir, rate: 0.3
  sample :bd_haus, rate: 1
  sleep 1
end

So, jetzt spiele damit herum. Verändere die Werte für rate: - was passiert, wenn Du hohe, kleine oder negative Zahlen einträgst? Hast Du gemerkt, wie sich eine sehr kleine Änderung des rate:-Wertes für das :ambi_choir-Sample auswirkt (z.B. 0.29)? Was passiert bei einem wirklich kleinen sleep-Wert? Kannst Du eine Fehlermeldung Deines Computers auslösen, wenn Du den Wert immer kleiner werden lässt? (Wenn das geschieht, nimm einfach wieder einen größeren Wert für sleep und drücke auf Ausführen.)

Kommentiere eine Code-Zeile aus, indem Du ein # an ihren Anfang schreibst:

live_loop :flibble do
  sample :ambi_choir, rate: 0.3
#  sample :bd_haus, rate: 1
  sleep 1
end

Siehst Du? Jetzt ignoriert der Computer diese Zeile und wir hören den Befehl nicht mehr. Was hinter einem # steht ist ein Kommentar. Wir können dieses Zeichen benutzen, um Code schnell zu entfernen und später wieder einzufügen.

Zum Abschluss möchte ich Dir etwas zum Spielen geben. Nimm den Code unten und kopiere ihn in einen freien Arbeitsbereich. Macht nix, Du musst noch nicht alles davon durchschauen, aber Du siehst, dass da zwei Loops sind - zwei Schleifen, die gleichzeitig laufen und sich endlos wiederholen. Jetzt tue, was Du am besten kannst: Experimentiere und spiele herum. Hier sind ein paar Vorschläge:

Vergiss nicht, Ausführen zu drücken, dann hörst Du sofort beim nächsten Durchlauf der Loops Deine Änderungen. Wenn irgendwas schiefgeht - macht nichts! Drücke Stopp, lösche den kaputten Code und fang mit dem ursprünglichen Code noch einmal von vorn an. Denn am besten lernt man beim Fehlermachen…

live_loop :guit do
  with_fx :echo, mix: 0.3, phase: 0.25 do
    sample :guit_em9, rate: 0.5
  end
#  sample :guit_em9, rate: -0.5
  sleep 8
end

live_loop :boom do
  with_fx :reverb, room: 1 do
    sample :bd_boom, amp: 10, rate: 1
  end
  sleep 8
end

Spiele also herum und experimentiere, bis Deine Neugierde einsetzt und Du Dich fragst, wie das hier alles eigentlich wirklich funktioniert und was man noch so alles damit anstellen kann. Jetzt bist Du bereit für den Rest dieses Tutorials.

Worauf wartest Du…?


1.2 - Die Programmoberfläche von Sonic Pi

Sonic PI hat eine sehr einfache Oberfläche zum Coden von Musik. Schauen wir uns das einmal genauer an.

Sonic Pi Interface

A. Wiedergabe-Steuerung

Mit diesen pinkfarbenen Buttons kannst Du Klänge abspielen und stoppen. Der Ausführen-Button startet den Code im Editor, Stopp hält den ablaufenden Code an, Speichern schreibt den Code in eine Datei und Aufnehmen nimmt den gerade laufenden Sound (in einer WAV-Datei) auf.

B. Editor-Steuerung

Die orangefarbenen Buttons steuern den Code-Editor. Die Text vergrößern and Text verkleinern-Buttons verändern die Schriftgröße. Auto-Align Text-Button richtet den Code ordentlich aus, damit er professioneller aussieht und besser lesbar ist.

C. Information und Hilfe

Die blauen Buttons bieten Dir den Zugriff auf Informationen, die Hilfe und die Voreinstellungen. Der Info-Button öffnet ein Fenster mit Informationen über Sonic Pi selbst und wo Du mehr Informationen und Hilfe von anderen findest. Der Hilfe-Button zeigt/verbirgt das eingebaute Hilfesystem (F) und Einstellungen zeigt/verbirgt das Fenster, wo Du einige grundsätzliche Einstellungen regeln kannst.

D. Code-Editor

In diesem Bereich schreibst Du Deinen Code, komponierst Du Deine Musik und führst sie später auf. Es ist ein einfacher Texteditor, in dem Du Code eingibst und bearbeitest; so eine Art sehr einfache Textverabeitung wie Word oder Google Docs. Der Editor färbt bestimmte Begriffe automatisch ein, je nachdem, welche Bedeutung sie innerhalb des Codes haben. Am Anfang ist das vielleicht ein wenig merkwürdig, aber Du wirst es bald nützlich finden. Zum Beispiel erkennst Du Zahlen sofort daran, dass sie blau eingefärbt sind.

E. Protokoll-Fenster

Wenn Dein Code abläuft, siehst Du im Protokoll-Fenster, was das Programm gerade tut. Standardmäßig siehst Du eine Nachricht für jeden erzeugten Klang und die exakte Zeit, wann der Klang ausgelöst wurde. Bei der Suche nach Fehlern kann das sehr hilfreich sein und Du verstehst schneller, was Dein Code macht.

F. Hilfe-System

Das Hilfe-System im unteren Bereich des Programmfensters ist einer der wichtigsten Teile von Sonic Pi. Du kannst es ein- und ausblenden, indem Du den blauenHilfe-Button klickst. Es enthält Hilfe und Informationen über alle Aspekte von Sonic Pi, einschließlich dieses Tutorials, einer Liste der mitgelieferten Synths, Samples, Beispiele, Effekte (FX1) sowie eine komplette Liste aller Funktionen, die Sonic Pi zum Coden von Musik bereitstellt.

  1. Im Englischen wird der Begriff Effekte manchmal lautmalerisch mit FX (“ef-eks”) abgekürzt; FX bezeichnet also die Klangeffekte in Sonic Pi.


1.3 - Spielend lernen

Sonic Pi soll Dich dazu animieren, etwas über Computer und Musik zu lernen - und zwar auf eine spielerische und experimentelle Weise. Das allerwichtigste ist, dass Du Spaß hast. Und bevor Du es überhaupt bemerkt hast, wirst Du zufällig gelernt haben, Code zu schreiben, zu komponieren und Musik aufzuführen.

Es gibt keine Fehler

Einen kleinen Rat möchte ich Dir noch geben, bevor wir anfangen. Ich habe das über die Jahre gelernt, in denen ich Musik live programmiert habe - es gibt keine Fehler, nur Gelegenheiten. Im Jazz habe ich das schön öfters gehört, aber man kann diese Idee auch auf das Live-Coding anwenden. Es spielt keine Rolle, wieviel Erfahrung Du hast, ob Du ein absoluter Anfänger oder ein erfahrender Algoraver bist, Du wirst Code laufen lassen, der vollkommen unerwartete Ergebnisse mit sich bringt. Kann sein, dass es unglaublich cool klingt - dann mache weiter. Kann auch sein, dass es schrecklich klingt und vollkommen fehl am Platz ist. Es spielt keine Rolle, dass so etwas passiert, wichtig ist, was Du damit als nächstes machst. Nimm den Sound, bearbeite ihn und mach daraus etwas Tolles. Die Menge wird durchdrehen.

Fang einfach an

Wenn man lernt, will man die tollen Sachen am liebsten sofort machen. Vergiss das nicht, aber sieh es als ein Ziel an, welches Du erst etwas später erreichen kannst. Überlege Dir aber zunächst mal die einfachste Sache, die Dir Spaß machen wird, und die lohnend erscheint; diese Sache ist ein kleiner Schritt auf dem Weg zu dem faszinierenden Ding, das Dir im Kopf herumgeht. Wenn Dir dieser einfache Schritt klar ist, versuche ihn umzusetzen, spiele damit herum und finde heraus, auf was für neue Ideen Du kommst. Es wird nicht lange dauern und Du wirst viel Spaß haben und Fortschritte machen.

Und: Sorg dafür, dass Du Deine Werke mit anderen teilst!


2 - Synths

Ok, genug der Einführung - jetzt wollen wir Klänge machen.

In diesem Abschnitt besprechen wir, wie man Synths ansteuert und manipuliert. Synth ist die Kurzform von Synthesizer - ein hochtrabendes Wort für ein Ding, das einen Klang erzeugt. Typischerweise sind Synths ziemlich kompliziert im Gebrauch, vor allem analoge Synths mit ihren vielen Kabeln und Modulen. Sonic Pi stellt Dir aber vieles davon auf eine einfache und gut zugängliche Art zur Verfügung.

Die Programmoberfläche von Sonic Pi mag simpel erscheinen, doch wenn Du willst, kannst Du damit sehr tief in ausgeklügelte Klangmanipulationen eintauchen.

Haltet Euch fest…


2.1 - Eure ersten Klänge

Seht Euch den folgenden Code an:

play 70

Damit fängt alles an. Leg los, kopiere und setze das in das Code-Fenster oben im Programm ein (der große weiße Raum unter dem Ausführen-Button). Nun klicke auf Ausführen…

Beep!

Stark. Klicke den Button nochmal. Und nochmal. Und nochmal…

Wow, verrückt, ich bin sicher, dass könntet Ihr den ganzen Tag lang machen. Aber halt, bevor Ihr Euch in einem endlosen Strom von Piepstönen verliert, versuche es mit einer anderen Zahl:

play 75

Hörst Du den Unterschied? Nimm eine niedrigere Zahl:

play 60

Aha, kleine Zahlen erzeugen niedrigere Töne und große Zahlen höhrere. Wie auf dem Klavier spielt man mit den unteren Tasten (die Seite der linken Hand) niedrigere Töne und mit den oberen Tasten (die Seite der rechten Hand) höhere Töne. Tatsächlich stehen die Zahlen und die Töne auf dem Klavier in einer Beziehung zueinander. play 47 bedeutet, spielt den 47. Ton auf dem Klavier. Also spielt play 48 die nächste Taste rechts davon, einen Ton höher. Das C in der vierten Oktave hat in dieser Zählweise die Nummer 60. Das kannst Du so spielen: play 60.

Keine Sorge, wenn Du keine Ahnung hast, was das alles bedeutet. Mir ging es zu Beginn auch so. Für den Anfang reicht es zu wissen: Kleinere Zahlen bedeuten tiefere Klänge und größere Zahlen bedeuten höhere Klänge.

Akkorde

Eine Note zu spielen kann ganz lustig sein, aber mehrere zur selben Zeit zu spielen ist noch besser. Versuche es:

play 72
play 75
play 79

Wow! Wenn Du also play mehrmals hinschreibst, spielen sie alle zur selben Zeit. Versuche es selbst - welche Nummern klingen gut zusammen? Was klingt fürchterlich? Experimentiere, erforsche und erkunde selbst.

Melodie

Einzelne Noten und Akkorde zu spielen macht Spaß - aber wie wäre es mit einer Melodie? Was, wenn Du eine Note nach der anderen spielen wolltest und nicht alle zur selben Zeit? Also das geht ganz einfach, Du brauchst nur ein sleep zwischen den Noten:

play 72
sleep 1
play 75
sleep 1
play 79

Wie hübsch, ein kleines Arpeggio. Was bedeutet die 1 in sleep 1? Sie gibt die Dauer von sleep an. Tatsächlich bedeutet das: Schlafe für einen Schlag. Aber vorläufig können wir uns vorstellen, dass es bedeutet: Schlafe für eine Sekunde. Wie könnten wir unser Arpeggio schneller ablaufen lassen? Dazu brauchen wir kürzere Werte für sleep. Wie wäre es z.B. mit 0.5:

play 72
sleep 0.5
play 75
sleep 0.5
play 79

Achte darauf, dass die Melodie nun schneller spielt. Probiere das selbst aus, ändere die Zeiten, verwende unterschiedliche Zeiten und Noten.

Versuche einmal Zwischennoten wie play 52.31 und play 52.63. Es gibt überhaupt keinen Grund, nur ganze Zahlen zu verwenden. Spiel damit herum und hab Spaß dabei.

Traditionelle Notennamen

Für die unter Euch, die das Notenschreiben schon ein bisschen kennen (keine Sorge, wenn nicht - Du brauchst es nicht unbedingt) - vielleicht möchtet Ihr eine Melodie mit Notennamen anstelle von Zahlen schreiben, also C oder F#2. Auch das geht mit Sonic Pi. Du kannst folgendes machen:

play :C
sleep 0.5
play :D
sleep 0.5
play :E

Denk daran, vor den Notennamen einen : zu stellen, sodass dieser sich Pink einfärbt. Die jeweilige Oktave kannst Du als Zahl dahinter schreiben:

play :C3
sleep 0.5
play :D3
sleep 0.5
play :E4

Wenn Du eine Note um einen Halbton erhöhen willst, füge ein s hinzu, also play :Fs3. Und wenn Du die Note um einen Halbton erniedrigen möchtest, füge ein b an, also play :Eb3.

Jetzt mach was Verrücktes und baue Deine eigenen Melodien.

Anmerkungen des Übersetzers

  1. Im deutschsprachigen Raum schreibt man solche Zahlen normalerweise mit Komma, also 52,3. Der Computer versteht aber nur Englisch, deshalb verwenden wir für Zahlen mit Nachkommastellen einen Punkt - also 52.3.

  2. Auch hier gibt es im deutschsprachigen Raum eine andere Schreibweise: Erhöhte oder erniedrigte Noten z.B. das F werden als Fis oder Fes bezeichnet. Im Englischen heisst das Fis “F sharp” oder auch “F#” und das Fes “F flat” oder auch “Fb”.

    Ansonsten sind die Notennamen mit einer Ausnahme gleich: Die Note H ist im Englischen das B. Und das um einen Halbton erniedrigte H heisst bei uns B, während es im Englischen logischerweise als “B flat” bezeichnet wird. Die C-Dur-Tonleiter lautet im Deutschen C D E F G A H C, während sie im Englischen so lautet: C D E F G A B C.

    Sonic Pi verwendet diese englische Namensgebung für Noten.


2.2 - Synth-Parameter: Amp and Pan

Mit Sonic Pi kannst Du nicht nur Noten und Samples abspielen. Ebenso kannst Du die Klänge mit Parametern gestalten und beeinflussen. Wir werden viele davon in diesem Tutorial behandeln, für jeden Parameter gibt es ausführliche Informationen in der Hilfe. Zwei der nützlichsten sehen wir uns gleich mal an: Amplitude und Pan. Aber vorher lass mich kurz erklären, was Parameter eigentlich sind.

Parameter

Die Synths von Sonic Pi lassen sich über verschiedene Parameter verändern. Parameter sind Regler, die play oder sample übergeben werden; sie verändern und steuern die Art, wie sich die Klänge anhören. Jeder Synth hat seine eigenen Parameter, um den Klang fein einzustellen. Es gibt auch Parameter, die für viele Klänge gleich sind, z.B. amp: und Hüllkurven-Parameter (die wir an anderer Stelle besprechen).

Parameter bestehen aus zwei Teilen: Ihrem Namen (der Name des Reglers) und ihrem Wert (den Wert, auf den Du den Regler setzten möchtest). Zum Beispiel könntest Du einen Parameter mit dem Namen cheese: haben, dem Du den Wert 1 geben möchtest.

Parameter werden den Aufrufen von play und sample mit einem Komma , übergeben, dem der Name des Parameters folgt, etwa amp: (vergiss den Doppelpunkt nicht :), dann eine Leerstelle und schließlich der Wert des Parameters. Zum Beispiel:

play 50, cheese: 1

(Den Parameter cheese: gibt es in Wirklichkeit gar nicht, wir nehmen ihn hier nur als Beispiel).

Du kannst mehrere Parameter hintereinanderschreiben, indem Du sie mit weiteren Kommata abtrennst:

play 50, cheese: 1, beans: 0.5

Die Reihenfolge der Parameter spielt keine Rolle, so dass die folgende Zeile dasselbe tun würde wie die vorherige:

play 50, beans: 0.5, cheese: 1

Parameter, die vom Synth nicht erkannt werden, werden einfach links liegen gelassen (so wie cheese und beans, welches ja wirklich lachhafte Namen für einen Parameter wären!).

Wenn Du aus Versehen zweimal denselben Parameter benutzt, gewinnt der letzte. Im folgenden Beispiel wird beans den Wert 2 bekommen und nicht 0.5:

play 50, beans: 0.5, cheese: 3, eggs: 0.1, beans: 2

Viele Dinge in Sonic Pi lassen sich über Parameter steuern; nimm Dir ein bisschen Zeit zu lernen, wie Du sie einsetzten kannst, und Du bist startklar. Jetzt spielen wir mal mit unserem ersten Parameter: amp:.

Amplitude

Die Amplitude ist die Weise, wie sich der Computer die Lautstärke eines Klangs vorstellt. Eine hohe Amplitude ergibt einen lauteren Klang und eine niedrige Amplitude ergibt einen leiseren Klang. So wie Sonic Pi Zahlen dazu benutzt, um Zeit und Töne darzustellen, so benutzt es Zahlen auch dazu, um die Lautstärke abzubilden. Eine Amplitude von 0 bedeutet Stille (Du wirst nichts hören), eine Amplitude von 1 steht für normale Lautstärke. Du kannst die Amplitude aufdrehen auf 2, 10, 100. Aber Vorsicht: Wenn die Amplitude aller gemeinsamen Klänge zu hoch wird, setzt Sonic Pi einen sogenannten Kompressor ein, damit die Klänge nicht zu laut für Dein Ohr werden. Oft klingt das dann matschig und schräg. Verwende also lieber niedrigere Amplituden, das heißt zwischen 0 und 0.5, um die Kompression zu verhindern.

Amp verwenden

Um die Amplitude eines Klangs zu ändern, setze den Parameter amp: ein. Mit 0.5 lässt Du zum Beispiel den Klang mit halber Amplitude spielen:

play 60, amp: 0.5

Und für die doppelte Amplitude:

play 60, amp: 2

Der Parameter amp: beeinflusst nur den Aufruf von play, mit dem er unmittelbar zusammenhängt. Das heißt, in dem folgenden Beispiel wird der erste Aufruf von play mit halber Lautstärke gespielt und der zweite wieder mit der Standardlautstärke (1) 1:

play 60, amp: 0.5
sleep 0.5
play 65

Natürlich kannst Du für jeden Aufruf von play andere Werte für amp: festlegen:

play 50, amp: 0.1
sleep 0.25
play 55, amp: 0.2
sleep 0.25
play 57, amp: 0.4
sleep 0.25
play 62, amp: 1

Panning

Ein weiterer interessanter Parameter ist pan:. Er gibt an, aus welcher Richtung der Klang kommt, wenn wir in Stereo hören. Der Wert -1 schiebt den Klang ganz nach links, 0 steht für die Mitte und 1 lässt den Klang nur aus dem rechten Lautsprecher kommen. Natürlich kannst Du jeden Wert zwischen -1 und 1 verwenden, um Deine Klänge im Stereofeld zu positionieren.

Spiel einen Klang, der nur aus linken Lautsprecher kommt:

play 60, pan: -1

Jetzt aus dem rechten Lautsprecher:

play 60, pan: 1

Nun lass den Klang aus der Mitte herauskommen (die Standardposition):

play 60, pan: 0

Jetzt leg’ los und arbeite mit der Amplitude und dem Panning von Deinen Klängen.

  1. In Programmiersprachen nennt man einen Standardwert einen Default. Genauer gesagt ist ein Default-Wert der Wert, der automatisch gesetzt wird, also die Voreinstellung im Programm.


2.3 - Synths wechseln

Bis jetzt hatten wir viel Spaß mit Tönen und Samples. Aber wahrscheinlich wird Dir langsam langweilig, immer denselben Klang zu hören. Ist das alles, was Sonic Pi anzubieten hat? Besteht das Live-Coding nicht aus mehr als Pieptönen? Aber klar doch, und in diesem Abschnitt sehen wir uns die spannenden Sounds an, die Sonic Pi mitbringt.

Synths

Sonic Pi bringt eine Palette an Instrumenten mit, die Synths heissen, eine Kurzform für Synthesizer. Samples sind vorher aufgenommene Klänge; demgegenüber erzeugen Synths neue Klänge, je nachdem, wie Du sie anlegst (wie das geht, werden wir später sehen). Die Synths von Sonic Pi sind sehr wirkungsvoll und ausdrucksstark und man kann damit tolle Sachen machen. Als erstes lernen wir, wie man einen Synth auswählt, den man benutzen möchte.

Brilliante Sägen und Prophets1

Einen spaßigen Sound ergibt die Sägezahn-Welle - probieren wir es mal aus:

use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
play 62

Nehmen wir einen anderen Klang - den Prophet:

use_synth :prophet
play 38
sleep 0.25
play 50
sleep 0.25
play 62

Wie wäre es damit, beide Sounds zu verbinden? Zuerst nacheinander:

use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25

Nun gleichzeitig:

use_synth :tb303
play 38
sleep 0.25
use_synth :dsaw
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25

Hast Du bemerkt, dass das use_synth-Kommando nur die nachfolgenden play-Kommandos beeinflusst? Stell es Dir als einen großen Schalter vor - neue Aufrufe von play werden immer den Synth benutzen, auf den der Schalter gerade zeigt. Du kannst diesen Schalter mit use_synth auf einen anderen Synth umschalten.

Synths entdecken

Du kannst herausfinden, welche Synths Sonic Pi für Dich bereitstellt, indem Du im Menü auf der linken Seite Synths anklickst (gleich über Fx). Es gibt über 20 Stück. Das sind einige meiner Lieblings-Synths:

Spiel mal ein bisschen herum, indem Du in Deinem Stück die Synths wechselst. Kombiniere unterschiedliche Synths oder setze sie für unterschiedliche Stellen in Deinem Stück ein.

  1. Der Name “Sägezahn” (engl. saw) kommt von der Wellenform, die dieser Synthesizer produziert. Wenn man sich diesen Klang mit einem Oszilloskop anzeigen lässt, sieht er aus wie die Zähne einer Säge. Der Name “Prophet” kommt von einem Synthesizer, der Ende der 70er Jahre vom amerikanischen Hersteller Sequential Circuits hergestellt wurde.


2.4 - Dauer und Hüllkurven

Wie wir schon vorher gesehen haben, können wir mit dem sleep-Kommando steuern, wann ein Klang zu spielen anfängt. Bislang konnten wir aber noch nicht die Dauer eines Klangs steuern (außer bei Samples, die wir strecken oder verdichten können).

Um die Dauer von Klängen auf einfache, aber tiefgehende Weise zu beeinflussen, bietet Sonic Pi das Prinzip der ADSR-Hüllkurve 1. (Wir werden später sehen, was ADSR genau bedeutet). Eine Hüllkurve hat zwei nutzbringende Eigenschaften:

Dauer

Die Dauer bestimmt, wie lange ein Klang klingt. Eine erhöhte Dauer bedeutet, dass Du den Klang länger hören kannst. Alle Klänge in Sonic Pi haben eine Hüllkurve, die beeinflusst werden kann, und die gesamte Dauer dieser Hüllkurve bestimmt die Dauer des Klangs. Deshalb kann man über die Kontrolle der Hüllkurve die Dauer des Klangs beeinflussen.

Amplitude

Die ADSR-Hüllkurve kontrolliert nicht nur die Dauer, sondern ermöglicht Dir auch die genaue Kontrolle über die Amplitude eines Klangs. Alle Klänge beginnen und enden mit Stille; dazwischen ist irgendetwas hörbar. Hüllkurven erlauben Dir, die Amplitude der hörbaren Anteile des Klanges zu verschieben, zu verlängern und zu verkürzen. Es ist so, als würdest Du jemanden sagen, wie er die Lautstärke einer Musik lauter und leiser dreht. Du könntest denjenigen z.B. bitten: “Fang bitte mit einer Stille an, dreh dann die Lautstärke langsam bis zum Anschlag hoch, lass es eine Weile so und blende dann schnell runter, bis man nichts mehr hört”. Genau dafür sind in Sonic Pi die Hüllkurven da.

Wie wir vorher schon gesehen haben, bedeutet eine Amplitude von 0 Stille und eine Amplitude von 1 entspricht der normalen Lautstärke.

Release-Zeit

Standardmäßig haben alle Synths eine Release-Zeit von der Länge 1. Das bedeutet, sie haben eine Dauer von 1 Schlagzeit (die in der Grundeinstellung 1 Sekunde lang ist), bevor sie verklungen sind. Über das das release-Argument der Funktion play können wir diese Dauer verändern. Damit ein Synth 2 Schläge lang spielt, übergeben wir z.B. einen release von 2:

play 60, release: 2

Mit einer sehr kurzen Release-Zeit können wir den Synth-Klang auch sehr kurz machen:

play 60, release: 0.2

Also was ist nun die Release-Zeit? Es ist die Zeit, die der Klang braucht, um von der vollen Höhe der Kurve (typischerweise der Wert 1) bis auf Null abzufallen. Das nennt man auch die Release-Phase und es ist ein linearer Übergang (d.h. eine gerade Linie). Die folgende Abbildung zeigt, wie ein solcher Übergang aussieht:

release envelope

Die senkrechte Linie ganz links im Bild zeigt, dass der Klang mit einer Amplitude von 0 startet, jedoch sofort auf die volle Höhe geht (das ist die Attack-Phase, die wir gleich ansehen werden). Wenn die volle Höhe erreicht ist, geht die Amplitude in einer geraden Linie bis auf Null zurück, wobei dies so lange dauert, wie es mit release festgelegt wurde. Je länger die Release-Zeit eines Synth, desto länger klingt dieser aus.

Deshalb kannst Du die Länge eines Klangs ändern, wenn Du seine Release-Zeit änderst. Spiele einmal mit unterschiedlichen Release-Zeiten herum.

Attack-Zeit

Standardmäßig ist die Attack-Phase für alle Synths 0, was bedeutet, dass diese sofort von der Amplitude 0 auf 1 hochgehen. Dies gibt dem Synth einen perkussiven Klang. Vielleicht möchtest Du den Klang jedoch einblenden. Dies kannst Du mit dem attack-Argument erreichen. Blende einige Klänge ein:

play 60, attack: 2
sleep 3
play 65, attack: 0.5

Du kannst mehrere Argumente zur selben Zeit anwenden. Zum Beispiel für eine kurze Attack- und eine lange Release-Zeit:

play 60, attack: 0.7, release: 4

Diese Hüllkurve mit einem kurzen Attack und langem Release sieht so aus:

attack release envelope

Natürlich kann man die Dinge auch umdrehen. Versuche einen langen Attack und einen kurzen Release:

play 60, attack: 4, release: 0.7

long attack short release envelope

Schließlich kannst Du auch einen kurzen Attack und Release für kürzere Klänge verwenden.

play 60, attack: 0.5, release: 0.5

short attack short release envelope

Sustain-Zeit

Zusätzlich zu den Attack- und Release-Zeiten kannst Du auch die Sustain-Zeit bestimmen. Das ist die Zeitdauer, die der Klang anhält, wenn er die eingestellte Lautstärke erreicht hat, also zwischen dem Attack- und dem Release-Stadium.

play 60, attack: 0.3, sustain: 1, release: 1

ASR envelope

Die Sustain-Zeit kann man gut dafür gebrauchen, um wichtige Klänge in einem Mix hervorzuheben, bevor möglicherweise der Release einsetzt. Natürlich kann man ohne weiteres sowohl den Attack als auch den Release auf 0 setzen und nur den Sustain gebrauchen. Damit bekommt man einen Klang ohne Ein- und Ausblendung. Aber vorsicht, ein Release von 0 kann Klickgeräusche in der Aufnahme verursachen. Meist ist es besser, einen geringen Wert wie z.B. 0.2 zu verwenden.

Decay-Zeit

Und schließlich, falls Du alles ganz genau beeinflussen möchtest, kannst Du noch die Decay-Zeit festlegen. Das ist eine Phase der Hüllkurve, die zwischen die Attack- und die Release-Phase passt; sie gibt die Zeit an, wo die Amplitude vom attack_level zum sustain_level hinunterfällt. Normalerweise steht das Decay-Argument auf 0, während sowohl das Attack- als auch das Sustain-Level auf 1 stehen. Damit die Decay-Zeit einen hörbaren Effekt hat, müssen Attack und Sustain also auch angegeben werden:

play 60, attack: 0.1, attack_level: 1, decay: 0.2, sustain_level: 0.4, sustain: 1, release: 0.5

ADSR envelope

ADSR-Hüllkurven

Fassen wir noch einmal zusammen: Die ADSR-Hüllkurven von Sonic Pi bestehen aus den folgenden Phasen:

  1. attack - die Zeit, welche die Amplitude von 0 bis zum attack_level benötigt,
  2. decay - die Zeit, in der die Amplitude vom attack_level zum sustain_level übergeht,
  3. sustain - die Zeit, in der sich die Amplitude auf dem sustain_level hält,
  4. release - die Zeit, welche die Amplitude vom sustain_level auf 0 bringt

Eins ist wichtig: der Klang dauert so lange wie die Summe aller Zeiten der unterschiedlichen Phasen. Deshalb hat der folgende Klang eine Dauer von 0.5 + 1 + 2 + 0.5 = 4 Schlägen:

play 60, attack: 0.5, decay: 1, sustain_level: 0.4, sustain: 2, release: 0.5

Jetzt weisst Du, wie Du Deine Klänge mit Hüllkurven verändern kannst…

  1. Der englische Begriff für Hüllkurve heißt Envelope.

    ADSR steht als Kurzform für die Begriffe Attack, Decay, Sustain und Release, die in diesem Kapitel erklärt werden.


3 - Samples

Du kannst auch aufgenommene Sounds in Deiner Musik verwenden. In der großen Tradition des Hip-Hop nennen wir diese aufgenommenen Sounds auch Samples. Also, wenn Du ein Mikrophon mit nach draußen nimmst und den zarten Klang der Regentropfen auf einem Zeltdach aufnimmst, dann ist das Ergebnis ein Sample.

Mit Samples kann man in Sonic Pi viele tolle Sachen machen. Es sind nicht nur 90 freie Samples zum sofortigen Gebrauch dabei, sondern Du kannst auch Deine eigenen Sampes einbauen und verändern.

Legen wir los…


3.1 - Samples ansteuern

Pieptöne zu spielen ist erst der Anfang. Mit aufgenommenen Samples hat man noch viel mehr Spaß. Probier mal:

sample :ambi_lunar_land

Sonic Pi enthält viele Samples, mit denen Du spielen kannst. Du kannst sie ebenso wie das play-Kommando benutzen. Um mehrere Samples gleichzeitig zu spielen, schreib sie einfach untereinander:

play 36
play 48
sample :ambi_lunar_land
sample :ambi_drone

Wenn Du sie nacheinander spielen willst, füge einen sleep-Befehl ein:

sample :ambi_lunar_land
sleep 1
play 48
sleep 0.5
play 36
sample :ambi_drone
sleep 1
play 36

Hast Du bemerkt, dass Sonic Pi nicht wartet, bis ein Klang beendet ist, bevor der nächste beginnt? Der sleep-Befehl beschreibt nur, wann ein Klang ausgelöst wird, und wann der nächste nachfolgt. Damit kannst Du Klänge in Schichten übereinander legen und interessante überlappende Effekte herstellen. Später sehen wir uns an, wie man die Länge von Klängen mit Hüllkurven kontrollieren kann.

Samples entdecken

Die Samples, die Sonic Pi mitbringt, kannst Du auf zwei Arten entdecken. Erstens kannst Du dieses Hilfesystem benutzen. Klicke auf Samples im Menü auf der linken Seite, wähle eine Gruppe aus und lass Dir die Liste aller verfügbaren Klänge anzeigen.

Zweitens hilft Dir das Auto-Completion System. Tipp einfach den Anfang eines Gruppennamens von Samples ein, also: sample :ambi_. Nun klappt ein Menü auf, aus dem Du ein Sample auswählen kannst. Versuche einen der folgenden Anfänge von Gruppennamen:

Jetzt leg los und mische Samples in Deine Komposition!


3.2 - Sample-Parameter: Amp und Pan

Genauso wie mit den Synths können wir auch unsere Sounds mit Parametern steuern. Der selbe Parameter-Mechanismus funktioniert auch mit Samples. Besuchen wir unsere Freunde amp: and pan: noch einmal.

Die Amplitude von Samples verändern

Du kannst die Amplitude (Lautstärke) von Samples so steuern, wie Du es schon von den Synths kennst:

sample :ambi_lunar_land, amp: 0.5

Das Stereo-Feld von Samples verändern

Wir können auch den pan:-Parameter auf Samples anwenden. Hier zum Beispiel spielen wir den Amen-Break zunächst für das linke und nach der Hälfte für das rechte Ohr:

sample :loop_amen, pan: -1
sleep 0.877
sample :loop_amen, pan: 1

0.877 ist genau die Hälfte der Dauer des Amen-Breaks in Sekunden.

Beachte: Samples berücksichtigen nicht die Grundeinstellungen für einen Synth, die Du mit use_synth_defaults setzen kannst (aber dazu kommen wir später noch).


3.3 - Samples dehnen

Jetzt können wir schon eine ganze Menge Synths und Samples spielen, um damit Musik zu machen. Es wird Zeit zu lernen, wie wir diese Synths und Samples verändern können; das macht unsere Musik einzigartiger und spannender. Als erstes sehen wir uns an, wie wir Samples strecken und stauchen können.

Wie Samples Klänge darstellen

Samples sind aufgenommene Klänge und werden als eine Zahlenreihe von Messwerten (deshalb “Sample”) gespeichert; diese Zahlen sagen der Lautsprechermembran, wie sie sich bewegen muss, um den Klang wiederzugeben. Die Lautsprechermembran kann sich nach innen und nach außen bewegen und die Zahlen geben deshalb an, wie weit sich die Membran zu jedem Zeitpunkt nach innen oder außen bewegen soll. Um einen Klang als Aufnahme wirklichkeitsgetreu wiederzugeben, muss das Sample je Sekunde viele tausend Zahlen speichern. Sonic Pi nimmt diese Zahlenreihe und gibt sie in der richtigen Samplerate 1 an den Lautsprecher in Deinem Computer, so dass der Klang richtig wiedergegeben wird. Es macht aber auch Spaß, die Samplerate zu beeinflussen, denn das verändert den Klang.

Die Samplerate ändern

Lass uns mit einem der Ambient-Klänge spielen: ambi_choir. Um diesen mit Standard-Samplerate wiederzugeben, kannst Du dem sample das Argument2 rate: übergeben:

sample :ambi_choir, rate: 1

Das Sample wird unverändert mit der normalen Samplerate (1) abgespielt, also nichts Besonderes. Aber wir können die Zahl jederzeit verändern. Was passiert bei 0.5?

sample :ambi_choir, rate: 0.5

Wow! Was ist denn jetzt los? Also, hier passieren zwei Dinge. Erstens braucht das Sample doppelt so lange und zweitens klingt er eine Oktave niedriger. Sehen wir uns das mal genauer an.

Lasst uns stretchen

Mit dem Amen-Break-Sample macht das strecken und zusammenstauchen besonders viel Spass. Mit der normalen Samplerate passt das Sample gut in einen Drum ‘n’ Bass-Track:

sample :loop_amen

Wenn wir die Samplerate ändern, dann können wir die Stilrichtungen wechseln. Versuche es mal mit halber Samplerate für Hip-Hop der alten Schule:

sample :loop_amen, rate: 0.5

Wenn wir es beschleunigen, betreten wir das Jungle-Territorium:

sample :loop_amen, rate: 1.5

Und als letzten Trick - sehen wir mal, was passiert, wenn wir eine negative Rate angeben:

sample :loop_amen, rate: -1

Boah! Er wird rückwärts gespielt! Jetzt probiere herum mit vielen unterschiedlichen Samples und unterschiedlichen Sampleraten. Versuch’s mit sehr hohen oder mit verrückt langsamen. Finde heraus, welche spannenden Klänge Du damit produzieren kannst.

Eine einfache Erklärung der Samplerate

Man kann sich Samples gut als Sprungfedern vorstellen. Wenn man die Samplerate verändert, ist das so, als ob man die Feder zusammendrückt oder auseinanderzieht. Wenn Du ein Sample mit der doppelten Samplerate abspielst, dann drückst Du die Feder zusammen, bis sie nur noch die Hälfte ihrer normalen Länge hat. Das Sample braucht also auch nur die Hälfte der Abspielzeit. Wenn Du das Sample mit halber Samplerate spielst, dann ziehst Du die Feder auf ihre doppelte Länge auseinander. Das Sample dauert also nun doppelt so lange. Je mehr Du zusammendrückst (höhere Rate), desto kürzer das Sample, je mehr Du auseinanderziehst (geringere Rate), desto länger dauert das Sample.

Wenn man eine Feder zusammendrückt, dann erhöht man ihre Dichtheit (die Anzahl der Windungen je Zentimeter) - das ist so ähnlich wie bei einem Sample, der höher klingt. Wenn man die Feder auseinanderzieht, dann verringert sich ihre Dichtheit, vergleichbar einem Klang, der tiefer klingt.

Die Mathematik hinter der Samplerate

(Dieser Abschnitt ist für diejenigen, die es genauer wissen möchten. Wenn nicht, könnt Ihr den gerne überspringen…)

Wie wir oben gesehen haben, wird ein Sample durch eine lange Liste von Zahlen dargestellt, die der Lautsprechermembran sagen, wo sie zu welchem Zeitpunkt sein soll. Wir können diese Zahlenliste nehmen und eine Kurve zeichnen, die ungefähr so aussieht:

sample graph

Vielleicht hast Du Bilder wie dieses schon einmal gesehen. Das ist die Kurvenform eines Sample. Es ist bloß eine Kurve, die aus Zahlen gebildet ist. Typischerweise wird eine solche Kurve aus 44100 Datenpunkten je Sekunde gebildet (das hat mit dem Nyquist-Shannon-Abtasttheorem zu tun). Wenn also das Sample 2 Sekunden dauert, dann wird die Kurve aus 88200 Zahlen gebildet, die wir an den Lautsprecher mit einer Datenrate von 44100 Datenpunkten pro Sekunde senden. Natürlich könnten wir es mit der doppelten Datenrate senden, also 88200 Datenpunkten pro Sekunde. Dann würde das Sample nur eine Sekunde lang dauern. Wir können es auch mit der halben Datenrate abspielen; das wären dann 22050 Datenpunkte pro Sekunde und würde 4 Sekunden dauern.

Die Dauer des Sample ist also abhängig von der Datenrate:

Wir können das in einer Formel zusammenfassen:

neue_sample_dauer = (1 / rate) * sample_dauer

Eine Veränderung der Samplerate beeinflusst auch die Tonhöhen des Samples. Die Frequenz oder Tonhöhe einer Kurve wird dadurch bestimmt, wie schnell sie hoch und runter geht. Unsere Gehirne machen aus schnellen Bewegungen einer Lautsprechermembran hohe Töne und aus langsamen tiefe. Deshalb kannst Du manchmal sogar sehen, wie sich ein großer Basslautsprecher bewegt, wenn ein sehr tiefer Ton rauskommt. Er bewegt sich dann wesentlich langsamer als ein Lautsprecher, der hohe Töne wiedergibt.

Wenn Du eine Kurve nimmst und sie zusammendrückst, wird sie je Sekunde öfter hoch und runter gehen als vorher. Der Ton wird dann auch höher sein. Wenn man die Auf- und Abbewegungen je Sekunde verdoppelt (Oszillationen), dann wird die Frequenz, die Tonhöhe, verdoppelt. Also, wenn Du Dein Sample mit doppelter Samplerate abspielst, wird es auch doppelt so hoch klingen; andererseits: eine Halbierung der Samplerate wird auch die Frequenz halbieren. Andere Sampleraten werden dementsprechend die Tonhöhe beinflussen.

  1. Die Samplerate heißt auch Samplingrate oder Abtastrate; rate steht für die Frequenz, mit der Sonic Pi die Zahlen, die im Sample den Klang darstellen, an die Lautsprechermembran sendet.

  2. Argument ist ein anderer Begriff für Parameter; an dieser Stelle bedeuten beide Begriffe dasselbe.


3.4 - Enveloped Samples

Es ist auch möglich, die Dauer und Amplitude eines Sample mit einer ADSR-Hüllkurve zu verändern. Das funktioniert jedoch ein wenig anders als die ADSR-Hüllkurven bei den Synths. Mit Sample-Hüllkurven kannst Du die Amplitude und die Dauer eines Samples nur verringern - niemals vergrößern. Das Sample wird entweder stoppen, wenn seine normale Laufzeit vorbei ist, oder wenn die Hüllkurve das Sample begrenzt - je nachdem welche kürzer ist. Mit einem sehr langen release kannst Du ein Sample also nicht über seine normale Laufzeit hinaus verlängern.

Amen-Hüllkuven

Kommen wir zu unserem treuen Freund zurück, dem Amen-Break:

sample :loop_amen

Ohne Parameter hören wir das Sample in seiner gesamten Länge und mit voller Lautstärke. Mit dem attack-Parameter können wir das Sample einblenden lassen:

sample :loop_amen, attack: 1

Wähle für eine kürzere Blende einen kürzeren Attack-Wert:

sample :loop_amen, attack: 0.3

Auto-Sustain

Beim Sustain-Wert unterscheidet sich das Verhalten einer ADSR-Hüllkuve. Bei der Hüllkurve für Standard-Synths steht der Sustain normalerweise auf 0 - außer Du setzt den Wert ausdrücklich. Bei Samples wird der Sustain-Wert auf einen automagical Wert gesetzt - nämlich die Zeit, die es braucht, bis das gesamte Sample abgelaufen ist. Darum hören wir das Sample komplett, wenn wir keine Default-Werte übergeben. Wenn die Werte für Attack, Decay, Sustain und Release alle 0 wären, würden wir keinen Pieps hören. Deshalb berechnet Sonic Pi zunächst, wie lange das Sample von sich aus dauert, zieht etwaige Dauern für Attack, Decay und Release davon ab und setzt die restliche Zeit als Sustain-Wert. Wenn die Werte von Attack, Decay und Release zusammengenommen länger dauern als das gesamte Sample, wird der Sustain-Wert einfach auf 0 gesetzt.

Ausblenden

Um das auszuprobieren, schauen wir uns den Amen-Break genauer an. Wir fragen Sonic Pi, wie lang das Sample ist:

print sample_duration :loop_amen

Es wird 1.753310657596372 ausgeben; das ist die Länge des Sample in Sekunden. Wir runden das einmal bequemerweise auf 1.75 ab. Wenn wir nun den Release-Wert auf 0.75 setzen, wird etwas erstaunliches passieren:

sample :loop_amen, release: 0.75

Die erste Sekunde des Sample wird mit voller Lautstärke gespielt, danach wird über eine Periode von 0.75 Sekunden ausgeblendet. Das ist der Auto-Sustain in Aktion. Standardmäßig berechnet Sonic Pi den Release immer vom Ende des Samples aus. Wenn unser Sample 10.75 Sekunden lang wäre, würden die ersten 10 Sekunden in voller Lautstärke gespielt bevor dann eine Ausblende über 0.75 Sekunden erfolgt.

Zur Erinnerung: Standardmäßig blendet der release: am Ende des Sample aus.

Ein- und Ausblenden

Wir können attack: und release: zusammen mit Auto-Sustain nutzen, um über die Laufzeit des Sample ein- und auszublenden:

sample :loop_amen, attack: 0.75, release: 0.75

Da die Gesamtdauer des Sample 1.75s beträgt und unsere Attack- und Release-Phasen zusammen 1.5s ergeben, erhält der Sustain automatisch den Wert 0.25s.

Ausdrücklich angegebener Sustain

Wir können ohne weiteres das normales Synth-ADSR-Verhalten aktivieren, indem wir dem sustain den Wert 0 geben:

sample :loop_amen, sustain: 0, release: 0.75

Jetzt spielt unser Sample insgesamt nur 0.75 Sekunden. Mit dem Standardwert 0 für attack: und decay: springt das Sample direkt auf die volle Lautstärke, bleibt dort für 0s und fällt dann innerhalb der Release-Phase mit einer Dauer von 0.75s auf den Lautstärkenwert 0 ab.

Perkussive Becken

Wir können dieses Verhalten gut dazu benutzen, um länger klingende Samples in kürzere, perkussivere Versionen zu verwandeln. Sieh Dir das Sample :drum_cymbal_open an:

sample :drum_cymbal_open

Man kann hören, wie das Becken eine Zeit lang ausklingt. Mit ein paar kleinen Änderungen an der Hüllkurve klingt es perkussiver:

sample :drum_cymbal_open, attack: 0.01, sustain: 0, release: 0.1

Indem Du die Sustain-Dauer verlängerst, kannst Du es so klingen lassen, als ob das Becken erst angeschlagen und dann abgedämpft würde:

sample :drum_cymbal_open, attack: 0.01, sustain: 0.3, release: 0.1

Jetzt versuch’ einmal, Hüllkuven über Samples zu legen. Verändere auch die Samplerate; damit kannst Du sehr interessante Ergebnisse erzielen.


3.5 - Teil-Samples

Dieses Kapitel schließt unsere Erkundung von Sonic Pi’s Sample-Player ab. Fassen wir noch einmal zusammen. Wir haben uns angesehen, wie wir Samples abspielen können:

sample :loop_amen

Dann haben wir gesehen, dass wir die Samplerate ändern können - etwa um ein Sample mit halber Geschwindigkeit abzuspielen:

sample :loop_amen, rate: 0.5

Als nächstes haben wir einen Blick darauf geworfen, wie wir ein Sample ein- und ausblenden lassen (hier zum Beispiel mit halber Geschwindigkeit):

sample :loop_amen, rate: 0.5, attack: 1

Wir haben uns auch angeschaut, wie wir ein Sample am Anfang perkussiver klingen lassen können, indem wir sustain: ausdrücklich einen Wert zuweisen, und sowohl der Attack als auch der Release kurze Werte bekommen:

sample :loop_amen, rate: 2, attack: 0.01, sustain: 0, release: 0.35

Wäre es aber nicht toll, wenn wir ein Sample nicht immer vom Anfang starten lassen müssten? Wäre es nicht auch prima, wenn das Ende des klingenden Sample nicht immer seinem wirklichen Ende entsprechen müsste?

Einen Startpunkt bestimmen

Es ist möglich, einen beliebigen Startpunkt eines Sample als Wert zwischen 0 und auszuwählen, wobei 0 der Anfang, 1 das Ende und 0.5 die Mitte des Samples darstellt. Spielen wir die zweite Hälfte des Amen Break:

sample :loop_amen, start: 0.5

Oder vielleicht das letzte Viertel des Sample:

sample :loop_amen, start: 0.75

Einen Endpunkt bestimmen

Gleichermaßen können wir über einen Wert zwischen 0 und 1 einen beliebigen Endpunkt im Sample festlegen. Beenden wir den Amen-Break nach der ersten Hälfte:

sample :loop_amen, finish: 0.5

Start- und Endpunkt bestimmen

Natürlich können das auch kombinieren und einen beliebigen Abschnitt des Sample abspielen. Wie wäre es mit einem kurzen Abschnitt aus der Mitte:

sample :loop_amen, start: 0.4, finish: 0.6

Was passiert, wenn wir eine Startposition nach der Endposition auswählen?

sample :loop_amen, start: 0.6, finish: 0.4

Cool! Dann spielt es rückwärts!

In Kombination mit der Samplerate

Diese neue Fähigkeit, beliebige Abschnitte eines Klangs zu spielen, lässt sich mit unserem Freund rate: kombinieren. Zum Beispiel können wir einen sehr kurzen Abschnitt des Amen-Breaks sehr langsam spielen:

sample :loop_amen, start: 0.5, finish: 0.7, rate: 0.2

In Kombination mit Hüllkurven

Schließlich können wir all dies mit unseren ADSR-Hüllkurven kombinieren und interessante Ergebnisse damit erzielen:

sample :loop_amen, start: 0.5, finish: 0.8, rate: -0.2, attack: 0.3, release: 1

Jetzt leg’ los und hab’ Spaß, Samples mit diesem Zeug aufzumischen…


3.6 - Samples aus externen Quellen

Mit den mitgelieferten Samples kannst Du schnell einsteigen, aber vielleicht möchtest Du mit neuen aufgenommenen Klängen in Deiner Musik experimentieren. Sonic Pi unterstützt das ausdrücklich. Lass’ uns aber zunächst über die Übertragbarkeit Deines Stücks sprechen.

Übertragbarkeit

Wenn Du Dein Stück nur mithilfe der eingebauten Synths und Samples komponierst, braucht man nur den Code, um Deine Musik so abzuspielen, wie Du sie geschrieben hast. Denk’ darüber einen Augenblick nach - das ist erstaunlich! Ein bisschen Text, den Du per Email verschicken oder auf Gist ablegen kannst, reicht vollkommen aus, um Deine Klänge wieder abzuspielen. So wird es sehr einfach, Deine Kompositionen mit Deinen Freunden zu teilen. Sie brauchen nur ein wenig Code von Dir.

Wenn Du nun selbst aufgenommene Samples verwendest, verlierst Du diese Übertragbarkeit. Und zwar deshalb, weil man zum Abspielen auf einem anderen Rechner nicht nur den Code braucht, sondern auch Deine Samples

Lokale Samples

Wie geht das nun, eine beliebige WAV- oder AIFF-Datei auf Deinem Computer zu spielen? Dafür musst Du dem Ausdruck sample nur den Pfad der Datei übergeben:

sample "/Users/sam/Desktop/my-sound.wav"

Sonic Pi wird das Sample nun automatisch laden und spielen. Alle anderen Standard-Parameter, die Du schon kennengelernt hast, kannst Du jetzt auch für Dein eigenes Sample einsetzen:

sample "/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3

4 - Randomisierung1

Zufallszahlen sind eine tolle Möglichkeit, Deine Musik interessant zu gestalten. Sonic Pi bietet einige Funktionen, um Zufallsfaktoren in Deine Musik einzubauen; aber bevor wir starten, müssen wir noch einer schockierenden Wahrheit ins Gesicht sehen: In Sonic Pi bedeutet zufällig nicht wirklich zufällig. Was zum Teufel soll das bedeuten? Nun, das verrate ich Dir jetzt.

Wiederholbarkeit

Eine wirklich nützliche Zufallsfunktion ist rrand; sie liefert Dir einen zufälligen Wert zwischen zwei Zahlen - einem Minimal- und einem Maximalwert. (rrand ist ein Kürzel für das englische ranged random, also eine Zufallszahl innerhalb eines bestimmten Wertebereichs).

play rrand(50, 100)

Oh, eine zufällige Note wird gespielt. Es war die Note 77.4407. Eine nette Note zwischen 50 und 100. Aber hallo, habe ich gerade diese angeblich zufällige Note exakt vorhergesagt? Da ist doch etwas nicht ganz astrein. Lasse den Code noch einmal ablaufen. Wieder 77.4407, oder? Das kann doch kein Zufall sein!

Die Antwort ist, es ist nicht wirklich zufällig, sondern pseudo-zufällig. Sonic Pi liefert Dir Reihenfolgen von Zufallszahlen, die wiederholbar sind. Das ist sehr nützlich, denn so ist sichergestellt, dass die Musik von Deinem Rechner auf anderen Rechnern identisch klingt - sogar dann, wenn Du einen Zufallsfaktor einbaust.

Klar, wenn in einem bestimmten Musikstück jedesmal die 77.4407 als ‘zufällige’ Zahl gewählt würde, dann wäre das nicht besonders interessant. Aber so ist es auch nicht. Versuch’ folgendes:

loop do
  play rrand(50, 100)
  sleep 0.5
end 

Jawohl! Nun klingt es zufällig. Innerhalb eines bestimmten Code-Durchgangs liefern Aufrufe von Zufallsfunktionen auch zufällige Werte. Der nächste Durchgang wird jedoch genau die selbe Folge von Zufallswerten liefern und also auch genau gleich klingen. Es ist, als ob der Code immer zu demselben Zeitpunkt zurückspringt, wenn der Ausführen-Button geklickt wird. Es ist der Groundhog-Day2 der musikalischen Synthese.

Ruhelose Glocken

Ein großartiges Beispiel von Zufall in Aktion bietet der “Haunted Bells”-Code. Die “ruhelosen Glocken” spielen das Sample :perc_bell mit einer zufälligen Samplerate und Pausenzeit in einer Endlosschleife3 ab:

loop do
  sample :perc_bell, rate: (rrand 0.125, 1.5)
  sleep rrand(0.2, 2)
end

Zufällig abschneiden (random cutoff)

Ein anderes spannendes Beispiel für die Randomisierung ist das zufällige Abschneiden4 eines Synth-Klangs. Der :tb303-Emulator ist ein guter Synth, um das auszuprobieren:

use_synth :tb303

loop do
  play 50, release: 0.1, cutoff: rrand(60, 120)
  sleep 0.125
  end

Startpunkt der Zufallsfolge (random seed)

Was aber, wenn Du die Abfolge von Zufallszahlen, die Sonic Pi Dir liefert, nicht magst? Nun, mit use_random_seed5 kannst Du unterschiedliche Startpunkte für diese Folge angeben. Der Standard-Startpunkt ist die 0. Wähle also einfach einen anderen Startpunkt und mache eine andere Zufallserfahrung!

Sieh Dir den folgenden Code an:

5.times do
  play rrand(50, 100)
  sleep 0.5
end

Jedes Mal, wenn Du den Code ablaufen läßt, hörst Du dieselbe Folge von 5 Tönen. Um eine andere Folge zu bekommen, setze einfach einen anderen Startpunkt:

use_random_seed 40
5.times do
  play rrand(50, 100)
  sleep 0.5
end

Nun produziert Sonic Pi eine andere Folge von 5 Tönen. Indem Du den Startpunkt wechselst und Dir die Ergebnisse anhörst, kannst Du eine Folge finden, die Dir gefällt - und wenn Du den Code dann an andere weitergibst, werden sie genau das hören, was auch Du gehört hast.

Schauen wir uns noch eine andere nützlich Zufallsfunktion an.

Auswählen (choose)

Häufig kommt es vor, dass man aus einer Liste von Dingen eines zufällig auswählen möchte. Zum Beispiel möchte ich einen Ton aus der folgenden Liste auswählen: 60, 65 oder 72. Dafür ist choose da. Zuerst musst Du Deine Zahlen in eine Liste packen; dafür schreibst Du sie jeweils durch Kommata getrennt in eckige Klammern. Dann übergibst Du diese Liste dem Kommando choose:

choose([60, 65, 72])

Hören wir uns das an:

loop do
  play choose([60, 65, 72])
  sleep 1
end

rrand

rrand haben wir schon kennengelernt, aber sehen wir uns das noch einmal genauer an. Es liefert eine zufällige Zahl zwischen zwei Werten, aber ohne diese Werte selbst; man sagt auch exklusiv dieser beiden Werte. Das bedeutet, dass sowohl der minimale als auch der maximale Wert niemals ausgegeben werden, immer nur eine Zahl zwischen diesen beiden Werten. Die Zahl wird immer eine Gleitkommazahl (engl. Float) sein, also keine ganze Zahl, sondern eine mit einem Komma6. Einige Beispiele für Gleitkommazahlen, die der wiederholte Aufruf von rrand(20, 110) ausgeben könnte:

rrand_i

Manchmal braucht man eine zufällige aber ganze Zahl, eben keine Gleitkommazahl. Hier rettet einen rrand_i7. Es funktioniert ähnlich rrand, kann jedoch auch den minimalen oder maximalen Wert, den man übergeben hat, als mögliche Zufallszahl auswählen (man kann auch sagen: es ist inklusiv, also nicht exklusive der Werte, mit denen man den Bereich für die Auswahl festgelegt hat). rrand_i(20, 110) könnte zum Beispiel die folgenden Werte ausgeben:

rand

rand gibt eine zufällige Gleitkommazahl zwischen 0 (inklusiv) und einem übergebenen Maximalwert (exklusiv) zurück. Standardmäßig - wenn also kein Maximalwert angegeben wird - wird ein Wert zwischen 0 und 1 geliefert. Deshalb kann man rand gut dafür gebrauchen, zufällige Werte für amp: (also die Lautstärke) auszuwählen.

loop do
  play 60, amp: rand
  sleep 0.25
end

rand_i

Ähnlich wie bei rrand_i und rrand, wählt rand_i eine ganze Zahl zwischen 0 und einem angegebenen Maximalwert aus.

dice

Manchmal möchte man so tun, als würde man würfeln (engl. to dice) - das ist ein Sonderfall von rrand_i, wobei der kleinste Wert immer die 1 ist. Wenn man dice verwendet, muss man dabei immer bestimmen, wieviele Seiten der Würfel hat. Ein normaler Würfel hat 6 Seiten, also wird dice(6) entsprechend funktionieren und den Wert 1, 2, 3, 4, 5 oder 6 zurückgeben. Aber - angenommen wir befänden uns in einen Fantasy-Rollenspiel - ist es Dir vielleicht lieber, wenn der Würfel 4 oder 12, 20 oder sogar 120 Seiten hat!?

one_in

Schließlich könnte es sein, das Du so tun willst, als ob Du beim Würfeln eine 6 hast - also den höchten Wert erreichst. one_in gibt - mit einer Wahrscheinlichkeit 1 im Verhältnis zur Menge der Würfelseiten - den Wert wahr (engl. true) zurück, falls die höchste Zahl gewürfelt wurde. one_in(6) wird also mit einer Wahrscheinlichkeit von 1 zu 6 wahr, ansonsten falsch (engl. false). Wahr- und Falsch-Werte sind sehr nützlich, wenn es um if-Anweisungen geht, die wir in einem folgenden Kapitel dieses Tutorials besprechen.

Jetzt los, bring’ Deinen Code mit ein paar Zufälligkeiten durcheinander!

  1. Randomisierung (engl. Randomisation) bedeutet hier, dass man eine Auswahl von Zahlen zufällig gestaltet, also jedesmal eine andere Zahl bekommt.

  2. Im Film Groundhog Day (deutsch: Und täglich grüßt das Murmeltier) erlebt Bill Murray immer wieder denselben Tag.

  3. Ein Schleife wird mit dem Ausdruck loop eingeleitet. Alles was innerhalb der Schleife steht, wird so oft wie angegeben oder unendlich oft wiederholt.

  4. In Sonic Pi wird das das Abschneiden oder Verkürzen mit dem Ausdruck cutoff bezeichnet.

  5. Das englische Wort Seed bedeutet im Deutschen Keim oder Samen; hier wird es als Startpunkt übersetzt.

  6. Die Sache wird noch dadurch ein wenig komplizierter, dass im Englischen anstelle eines Kommas ein Punkt steht. Die Gleitkommazahl 5,978 ist also im Englischen die Floating Point Number (kurz: Float) 5.978. Alle Zahlen mit Kommawerten werden also in Sonic Pi mit einem Punkt dargestellt.

  7. Das kleine i in rrand_i steht für englisch Integer als eine ganze Zahl im Unterschied zu den Gleitkommazahlen.


5 - Programmstrukturen

Jetzt kennst Du schon die wichtigsten Grundlagen. Du weißt, wie man Klänge mit play und sample erzeugt, und kannst einfache Melodien und Rhythmen bauen, indem Du sleep zwischen die Klänge setzt. Du fragst Dich nun vielleicht, was Dir die Welt des Codes noch alles zu bieten hat…

Ich denke, da kommen noch einige tolle Sachen auf Dich zu! Du wirst sehen, dass grundlegende Programmstrukturen wie Schleifen, Bedingungen, Funktionen und Threads großartige Werkzeuge sind, wenn Du Deine musikalischen Ideen ausdrücken willst.

Sehen wir uns also die Grundlagen an…


5.1 - Blocks

Eine Struktur, die man häufig in Sonic Pi sieht, ist der Block. Blocks erlauben uns, nützliche Dinge mit größeren Codeabschnitten zu tun. Mit Synth- oder Sample-Parametern konnten wir etwas ändern, was in einer Codezeile geschah. Manchmal aber möchten wir etwas mit einer ganzen Reihe von Codezeilen anstellen. Zum Beispiel möchten wir diese in einer Schleife ablaufen lassen, Hall hinzufügen, bei vorgegebenen Wiederholungen nur eine von fünf ablaufen lassen etc. Schau Dir den folgenden Code an:

play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62

Um etwas mit einem mehrzeiligen Codestück zu tun, müssen wir Sonic Pi sagen, wo der Code-Block anfängt, und wo er aufhört. Dazu verwenden wir do für den Anfang und end für das Ende. So zum Beispiel:

do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Das ist aber noch nicht alles und wird so nicht funktionieren (versuche es und Du wirst einen Fehler erhalten), weil wir Sonic Pi noch nicht gesagt haben, was wir mit diesem do/end-Block machen wollen. Dafür setzen wir noch einen speziellen Ausdruck vor das do. Solche Ausdrücke werden wir in diesem Tutorial gleich kennenlernen. Zunächst einmal ist wichtig, dass wir mehrere Codezeilen mit do und end zusammenfassen und Sonic Pi sagen können, dass wir mit diesem Codestück etwas Bestimmtes machen wollen.


5.2 - Iteration und Schleifen

Bislang haben wir einige Zeit damit verbracht, uns unterschiedliche Klänge anzusehen, die Du mit play und sample erzeugen kannst. Wir haben auch gelernt, wie Du den Ablauf dieser Klänge mit sleep steuern kannst.

Wahrscheinlich hast Du entdeckt, dass man mit diesen Grundbausteinen schon vieles bauen kann. Eine ganz neue Dimension eröffnet sich jedoch, wenn wir beginnen, die Musik und die Kompositionen über den Code weitergehend zu strukturieren. In den nächsten Abschnitten schauen wir einige wirkungsvolle neue Werkzeuge dafür an. Als erstes kommen die Iteration und die Schleife (engl. Loop) dran.

Wiederholung

Möchtest Du Code, den Du geschrieben hast, einige Male wiederholen? Zum Beispiel hast Du vielleicht ungefähr so etwas:

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

Was, wenn Du das drei Mal wiederholen wolltest? Naja, die Lösung ist einfach! Du kannst den Code kopieren und drei Mal hintereinander einfügen:

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

Das ist natürlich eine Menge Code! Was wäre, wenn Du das Sample in :elec_plip umändern wolltest? Du müsstest alle Stellen mit :elec_blub finden und ändern. Und weiter: Was, wenn Du das ursprüngliche Codestück 50 oder 1000 Mal wiederholen wolltest? Das wäre noch mehr Code, und Du müsstest eine Menge Zeilen bearbeiten, wenn Du etwas ändern wolltest.

Iteration

Wenn man Code wiederholt ablaufen lassen wollte, müsste man eigentlich nur sagen: Mach’ das drei Mal. Und so ist es auch in etwa. Erinnerst Du Dich an unseren Freund, den Code-Block? Wir können damit den Anfang und das Ende des Codes markieren, den wir drei Mal wiederholen wollen. Dann benutzen wir den speziellen Ausdruck 3.times. Wir schreiben zwar nicht mach’ das drei Mal, wir schreiben 3.times do - also nicht besonders schwierig. Denk’ aber daran, ans Ende des zu wiederholenden Code-Blocks gehört ein end.

3.times do
  play 50
  sleep 0.5
  sample :elec_blup
  sleep 0.5
  play 62
  sleep 0.25
end

Na, ist das nicht viel eleganter als kopieren und einfügen? Wir können das gut gebrauchen, um eine Menge sich wiederholender Strukturen zu erzeugen.

4.times do
  play 50
  sleep 0.5
end

8.times do
  play 55, release: 0.2
  sleep 0.25
end

4.times do
  play 50
  sleep 0.5
end

Verschachtelte Iterationen

Wir können Iterationen in andere Iterationen hinein packen, um damit interessante Muster zu erzeugen. Zum Beispiel:

4.times do
  sample :drum_heavy_kick
  2.times do
    sample :elec_blip2, rate: 2
    sleep 0.25
  end
  sample :elec_snare
  4.times do
    sample :drum_tom_mid_soft
    sleep 0.125
  end
end

Schleifen

Wenn Du etwas sehr oft wiederholen möchtest, könnte es sein, dass Du mit sehr hohen Zahlen arbeiten musst, wie zum Beispiel 1000.times do. In einem solchen Fall macht es mehr Sinn, Sonic Pi dazu zu bringen, den Code in einer Endlos-Schleife zu wiederholen (zumindest, bis Du den Stopp-Button klickst!). Wiederholen wir den Amen Break unendlich oft:

loop do
  sample :loop_amen
  sleep sample_duration :loop_amen
end

Eine wichtige Sache bei Endlos-Schleifen ist, dass sie für den Code wie schwarze Löcher sind. Wenn der Code einmal in einer Endlos-Schleife läuft, kann er diese nicht mehr verlassen, bis Du auf Stopp klickst - ansonsten wird er für immer weiterlaufen. Das bedeutet, wenn hinter Deiner Endlos-Schleife noch weiterer Code steht, wirst Du diesen nie hören. Zum Beispiel wird das Becken hinter dieser Schleife nie spielen:

loop do
  play 50
  sleep 1
end

sample :drum_cymbal_open

Jetzt fang’ an und strukturiere Deinen Code mit Wiederholungen und Schleifen!


5.3 - Bedingungen

Wahrscheinlich willst Du häufig nicht nur einen einen zufälligen Ton abspielen (siehe das Kapitel über Zufallszahlen), sondern auch eine zufällige Entscheidung treffen: je nachdem wie diese ausfällt, möchtest Du dann den einen oder anderen Code ausführen. Zum Beispiel könnte es sein, dass Du zufällig entweder eine Trommel oder ein Becken anschlagen möchtest. Das können wir mit einem if-Ausdruck erreichen.

Wirf eine Münze

Werfen wir also ein Münze: bei Kopf, spiele eine Trommel, bei Zahl, ein Becken. Das ist leicht. Wir können den Münzwurf mit unserer one_in-Funktion nachbilden (eingeführt im Kapitel über Randomisierung), indem wir eine Wahrscheinlichkeit von 1 aus 2 angeben: one_in(2). Das Ergebnis dieser Berechnung benutzen wir, um zwischen zwei Codestücken auszuwählen, entweder den Code für die Trommel oder für das Becken:

loop do

  if one_in(2)
    sample :drum_heavy_kick
  else
    sample :drum_cymbal_closed
  end
  
  sleep 0.5
  
end

Denke daran, dass if-Anweisungen drei Teile haben:

Für Programmiersprachen typisch steht für das Ja der Ausdruck true (wahr) und für das Nein der Ausdruck false (falsch). Also müssen wir eine Frage finden, die uns eine Antwort gibt, die entweder wahr oder falsch ist; genau das erledigt im Beispiel one_in.

Beachte, dass die erste Wahl zwischen if und else und die zweite Wahl zwischen else und end eingeschlossen wird. So wie bei den do/end-Blöcken kannst Du beliebig viele Codezeilen an beide Stellen schreiben. Zum Beispiel:

loop do

  if one_in(2)
    sample :drum_heavy_kick
    sleep 0.5
  else
    sample :drum_cymbal_closed
    sleep 0.25
  end
  
end

Dieses Mal schläft der Klang unterschiedlich lange, je nachdem, welche Auswahl getroffen wird.

Einfaches if

Manchmal möchtest Du wahlweise nur eine Codezeile ausführen. Dafür hängst Du ein if und die Frage an das Ende der Codezeile, zum Beispiel:

use_synth :dsaw

loop do
  play 50, amp: 0.3, release: 2
  play 53, amp: 0.3, release: 2 if one_in(2)
  play 57, amp: 0.3, release: 2 if one_in(3)
  play 60, amp: 0.3, release: 2 if one_in(4)
  sleep 1.5
end

Dieses Beispiel setzt einen Akkord aus verschiedenen Noten zusammen, wobei die Chance, dass bestimmte Noten gespielt werden, eine unterschiedliche Wahrscheinlichkeit hat.


5.4 - 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 nicht mehr da 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

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

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’s aus, und Du wirst den Beat zusammen mit der Basslinie hören!

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 Tread:

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 Tread - kein anderer der laufenden Treads 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 unterschied? 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äßt. 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 ein Arbeitsfenster 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 simultan ablaufen.

Mit benannten Treads 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.


5.5 - Funktionen

Wenn Du einmal damit angefangen hast, mehr Code zu schreiben, dann wirst Du nach Wegen suchen, wie Du die Dinge organisieren und strukturieren kannst. Damit wird alles ordentlicher und einfacher zu verstehen. Funktionen sind sehr praktisch, um das zu erreichen. Sie geben uns die Möglichkeit, einem Bündel von Codezeilen einen Namen zu geben. Sehen wir uns das an.

Funktionen definieren

define :foo do
  play 50
  sleep 1
  play 55
  sleep 2
end

Hier haben wir eine neue Funktion mit dem Namen foo definiert. Wir machen das mit unserem alten Freund, dem do/end-Block und dem Zauberwort define gefolgt von dem Namen, den wir unserer Funktion geben möchten. Wir müssen die Funktion nicht unbedingt foo nennen, wir können sie auch irgendwie anders nennen; zum Beispiel bar, baz oder idealerweise einen für Dich bedeutsamen Namen wie main_section (etwa: Hauptteil) oder lead_riff (etwa: Leitfigur).

Denk’ daran, bei der Definition einer Funktion einen Doppelpunkt : vor ihren Namen zu stellen.

Funktionen aufrufen

Wenn wir unsere Funktion definiert haben, können wir sie einfach über ihren Namen aufrufen:

define :foo do
  play 50
  sleep 1
  play 55
  sleep 0.5
end

foo

sleep 1

2.times do
  foo
end

Wir können foo sogar in Iterations-Blocks aufrufen und überall da, wo wir auch play oder sample hätten benutzen können. Das gibt uns eine große Ausdrucksfreiheit und wir können sinnvolle Worte bilden, die wir in unseren Kompositionen verwenden.

Funktionen bleiben in Erinnerung

Wenn Du bislang den Ausführen-Button geklickt hast, startete Sonic Pi jedesmal aufs Neue ohne irgendwelche Vorgaben. Es berücksichtigt nichs, außer dem, was im jeweiligen Arbeitsfenster steht. Du kannst Dich nicht auf irgendwelchen Code beziehen, der in einem anderen Arbeitsfenster oder einem anderen Thread steht. Funktionen ändern das jedoch. Wenn Du eine Funktion definierst, dann erinnert sich Sonic Pi daran. Probieren wir das aus. Ersetze den den gesamten Code in Deinem Arbeitsfenster durch:

foo

Klick’ den Ausführen-Button und höre, wie Deine Funktion spielt. Wo wurde dieser Code gespeichert? Woher weiss Sonic Pi, was es zu spielen hat? Sonic Pi hat sich Deine Funktion einfach gemerkt. Also sogar, nachdem Du den Code aus dem Arbeitsfenster gelöscht hast, wusste Sonic Pi noch, was Du geschrieben hattest. Dies funktioniert nur mit Funktionen, die Du mit define (und defonce) definiert hast.

Funktionen parametrisieren

Du kannst Deinen Funktionen beibringen, Argumente zu übernehmen, genau so, wie Du z.B. rrand einen Minimal- und einen Maximalwert übergeben kannst. Sehen wir uns das an:

define :my_player do |n|
  play n
end

my_player 80
sleep 0.5
my_player 90

Das ist jetzt nicht besonders aufregend, zeigt aber, worum es hier geht. Wir haben unsere eigene Version von play mit dem Namen my_player erschaffen. Diese ist parametrisiert - sie akzeptiert also Argumente.

Die Parameter müssen nach dem do stehen, welches zum define des do/end-Blocks gehört; sie werden von senkrechten Strichen (auch: Verkettungszeichen) umgeben und durch Kommata getrennt. Du kannst beliebige Worte als Parameternamen verwenden.

Die Zauberei findet innerhalb des define-do/end-Blocks statt. Du kannst die Parameternamen so benutzen, als wären sie wirkliche Werte. In diesem Beispiel spiele ich den Ton n. Du kannst die Parameter als eine Art Versprechen ansehen, dass sie durch wirkliche Werte ersetzt werden, wenn der Code läuft. Das machst Du, indem Du der Funktion beim Aufruf einen Parameter mitgibst. Ich tue das hier mit my_player 80, um den Ton 80 zu spielen. Innerhalb der Funktionsdefinition wird n nun durch 80 ersetzt, sodass play n sich in play 80 verwandelt. Wenn ich die Funktion erneut mit my_player 90 aufrufe, wird n durch 90 ersetzt, sodass sich play n in play 90 verwandelt.

Sehen wir uns interessantere Beispiele an:

define :chord_player do |root, repeats| 
  repeats.times do
    play chord(root, :minor), release: 0.3
    sleep 0.5
  end
end

chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3

Hier habe ich repeats so benutzt, als ob es eine Zahl in der Zeile repeats.times do wäre. Zusätzlich habe ich roots so verwendet, als ob es ein Notenname im Aufruf play wäre.

Siehst Du? Unser Code wird sehr aussagekräftig und leichter lesbar, wenn wir eine Menge der Programmlogik in Funktionen verschieben.


5.6 - Variablen

Es ist sehr nützlich beim Coden, Namen für Dinge zu vergeben. Sonic Pi macht es Dir hier sehr leicht: Schreib’ einfach den Namen, den Du gerne verwenden möchtest, dann ein Gleichheitszeichen (=) und dann das Ding, welches Du Dir merken möchtest.

sample_name = :loop_amen

Hier haben wir uns das Symbol :loop_amen mit der Variable sample_name gemerkt. Wir können nun sample_name überall da benutzen, wo wir auch loop_amen benutzen könnten. Zum Beispiel:

sample_name = :loop_amen
sample sample_name

Es gibt drei Hauptgründe, Variablen in Sonic Pi zu nutzen: Bedeutung vermitteln, Wiederholung steuern und Ergebnisse von Dingen speichern.

Bedeutung vermitteln

Wenn Du Code schreibst, könnest Du denken, dass Du einfach nur dem Computer sagst, was er tun soll - solange der Computer das versteht, ist es okay. Es ist jedoch wichtig daran zu denken, dass nicht nur der Computer den Code liest. Andere Leute könnten den Code auch lesen und wollen verstehen, was da vor sich geht. Wahrscheinlich wirst Du den Code auch später selbst wieder lesen und möchtest verstehen, was er bedeutet. Obwohl Dir jetzt vielleicht alles offensichtlich erscheint - wahrscheinlich ist es für andere nicht ganz so offensichtlich und vielleicht nicht einmal für Dich in der Zukunft!

Kommentare sind eine Möglichkeit, anderen dabei zu helfen, Deinen Code zu verstehen. Weiterhin kannst Du sinnvolle Namen für Deine Variablen verwenden. Sie Dir diesen Code an:

sleep 1.7533

Warum steht hier die Zahl 1.7533. Woher kommt diese Zahl? Was bedeutet sie? Sieh Dir zum Vergleich diesen Code an:

loop_amen_duration = 1.7533
sleep loop_amen_duration

Aha, jetzt ist viel klarer, was 1.7533 bedeutet: Es ist die Dauer des Sample loop_amen! Natürlich kannst Du jetzt sagen, warum nicht einfach schreiben:

sleep sample_duration(:loop_amen)

Das ist natürlich auch ein sehr guter Weg, die Absicht mitzuteilen, die hinter dem Code steht.

Wiederholungen steuern

In Deinem Code wirst Du oft Dinge wiederholen, und wenn Du irgendwo etwas ändern willst, musst Du das an vielen Stellen tun. Schau Dir mal diesen Code an:

sample :loop_amen
sleep sample_duration(:loop_amen)
sample :loop_amen, rate: 0.5
sleep sample_duration(:loop_amen, rate: 0.5)
sample :loop_amen
sleep sample_duration(:loop_amen)

Hier machen wir eine ganze Menge mit dem :loop_amen! Was wäre, wenn Du das Ganze mit einem anderen Loop-Sample wie zum Beispiel :loop_garzul hören wollten? Wir müssten alle :loop_amen suchen und mit :loop_garzul ersetzen. Das mag in Ordnung sein, wenn Du viel Zeit hast - aber was, wenn Du gerade auf einer Bühne stehst? Manchmal hast Du nicht den Luxus, Zeit zu haben - vor allem dann nicht, wenn Du willst, dass die Leute weitertanzen.

Was wäre, wenn Du den Code so geschrieben hättest:

sample_name = :loop_amen
sample sample_name
sleep sample_duration(sample_name)
sample sample_name, rate: 0.5
sleep sample_duration(sample_name, rate: 0.5)
sample sample_name
sleep sample_duration(sample_name)

Das tut genau dasselbe wie der Code weiter oben (probier’s aus). Außerdem bekommen wir die Möglichkeit, durch die Änderung der einen Zeile sample_name = :loop_amen in sample_name = :loop_garzul die vielen anderen Stellen durch die Magie der Variablen zu verändern.

Ergebnisse von Dingen speichern

Wenn man schließlich die Ergebnisse von irgendwelchen Dingen speichern möchte, dann ist das ebenfalls ein guter Grund dafür, Variablen zu verwenden. Du möchtest vielleicht irgendetwas mit der Dauer eines Sample anstellen:

sd = sample_duration(:loop_amen)

Wir können nun sd überall da einsetzen, wo wir die Länge von :loop_amen brauchen.

Noch wichtiger vielleicht: Eine Variable erlaubt es uns, das Ergebnis eines Aufrufs von play oder sample zu speichern:

s = play 50, release: 8

Jetzt haben wir s als Variable eingefangen und gemerkt. Und das erlaubt es uns, einen Synth zu steuern während er läuft:

s = play 50, release: 8
sleep 2
control s, note: 62

Das nur als kleine Vorschau, wie man Synths steuert. Später schauen wir uns das noch genauer an.


5.7 - Synchronisation von Threads

Bald wirst Du ausreichend vertraut damit sein, live mit einer Anzahl von gleichzeitig ablaufenden Funktionen und Threads zu coden. Dann wirst Du bemerken, dass es ziemlich leicht ist, einen einzelnen Thread mit einem Fehler zum Abbruch zu bringen. Das ist nicht weiter schlimm, da Du den Thread mit einem Klick auf Ausführen ja einfach neu starten kannst. Wenn Du den Thread aber neu startest, dann läuft er nicht mehr zusammen mit den anderen so wie vorher, er ist nun aus dem Takt mit den ursprünglichen Threads.

Vererbte Zeit

Wir haben zuvor erwähnt, dass neue Threads beim Start mit in_thread alle ihre Einstellungen vom Eltern-Thread erben. Das schließt auch die aktuelle Zeit mit ein. Das bedeutet, dass Threads bei gleichzeitigem Start immer miteinander im Takt sind.

Wenn Du aber einen Thread alleine startest, spielt er in seinem eigenen Takt, der höchstwahrscheinlich nicht mit irgendeinem der anderen laufenden Threads zusammenpasst.

Cue und Sync

Sonic Pi hat mit den Funktionen cue und sync eine Lösung für dieses Problem.

cue erlaubt es uns, regelmäßige Signale an alle anderen Threads mit einem Taktgeber zu versenden. Standardmäßig sind die anderen Threads an solchen Signale nicht interessiert und werden sie ignorieren. Mit der sync-Funktion kann man jedoch erreichen, dass ein anderer Thread auf diesen Taktgeber hört.

Eine wichtige Sache, derer man sich bewusst sein sollte: sync ist so ähnlich sleep, weil es den aktuellen Thread für eine bestimmte Zeit anhält und dieser so lange nichts tut. Allerdings sagt man mit sleep, wie lange man warten möchte, während man bei sync nicht weiss, wie lange gewartet wird - denn sync wartet auf das nächste cue eines anderen Threads; das kann kürzer oder länger dauern.

Sehen wir uns das etwas genauer an:

in_thread do
  loop do
    cue :tick
    sleep 1
  end
end

in_thread do
  loop do
    sync :tick
    sample :drum_heavy_kick
  end
end

Hier haben wir zwei Threads - einer davon arbeitet wie ein Metronom; er spielt nichts, aber sendet bei jedem Schlag ein :tick-Taktgebersignal. Der zweite Thread synchronisiert sich mit den tick-Signalen, und wenn er eins davon erhält, übernimmt er die Zeit vom cue-Thread und läuft weiter.

Als Ergebnis hören wir den :drum_heavy_kick Sample genau dann, wenn der andere Thread ein :tick-Signal sendet, auch dann, wenn beide Threads gar nicht zur selben Zeit gestartet sind.

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

Dieser freche (zweite) Aufruf von sleep würde eigentlich den zweiten Thread gegenüber dem ersten aus dem Takt bringen. Weil wir aber cue und sync verwenden, synchronisieren wir beide Threads automatisch und umgehen dabei, dass beide in der Zeit auseinanderfallen.

Cue benennen

Du kannst cue-Signale benennen, wie Du willst - nicht nur mit :tick. Du musst nur sicherstellen, dass irgendein anderer Thread sich mit eben diesem Namen synchronisiert - ansonsten wartet der zweite Thread dann für immer (oder jedenfalls bis Du den Stopp-Button klickst).

Lasst uns ein paar Namen für cue ausprobieren:

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

Hier haben wir eine cue-Hauptschleife, die auf Zufallsbasis einen von drei Namen des Taktgebers :foo, :bar oder :baz aussendet. Wir haben auch drei Schleifen-Threads, die jeder für sich mit einem der Namen synchronisiert werden und dann jeweils ein anderes Sample spielen. Im Endeffekt hören wir bei jedem halben Schlag einen Klang, da jeder der sync-Threads auf Zufallsbasis mit dem cue-Thread synchronisiert ist, und sein Sample spielt, wenn er dran ist.

Das funktioniert natürlich auch, wenn Du die Reihenfolge der Threads umkehrst: Die die sync-Threads sitzen einfach da und warten auf ihren nächsten cue.


6 - Studio-Klangeffekte

Es lohnt sich, mit Sonic Pi Deine Klänge mit Studio-Effekten zu verändern - Du wirst sehen, wie spannend das ist und wieviel Spaß das macht. Zum Beispiel kannst Du zu Teilen Deiner Komposition Hall-Effekte (‘Reverb’) hinzufügen. Oder etwas Echo (‘Echo’). Oder vielleicht möchtest Du Deine Bassmelodien verzerren (‘Distortion’) oder schwabbeln lassen (‘Wobble’).

Sonic Pi kannst Du sehr mächtige Klangeffekte auf ganz einfache Art einfügen. Du kannst sie sogar miteinander verketten oder sie ineinander verschachteln (zum Beispiel könntest Du einen Ton zuerst verzerren, dann Echo hinzufügen und zum Schluss noch etwas Hall). Jede individuelle Effekteinheit lässt sich mit Parametern steuern (ganz ähnlich, wie sich auch Synths und Samples steuern lassen). Du kannst sogar die Parameter eines Klangeffektes ändern, während der Effekt läuft. Zum Beispiel könntest Du den Halleffekt Deiner Bassmelodie während des Stückes langsam anheben.

Gitarreneffekte

Wenn sich das alles etwas kompliziert anhören sollte - keine Sorge! Spiel ein bisschen mit den Effekten herum und es wird Dir ganz schnell alles viel einfacher vorkommen. Bevor Du loslegst, könnte dieser kleine Vergleich nützlich sein: Die Effekte in Sonic Pi funktionieren so ähnlich wie Gitarreneffektpedale. Es gibt eine Vielzahl von solchen Effektpedalen zu kaufen. Manche Gitarristen benutzen gerne Hall-Effekte (‘Reverb’), andere bevorzugen ein Verzerrerpedal (‘Distortion’), etc. Als Gitarrist kann man einfach seine Gitarre an ein Effektpedal anstecken - z.B. ‘Distortion’ - und dann mit einem weiteren Kabel noch ein Hallpedal anhängen. So entsteht eine Kette von Effekten. Das Ausgangssignal des Hall-Effektpedals am Ende der Kette kann man dann in einen Verstärker leiten:

Gitarre -> Verzerrer -> Hall -> Verstärker

Man nennt diese Vorgehensweise ‘Effektverkettung’. Und genau das kannst Du mit Sonic Pi machen. Jedes Effektpedal hat normalerweise einige Drehknöpfe und Schalter, mit denen man exakt steuern kann, wieviel Verzerrung, Hall, oder Echo erzeugt werden soll. Und eines noch zum Schluss: Du kannst Dir sicher vorstellen, dass ein Gitarisst mit Gitarrespielen beschäftigt sein könnte, während jemand anderes die Effekte steuert. Das ist auch bei Sonic Pi möglich - aber anstatt auf jemand anderen dafür angewiesen zu sein, steht für Dich Dein Computer am Effektmischer und hilft Dir.

Aber jetzt ist es höchste Zeit, die Effektfunktionen auszuprobieren!


6.1 - FX hinzufügen

In diesem Abschnitt sehen wir uns zwei Effekte genauer an: Hall und Echo. Wir werden lernen, wie diese Effekte zu benutzen sind, wie man ihre Parameter steuern kann, und wie man sie verketten kann.

Das FX-System von Sonic Pi benutzt sogenannte Code-Blocks. Falls Du Abschnitt 5.1 des Tutorials noch nicht gelesen hast, sieh es Dir doch kurz an und kehre dann hierher zurück.

Hall (‘Reverb’)

Um den Hall-Effekt zu benutzen, fügen wir with_fx :reverb als Spezialcode zu unserem bestehenden Code-Block hinzu. Und zwar so:

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Wenn Du nun diesen Code-Block abspielst, wirst Du hören, dass der Hall-Effekt hinzugefügt wurde. Hört sich gut an, nicht wahr! Mit Hall-Effekt hört sich alles immer ziemlich gut an.

Aber was passiert, wenn wir den Code außerhalb des do/end-Code-Blocks hinzufügen:

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

sleep 1
play 55

Wie Du sicher bemerkt hast, wird nun die letzte Note (55) nicht mehr mit Hall-Effekt abgespielt. Der Grund dafür ist, dass sich die Note ausserhalb des do/end Code-Blocks befindet und deshalb unsere Anweisung zum Hall-Effekt für sie nicht mehr gültig ist.

Wenn Du Noten vor dem do/end-Code-Block einfügst, verhält es sich ganz ähnlich, und sie werden ebenfalls ohne Hall-Effekt abgespielt:

play 55
sleep 1

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

sleep 1
play 55

Echo

Es stehen noch viele weitere Effekte zur Auswahl. Wie wäre es zum Beispiel mit etwas Echo?

with_fx :echo do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Die FX-Blocks von Sonic Pi sind besonders vielfältig einsetzbar, denn sie lassen sich über Parameter steuern. Genauso wie die Befehle play und sample, die wir ja schon kennen. Ein spannender Echo-Parameter ist zum Beispiel phase:. Dieser Parameter stellt die Dauer des Echos in Schlägen dar. Versuchen wir, das Echo etwas langsamer zu machen:

with_fx :echo, phase: 0.5 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Und jetzt lass uns das Echo wieder schneller machen:

with_fx :echo, phase: 0.125 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Wie wäre es nun mit einem langsam ausschwingenden Echo? Wir können dafür einfach den decay:-Wert auf 8 Schläge verlängern:

with_fx :echo, phase: 0.5, decay: 8 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

FX verschachteln

Interessant wird es, wenn wir die FX-Blocks ineinander verschachteln. So können eine Vielzahl verschiedener FX leicht verkettet werden. Wie wäre es zum Beispiel damit, einen Code-Block zuerst mit Echo und dann mit Hall zu versehen? Das geht ganz einfach, Du musst nur die beiden Code-Blocks ineinander verschachteln:

with_fx :reverb do
  with_fx :echo, phase: 0.5, decay: 8 do
    play 50
    sleep 0.5
    sample :elec_blup
    sleep 0.5
    play 62
  end
end

Stell Dir das so vor, als ob die erzeugten Klänge von innen nach außen fließen würden. Der erzeugte Klang des innersten do/end-Code-Blocks (zum Beispiel ‘play 50’) wird zuerst durch den Echo-FX-Block gesendet, und danach noch durch den Hall-FX-Block.

Es ist ganz einfach, mit vielschichtigen Verschachtelungen verrückte Ergebnisse zu erzielen. Aber sei vorsichtig, weil FX viel Rechenkraft des Computers verbraucht, besonders dann, wenn Du mehrere FX zugleich benutzt. Sei also etwas sparsam mit Deinen FX, wenn Du mit eher rechenschwachen Geräten wie dem Raspberry Pi arbeitest.

Weitere FX entdecken

Sonic Pi bringt eine Vielzahl von FX mit, die Du ausprobieren kannst. Eine komplette Liste findest Du im Hilfe-Fenster, wenn Du dort links auf ‘FX’ klickst. Hier sind einige meiner Favoriten:

Jetzt aber los, mach was verücktes und baue überall in Deinem Code FX ein. Du wirst unglaubliche neue Klänge erzeugen!


6.2 - FX Praxis

Auf den ersten Blick mögen die Effekte von Sonic Pi sehr einfach aussehen, aber in Wirklichkeit sind sie höchst komplexe Gebilde. Ihre scheinbare Einfachheit verleitet manche dazu, zu viele FX in ihre Projekte einzubauen. Das kann durchaus Spaß machen, wenn Du über einen sehr starken Computer hast. Aber falls Du - so wie ich - einen einfachen Raspberry Pi zum Musikmachen benutzt, musst Du darauf achten, die Maschine nicht zu überlasten. Nur so kannst Du sicher gehen, dass Sonic Pi ordentlich funktioniert und im Takt bleibt.

Sie Dir den folgenden Code an:

loop do
  with_fx :reverb do
    play 60, release: 0.1
    sleep 0.125
  end
end

Hier spielen wir die Note 60 mit sehr kurzem release:-Wert, und erzeugen so einen sehr kurzen Ton. Wir wollen außerdem einen Hall-Effekt, und haben deshalb den notwendigen Code-Block außen herum geschrieben. Soweit sieht alles gut aus. Oder doch nicht?

Sehen wir uns genauer an, was der Code hier macht. Zuerst einmal haben wir einen Loop, und wie wir ja schon wissen wird alles, was innerhalb der Endlosschleife geschrieben ist, für immer und ewig wiederholt. Außerdem haben wir einen with_fx:-do/end-Block. Das bedeutet, dass bei jeder Wiederholung des Loops ein neuer Hall-Effekt erzeugt wird. Das ist so, als ob wir jedes Mal, wenn wir eine Gitarrenseite zupfen, ein neues Pedal an die Effektkette hängen würden. Es ist ja ganz nett, das wir das machen können, aber es ist möglicherweise nicht das, was wir eigentlich wollen. Ein kleiner Raspberry Pi wird an diesem Code schwer zu arbeiten haben. Die with_fx:-Funktion erledigt die ganze Arbeit, bei jeder Wiederholung des Loops den Hall-Effekt zu erzeugen, dann zu warten, und dann den Effekt wieder zu entfernen, aber insgesamt werden dabei wertvolle CPU Ressourcen verbraucht.

Wie können wir einen ähnlichen Code-Block schreiben, bei dem unser Gitarrist nur ein einzelnes Hall-Effektpedal zur Klangerzeugung benutzt? Ganz einfach:

with_fx :reverb do
  loop do
    play 60, release: 0.1
    sleep 0.125
  end
end

Nun haben wir unseren Loop ins Innere des with_fx:-Blocks verpackt. So wird nur noch ein einziger Hall-Effekt erzeugt und auf alle Noten im Loop angewandt. Dieser Code-Block ist viel effizienter und wird auf jedem Raspberry Pi gut funktionieren.

Als Kompromiss könnten wir with_fx: auch als ‘iteration’ innerhalb eines Loops schreiben:

loop do
  with_fx :reverb do
    16.times do
      play 60, release: 0.1
      sleep 0.125
    end
  end
end

Somit wird die with_fx:-Funktion aus dem Inneren des Loops geholt, und der Code erzeugt jetzt nur noch einen Hall-Effekt alle 16 Noten.

Denk daran, man kann nichts falsch machen, dafür aber unendlich viele Varianten ausprobieren! Jede dieser Varianten wird sich jedoch ein bisschen anders anhören, und jeweils mehr oder weniger gut funktionieren. Es ist also empfehlenswert, so viel wie möglich zu experimentieren, bis Du die Variante gefunden hast, die am besten funktioniert und den Einschränkungen Deines Computers am besten gerecht wird.


7 - Laufende Sounds steuern

Bisher haben wir uns angeschaut, wie man Synths und Samples starten und ihre Standard-Einstellungen wie Lautstärke, Position im Stereofeld, Hüllkurven und so weiter anpassen kann. Jeder abgespielte Ton ist im Grunde genommen ein eigener Klang mit seinen eigenen Parametern für seine Abspieldauer.

Wäre es nicht cool, wenn man diese Parameter verändern könnte - während der Ton noch abgespielt wird? Etwa so, wie Du eine noch schwingende Saite beim Gitarrespielen ziehen kannst?

Glück gehabt - dieses Kapitel wird Dir genau das zeigen.


7.1 - Laufende Synths steuern

Bisher haben wir uns nur damit befasst, neue Sounds und Effekte zu starten.

Mit Sonic Pi kannst Du aber auch laufende Klänge steuern und verändern. Um das zu tun, speichern wir die Referenz zu einem Synth in einer Variable:

s = play 60, release: 5

Jetzt haben wir eine run-local Variable s. Sie repräsentiert einen Synth, der die Note 60 spielt. Beachte, dass diese Variable eine lokale ist - Du kannst nicht von anderen Runs, wie beispielsweise Funktionen, auf sie zugreifen.

Sobald wir die Referenz in der Variable s haben, können wir den Synth mit Hilfe der control-Funktion steuern:

s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

Wichtig ist hier, dass wir nicht vier verschiedene Synths starten - wir starten einen einzigen und ändern danach dreimal die Tonhöhe, während er noch spielt.

Wir können jeden der Standard-Parameter an die control-Funktion übergeben. Das erlaubt Dir, Dinge wie amp:, cutoff: oder pan: zu kontrollieren.

Nicht-kontrollierbare Parameter

Manche Parameter lassen sich nach dem Start des Synths nicht mehr verändern. Das trifft auf alle ADSR-Hüllkurven-Parameter zu. Welche Parameter kontrollierbar sind, kannst Du in der Dokumentation im Hilfe-System herausfinden. Parameter, die mit Can not be changed once set markiert sind, lassen sich nach dem Synth-Start nicht mehr verändern.


7.2 - Effekte steuern

Man kann auch Effekte steuern, allerdings geht das ein wenig anders:

with_fx :reverb do |r|
  play 50
  sleep 0.5
  control r, mix: 0.7
  play 55
  sleep 1
  control r, mix: 0.9
  sleep 1
  play 62
end

Statt eine Variable zu verwenden, nutzen wir die senkrechten Striche des do/end-Blocks. Innerhalb der Striche |, müssen wir einen eindeutigen Namen für unseren laufenden Effekt vergeben, den wir dann innerhalb des do/end-Blocks verwenden. Dieses Verhalten ist das gleiche wie bei parametrisierten Funktionen.

Jetzt los - steuere ein paar Synths und Effekte!


7.3 - Gleitende Parameter

Vielleicht ist Dir beim Erforschen der Synth- und FX-Argumente aufgefallen, dass manche Parameter mit _slide enden. Vielleicht hast Du sie sogar ausprobiert und keine Auswirkung bemerkt. Das liegt daran, dass dies keine normalen Parameter sind. Diese besonderen Parameter funktionieren nur dann, wenn Du Synths wie im letzten Kapitel beschrieben steuerst.

Schau Dir das folgende Beispiel an:

s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

Hier kannst Du hören, wie sich die Tonhöhe unmittelbar bei jedem Aufruf von control ändert. Vielleicht möchtest Du aber, dass die Tonhöhe sich gleitend zwischen den Aufrufen verändert. Um dort, wo wir den Parameter note: verwenden, gleitende Übergänge hinzuzufügen, nutzen wir den note_slide:-Parameter des Synth:

s = play 60, release: 5, note_slide: 1
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

Jetzt hören wir, wie die Noten zwischen den control-Aufrufen “gezogen” werden. Hört sich gut an, oder? Mit einer kürzeren Dauer wie beispielsweise note_slide: 0,2 kannst Du den Übergang beschleunigen. Oder ihn mit einer längeren Slide-Dauer verlangsamen.

Jeder steuerbare Parameter hat einen entsprechenden _slide-Parameter, mit dem Du spielen kannst.

Gleiten ist klebrig

Nachdem Du einmal einen _slide Parameter auf einem laufenden Synth angegeben hast, bleibt er bestehen und wird jedesmal genutzt, wenn Du den entsprechenden Parameter steuerst. Um das Gleiten auszuschalten, musst Du den _slide Wert vor dem nächsten control-Aufruf auf 0 setzen.

Gleitende Effekt-Parameter

Genauso ist es möglich, Effekt-Parameter gleiten zu lassen:

with_fx :wobble, phase: 1, phase_slide: 5 do |e|
  use_synth :dsaw
  play 50, release: 5
  control e, phase: 0.025
end

Und jetzt lass die Dinge ein wenig gleiten. Viel Spaß mit den weichen Übergängen…


8 - Datenstrukturen

Ein sehr praktisches Werkzeug im Werkzeugkasten jedes Programmierers sind Datenstrukturen.

Manchmal möchtest Du mehr als eine Sache darstellen oder verwenden. Es könnte beispielsweise nützlich sein, sich eine Reihe von Noten zu merken, um sie dann nacheinander abzuspielen. In Programmiersprachen sind Datenstrukturen genau für diesen Zweck da.

Es sind viele aufregende und exotische Datenstrukturen für Programmierer verfügbar - und es werden immer noch neue erfunden. Für unsere Zwecke benötigen wir vorerst jedoch nur eine sehr einfache Datenstruktur: Die Liste.

Lass uns das gleich im Detail anschauen. Wir werden uns die Grundform einer Liste anschauen und wie man sie verwendet, um Skalen und Akkorde abzubilden.


8.1 - Listen

In diesem Abschnitt werden wir uns eine sehr nützliche Datenstruktur anschauen - die Liste.

Wir hatten schon einmal in dem Abschnitt über Randomisierung kurz mit ihr zu tun, als wir die zu spielenden Noten zufällig aus einer Liste auswählten:

play choose([50, 55, 62])

In diesem Abschnitt erforschen wir, wie man Akkorde und Skalen mit Listen darstellen kann. Rufen wir uns wieder in Erinnerung, wie wir einen Akkord spielen könnten. Wenn wir sleep nicht verwenden, werden alle Töne zur gleichen Zeit abgespielt:

play 52
play 55
play 59

Wir können diesen Code aber auch anders schreiben.

Eine Liste abspielen

Eine Möglichkeit ist es, alle Noten aus einer Liste zu spielen: [52, 55, 59]. Unsere freundliche Funktion play ist schlau genug, um zu wissen, wie man eine Liste von Noten abspielt. Versuche es einmal:

play [52, 55, 59]

Prima, das kann man schon viel besser lesen. Das Abspielen einer Liste hindert uns aber nicht daran, die gewohnten Parameter zu verwenden:

play [52, 55, 59], amp: 0.3

Natürlich kannst Du auch die traditionellen Namen der Noten anstelle der MIDI-Nummern verwenden:

play [:E3, :G3, :B3]

Die Glücklichen unter Euch, die ein bisschen Musiktheorie gelernt haben, erkannten den Akkord vielleicht: Es ist E-Moll in der dritten Oktave.

Listenzugriffe

Sehr nützlich an Listen ist, dass man auf die enthaltenen Informationen zugreifen kann. Das klingt vielleicht seltsam, aber es ist nicht komplizierter als beispielsweise das Öffnen eines Buches auf der Seite 23. Eine Liste fragt man einfach “Was ist das Element am Index 23?”. Du musst Dir nur eine Merkwürdigkeit merken: Beim Programmieren beginnt man beim Zählen der Listenelemente normalerweise mit 0 statt mit 1.

Listenindizes zählen wir also nicht 1,2,3,… sondern 0,1,2,…

Wir schauen uns das etwas genauer an. Nehmen wir diese Liste:

[52, 55, 59]

Nicht besonders beängstigend. Was ist das zweite Element dieser Liste? Natürlich, das ist 55. Das war einfach. Jetzt versuchen wir, ob wir nicht den Computer dazu bringen können, die Frage für uns zu beantworten:

puts [52, 55, 59][1]

Falls Du so etwas noch nie gesehen hast, mag das ein bisschen seltsam wirken. Aber vertrau mir, das ist nicht schwierig zu durchschauen. Die Zeile oben besteht aus drei Teilen: Dem Wort puts, unserer Liste 52, 55, 59 und unserem Index [1]. Als Erstes sagen wir puts, damit Sonic Pi die Antwort für uns ins Protokoll schreibt. Danach übergeben wir unsere Liste und am Ende den Index, mit dem wir nach dem zweiten Element der Liste fragen. Den Index müssen wir mit eckigen Klammern umschließen, und da wir bei 0 zu zählen beginnen, ist der Index des zweiten Elements 1. Wie hier unten:

# indexes:  0   1   2
           [52, 55, 59]

Versuche mal, den Code puts [52, 55, 59][1] auszuführen, dann wirst Du sehen, dass 55 im Protokoll erscheint. Ändere mal den Index 1 in einen anderen, probiere längere Listen aus und denke darüber nach, wie Du Listen in Deinem nächsten Code-Jam verwenden könntest. Welche Strukturen aus der Musik könnte man denn als eine Reihe von Zahlen interpretieren?


8.2 - Akkorde

Sonic Pi kann Dir den Namen eines Akkords in eine Liste seiner Töne übersetzen. Versuche es selbst:

play chord(:E3, :minor)

Jetzt tut sich was. Das sieht doch schon viel schöner aus als einfache Listen (und ist für andere viel einfacher lesbar). Welche Akkorde kennt Sonic Pi noch? Naja, viele. Probier mal ein paar von diesen aus:

Arpeggios

Um Akkorde einfach in Arpeggios umzuwandeln, können wir die Funktion play_pattern verwenden:

play_pattern chord(:E3, :m7)

Ok, das war nichts besonderes - das ging wirklich langsam. play_pattern spielt jede Note in der Liste hintereinander, getrennt durch Aufrufe von sleep 1 ab. Wir können die Funktion play_pattern_timed verwenden, um unsere eigenen Zeitdauern zu verwenden und das Ganze zu beschleunigen:

play_pattern_timed chord(:E3, :m7), 0.25

Wir können sogar eine Liste von Dauern übergeben; Sonic Pi verwendet diese nacheinander und wiederholt sie solange wie notwendig:

play_pattern_timed chord(:E3, :m13), [0.25, 0.5]

Das bedeutet das gleiche wie:

play 52
sleep 0.25
play 55
sleep 0.5
play 59
sleep 0.25
play 62
sleep 0.5
play 66
sleep 0.25
play 69
sleep 0.5
play 73

Was würdest Du lieber schreiben?


8.3 - Skalen

Sonic Pi kennt eine große Anzahl von Skalen. Wie wäre es, eine C3-Dur-Skala zu spielen?

play_pattern_timed scale(:c3, :major), 0.125, release: 0.1

Wir können die Skala auch über mehrere Oktaven spielen lassen:

play_pattern_timed scale(:c3, :major, num_octaves: 3), 0.125, release: 0.1

Und wie wär’s mit allen Noten einer pentatonischen Tonleiter?

play_pattern_timed scale(:c3, :major_pentatonic, num_octaves: 3), 0.125, release: 0.1

Zufällige Noten

Akkorde und Skalen sind gute Methoden, eine zufällige Auswahl auf etwas von Bedeutung einzugrenzen. Spiele einmal mit diesem Beispiel, das zufällige Noten aus dem E-Moll-Akkord in der 3. Oktave auswählt:

use_synth :tb303
loop do
  play choose(chord(:E3, :minor)), release: 0.3, cutoff: rrand(60, 120)
  sleep 0.25
end

Probiere auch verschiedene Akkord-Namen und Cut-Off-Bereiche aus.

Akkorde und Skalen entdecken

Um herauszufinden, welche Skalen und Akkorde Sonic Pi unterstützt, klicke einfach auf den Lang-Button ganz auf der linke Seite dieses Tutorials und wähle entweder chord oder scale aus der API-Liste. Scrolle im Hauptfenster herunter, bist Du eine lange Liste von Akkorden oder Skalen findest.

Viel Spaß und nicht vergessen: Es gibt keine Fehler, nur Möglichkeiten.


8.4 - Ringe

Eine interessante Spielart von normalen Listen sind Ringe. Wenn Du ein bisschen Programmiererfahrung hast, könntest Du Ringspeicher (engl. ‘Ring Buffer’) oder Ring-Arrays kennen. Wir nennen die hier nur Ring - das ist kurz und einfach.

Im vorherigen Abschnitt über Listen haben wir gesehen, dass wir Elemente aus einer Liste über den Index holen können:

puts [52, 55, 59][1]

Was passiert jetzt wohl, wenn Du den Index 100 abfragen willst? Offensichtlich gibt es kein Element mit dem Index 100, da die Liste nur drei Elemente enthält. Also gibt Sonic Pi nil zurück, was “nichts” bedeutet. Stell Dir vor, einen Zähler wie den aktuellen Takt zu haben, der kontinuierlich wächst. Lass uns so einen Zähler und unsere Liste anlegen:

counter = 0
notes = [52, 55, 59]

Jetzt können wir mit unserem Zähler auf eine Note in unserer Liste zugreifen:

puts notes[counter]

Super, da kam 52 heraus. Jetzt erhöhen wir den Zähler (inc, die Abkürzung für englisch “to increment” = erhöhen) und bekommen damit eine neue Note:

counter = (inc counter)
puts notes[counter]

Ok, jetzt kommen 55 und beim nächsten Mal 59 heraus. Wenn wir das jedoch jetzt noch einmal machen, werden wir aber nicht mehr genug Zahlen in unserer Liste haben und werden stattdessen nil zurück bekommen. Was wäre, wenn wir dann einfach wieder vom Anfang der Liste anfangen wollten? Genau dafür gibt es Ringe.

Ringe erzeugen

Es gibt zwei Möglichkeiten, Ringe zu erzeugen. Die erste ist, die ring Funktion mit den gewünschten Elementen des Rings als Parameter zu verwenden:

(ring 52, 55, 59)

Die zweite Möglichkeit ist es, eine normale Liste mit der Nachricht .ring zu einem Ring umzuwandeln:

[52, 55, 59].ring

Auf Ringelemente zugreifen

Sobald wir einen Ring haben, können wir ihn auf die gleiche Art wie eine Liste verwenden. Die einzige Ausnahme ist, dass Du Indizes verwenden kannst, die negativ oder größer als der Ringinhalt sind. Diese fangen dann dann wieder am Anfang an, um immer auf ein Element des Rings zu zeigen:

(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59

Ringe verwenden

Angenommen, wir bilden die Nummer des aktuellen Takts in einer Variable ab. Diese Nummer können wir als Zugriffsindex für unseren Ring verwenden, um abzuspielende Note, Release-Zeiten oder andere sinnvolle Dinge, die wir in unserem Ring abgelegt haben, abzurufen.

Skalen und Akkorde sind Ringe

Gut zu wissen: Die Listen, die von scale und chord zurückgegeben werden, sind Ringe. Du kannst also mit beliebigen Indizes auf sie zuzugreifen.

Ring-Konstruktoren

Zusätzlich zu ring gibt es noch eine Anzahl weiterer Funktionen, die Ringe für uns erzeugen:

Mehr Informationen zu diesen Funktionen findest Du in der entsprechenden Dokumentation.


9 - Live-Coding

So, und jetzt wird es aufregend! Mit Sonic Pi kannst Du den Code für Deine Musik live schreiben und verändern. Du kannst also während eines Auftritts mit Sonic Pi live Musik machen - wie mit einer Gitarre.

Das Großartige daran ist, dass Du noch während des Komponierens sofort die Rückmeldung vom Publikum erhältst. Starte einen einfachen Loop und spiele daran herum, bis er genau richtig klingt. Der größte Vorteil ist aber, dass Du Sonic Pi bei einem Gig mit auf die Bühne nehmen kannst.

In diesem Abschnitt behandeln wir die Grundlagen, mit denen Du Deine Kompositionen von statischem Code in rasante Performances verwandeln kannst.

Halt Dich fest…


9.1 - Live-Coding

Inzwischen haben wir genug gelernt, nun können wir wirklich Spaß haben.

In diesem Abschnitt nutzen wir alles, was wir bisher in diesem Tutorial gelernt haben und zeigen Dir, wie Du Deine Kompositionen live aufführen und in Performances verwandeln kannst. Dazu benötigen wir vor allem drei Zutaten:

Ok, es kann also los gehen. Lass uns unsere ersten Sounds live coden. Zuerst brauchen wir eine Funktion, die den abzuspielenden Code enthält. Wir fangen ganz einfach an. Außerdem wollen wir diese Funktion in einer Schleife in einem Thread aufrufen:

define :my_loop do
  play 50
  sleep 1
end

in_thread(name: :looper) do
  loop do
    my_loop
  end
end

Wenn Dir das ein bisschen zu kompliziert aussieht, lies bitte noch einmal die Abschnitte über Funktionen und Threads durch. Wenn Du diese Dinge verstanden hast, wird es Dir nicht mehr sehr kompliziert vorkommen.

Wir haben hier eine Funktion, welche die Note 50 spielt und danach eine Schlagzeit lang schläft. Dann definieren wir einen benamten Thread, den wir :looper nennen. Dieser ruft in einer Endlosschleife my_loop auf.

Wenn Du diesen Code ausführst, wirst Du immer und immer wieder die Note 50 hören…

Hochschalten

Jetzt geht es richtig los. Während der Code noch läuft, ändere die 50 in eine andere Zahl, zum Beispiel 55, und drücke den Ausführen-Button erneut. Woah! Es hat sich verändert! Live!

Wir haben keine neue Ebene bekommen, da wir einen benannten Thread verwendet haben und es nur einen Thread pro Name geben kann. Der Ton hat sich geändert, weil wir die Funktion umgeschrieben haben. Wir haben also :my_loop eine veränderte Funktion verpasst. Der :looper-Thread hat einfach diese veränderte Funktion aufgerufen.

Verändere die Funktion noch einmal, ändere die Note und die Pausenzeit. Wie wäre es damit, ein use_synth-Statement einzufügen?

Ändere die Funktion zum Beispiel in folgenden Code:

define :my_loop do
  use_synth :tb303
  play 50, release: 0.3
  sleep 0.25
end

Jetzt klingt es schon ganz interessant, wir können es aber noch ein bisschen aufpeppen. Anstatt immer wieder die gleiche Note zu spielen, versuche es einmal mit einem Akkord.

define :my_loop do
  use_synth :tb303
  play chord(:e3, :minor), release: 0.3
  sleep 0.5
end

Und wie wäre es damit, zufälllige Töne des Akkords zu spielen:

define :my_loop do
  use_synth :tb303
  play choose(chord(:e3, :minor)), release: 0.3
  sleep 0.25
end

Oder einen zufälligen Cut-Off-Wert:

define :my_loop do
  use_synth :tb303
  play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
  sleep 0.25
end

Und zum Schluss noch ein Schlagzeug dazu:

define :my_loop do
  use_synth :tb303
  sample :drum_bass_hard, rate: rrand(0.5, 2)
  play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
  sleep 0.25
end

So langsam wird das hier alles viel spannender!

Bevor Du jetzt aufspringst und mit Funktionen und Threads live codest, solltest Du lieber erst einmal eine Pause machen und das nächste Kapitel über den live_loop lesen. Denn dieser wird für immer verändern, wie Du in Sonic Pi programmierst…


9.2 - Live-Loops

Ok, dieses Kapitel des Tutorials ist ein Juwel. Wenn Du nur einen Abschnitt lesen würdest, sollte es dieser sein. Mit live_loop kannst Du genau das, was Du im letzten Abschnitt gelernt hast, viel einfacher und mit weniger Code tun. Falls Du den letzten Abschnitt nicht gelesen hast: live_loop ist der beste Weg, mit Sonic Pi zu jammen.

Also los. Schreibe folgendes in einen neuen Arbeitsbereich:

live_loop :foo do
  play 60
  sleep 1
end

Jetzt klicke den Ausführen-Button. Du hörst zu jeder Schlagzeit ein einfaches Piepen. Kein besonderer Spaß. Drücke aber noch nicht den Stopp-Button. Ändere die 60 in 65 und drücke wieder Ausführen.

Whoa! Es hat sich automatisch verändert, ohne einen Takt auszulassen. Das ist Live-Coding. Warum es jetzt nicht ein wenig bassiger machen? Verändere Deinen Code, während er abläuft:

live_loop :foo do
  use_synth :prophet
  play :e1, release: 8
  sleep 8
end

Dann drücke Ausführen.

Lass uns den Cut-Off ein wenig bewegen:

live_loop :foo do
  use_synth :prophet
  play :e1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Drücke wieder Ausführen.

Füge ein Schlagzeug hinzu:

live_loop :foo do
  sample :loop_garzul
  use_synth :prophet
  play :e1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Ändere den Ton von e1 nach c1:

live_loop :foo do
  sample :loop_garzul
  use_synth :prophet
  play :c1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Und jetzt hör auf, mir zuzuhören. Spiele selbst herum, viel Spaß!


9.3 - Mehrere Live-Loops

Schau Dir den folgenden Live-Loop an:

live_loop :foo do
  play 50
  sleep 1
end

Vielleicht fragst Du Dich, warum er den Namen :foo braucht. Dieser Name ist wichtig, weil er sicherstellt, dass sich dieser Live-Loop von allen anderen Live-Loops unterscheidet.

Es können nie zwei Live-Loops mit dem selben Namen gleichzeitig laufen.

Wir müssen also unterschiedliche Namen vergeben, damit wir mehrere gleichzeitig laufende Live-Loops spielen können.

live_loop :foo do
  use_synth :prophet
  play :c1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

live_loop :bar do
  sample :bd_haus
  sleep 0.5
end

Jetzt kannst Du beide Live-Loops unabhängig voneinander verändern und alles funktioniert - einfach so.

Live-Loops synchronisieren

Du hast vielleicht schon bemerkt, dass Live-Loops automatisch mit dem Thread-Cue-Mechanismus arbeiten, den wir uns im Abschnitt über Thread-Synchronisation bereits angeschaut haben.

In jedem Durchlauf des Live-Loops generiert er ein neues cue-Event mit dem Namen des Loops. Anhand dieser Cues können wir für unsere Loops mit sync sicherstellen, dass sie zueinander synchron laufen, ohne dass wir das Abspielen zwischendurch stoppen müssen.

Schau Dir diesen schlecht synchronisierten Code an:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.4
end

live_loop :bar do
  sample :bd_haus
  sleep 1
end

Jetzt versuchen wir, das Timing zu korrigieren ohne den Loop zu stoppen. Zuerst reparieren wir den Loop :foo, indem wir die Sleep-Dauer zu einem Faktor von 1 machen - dafür funktioniert zum Beispiel 0.5.

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.5
end

live_loop :bar do
  sample :bd_haus
  sleep 1
end

Damit sind wir aber noch nicht ganz fertig. Du hörst schon, dass die Beats nicht so recht zusammenpassen. Der Grund dafür ist, dass diese Loops out of phase sind. Das können wir reparieren, indem wir einen Loop mit dem anderen synchronisieren:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.5
end

live_loop :bar do
  sync :foo
  sample :bd_haus
  sleep 1
end

Wow, jetzt passt alles genau zusammen - und das, ohne dass wir die Loops anhalten mussten.

Jetzt fangt an und coded live in Live-Loops!


10 - Unentbehrliche Kenntnisse

In diesem Kapitel findest Du sehr nützliches - nein, unentbehrliches - Wissen, um das Bestmögliche aus Deinem Sonic Pi herauszuholen.

Wir behandeln viele der verfügbaren Tastaturkürzel, zeigen, wie Du Deine Ergebnisse mit anderen teilen kannst, und geben Dir Tipps für Auftritte mit Sonic Pi.


10.1 - Tastaturkürzel

Sonic Pi ist zu gleichen Teilen Musikinstrument und Programmierumgebung. Mit Tastaturkürzeln kannst Du Sonic Pi viel effizienter und natürlicher spielen - insbesondere, wenn Du live vor Publikum spielst.

Sehr vieles in Sonic Pi kann mit der Tastatur gesteuert werden. Je vertrauter Du mit Sonic Pi wirst, umso mehr wirst Du diese Tastaturkürzel verwenden. Ich selbst tippe, ohne die Tastatur anzusehen (und kann Dir nur empfehlen, das Zehnfingersystem auch zu lernen). Und ich bin jedes Mal frustriert, wenn ich zur Maus greifen muss, denn das macht mich langsam. Deshalb benutze ich ständig Tastaturkürzel!

Wer die Tastaturkürzel beherrscht, kann auch seine Tastatur viel effektiver benutzen und in kürzester Zeit wirst Du programmieren wie ein Profi.

Versuche aber nicht, alle auf einmal zu lernen, merke Dir erst einmal die, die Du am häufigsten brauchst. Später kannst Du Dein Repertoire nach und nach erweitern.

Konsistenz auf verschiedenen Plattformen

Stell Dir vor, Du lernst Klarinette. Du kannst davon ausgehen, dass alle Klarinetten aller Marken gleiche Mechaniken und Fingersätze haben. Hätten sie das nicht, könntest Du nicht ohne weiteres zwischen verschiedenen Klarinetten hin- und her wechseln. Sondern müsstest immer bei einer Marke bleiben.

Unglücklicherweise haben die drei wesentlichen Betriebssysteme (Linux, Mac OS X und Windows) alle ihre eigenen typischen Tastaturkürzel für Aktionen wie z.B. Kopieren, Ausschneiden und Einfügen. Sonic Pi nutzt diese Standards wo immer möglich. Jedoch liegt die Priorität auf plattformübergreifender Konsistenz innerhalb von Sonic Pi, nicht auf dem Versuch, die Standards der jeweiligen Plattform vollumfänglich zu erfüllen. Das bedeutet, dass die in Sonic Pi auf dem Raspberry Pi gelernten Tastaturkürzel ebenso auf einem Mac oder PC mit Sonic Pi funktionieren.

Control und Meta

Für diese Konsistenz müssen wir auch die Namen der Tastaturkürzel entsprechend auswählen. In Sonic Pi verwenden wir die Namen Control und Meta für die beiden wichtigsten Kombinationstasten. Control (Ctrl - oder Strg für “Steuerung” auf deutschen Tastaturen) ist auf allen Plattformen gleich. Auf Linux und Windows ist Meta die Alt-Taste, während Meta auf dem Mac die Command-Taste ist. Um konsistent zu bleiben, nutzen wir den Begriff Meta - diesem musst Du mental die passende Taste Deines Betriebssystems zuordnen.

Abkürzungen

Um die Dinge einfach und lesbar zu halten, werden wir die Abkürzungen C- für Control und eine weitere Taste sowie M- für Meta und eine weitere Taste verwenden.

Wenn ein Tastaturkürzel beispielsweise erfordert, dass Du Meta und r gleichzeitig drückst, werden wir die Abkürzung M-r verwenden. Der Bindestrich in der Mitte (-) bedeutet nur “zur gleichen Zeit”.

Hier sind ein paar der Tastaturkürzel, die ich am nützlichsten finde.

Stoppen und starten

Du musst nicht immer zur Maus greifen, um Deinen Code auszuführen. Drücke stattdessen einfach M-r zum Abspielen. Mit M-s stoppst Du die Musik.

Ohne die Tastenkürzel zur Navigation bin ich verloren. Deshalb empfehle ich Dir dringend, diese Kürzel zu lernen. Sie funktionieren besonders gut, wenn Du das Zehnfingersystem schon halbwegs beherrschst, da sie normale Buchstaben verwenden - so musst Du Deine Hand nicht zur Maus oder zu den Pfeiltasten bewegen.

Mit C-a springst Du an den Anfang, mit C-e ans Ende einer Zeile. Eine Zeile nach oben geht es mit C-p, eine nach unten mit C-n, ein Zeichen vorwärts mit C-f und eines nach hinten mit C-b.

Du kannst auch alle Zeichen von der akutellen Cursorposition bis zum Ende der Zeile mit C-k löschen.

Code Aufräumen

Um Deinen Code sauber einzurücken, drücke M-m.

Hilfesystem

Zum Hilfesystem kommst Du mit M-i. Noch hilfreicher ist allerdings C-i, damit wird Dir für das Wort, auf dem der Cursor gerade steht, sofort die passende Stelle in der Dokumentation gezeigt. Sofortige Hilfe!

Eine Liste aller Tastaturkürzel ist in Kapitel 10.2 “Cheatsheet für Tastenkürzel” enthalten.


10.2 - Cheatsheet für Tastaturkürzel

In diesem Abschnitt findest Du eine Zusammenfassung der wichtigsten Tastenkürzel von Sonic Pi. In Abschnitt 10.1 erklärte ich Dir bereits, warum diese so nützlich sind.

Konventionen

Wir verwenden die folgenden Konventionen (Meta ist Alt auf Windows und Linux und Cmd auf dem Mac wie in 10.1 beschrieben):

Steuerung der Hauptanwendung

Auswahl/Kopieren/Einfügen

Text-Manipulation

Löschen

Fortgeschrittene Funktionen des Editors


10.3 - Teilen

In Sonic Pi geht es vor allen Dingen um das Teilen und gemeinsame Lernen.

Sobald Du gelernt hast, Musik zu programmieren, kannst Du Deine Kompositionen ganz leicht mit anderen teilen: Schicke Deinen Code einfach mit einer Email an Deine Freunde.

Ich möchte Dich ermuntern, Deinen Code mit anderen zu teilen, so dass sie von Deiner Arbeit lernen und Teile davon in neuen Mash-Ups verwenden können.

Du hast keine Ahnung, wo Du Deine Werke am besten mit anderen teilen kannst? Ich empfehle Dir für Deinen Code GitHub und für Deine Musik SoundCloud. So erreichst Du schnell ein großes Publikum.

Code -> GitHub

GitHub wird von professionellen Entwicklern und auch Künstlern verwendet, um Code zu teilen und zusammenzuarbeiten. Auf Github gibt es einen eigenen Bereich namens Gist, damit kann man besonders einfach ein neues Stück Code (egal ob fertig oder nicht) veröffentlichen. Mit einem Gist können dann auch andere Deinen Code übernehmen, kommentieren und verbessern.

Audio -> SoundCloud

Statt Code kannst Du auch eine Musikaufnahme veröffentlichen und dafür eine Audiodatei zu SoundCloud hochladen. Dort können andere Nutzer Kommentare dazu abgeben und die Musik diskutieren. Es ist empfehlenswert, bei einer Veröffentlichung auf Soundcloud zusätzlich einen Link zu einem Gist mit Deinen Code in die Beschreibung aufzunehmen.

Mit dem Um Dein Stück aufzunehmen, drücke den Aufnehmen-Knopf in der Werkzeugleiste, die Aufnahme startet dann sofort. Drücke Ausführen, um Deinen Code zu starten, wenn er nicht bereits läuft. Wenn Du fertig bist, drücke den den blinkenden Aufnehmen-Knopf erneut. Du wirst dann nach einem Dateinamen gefragt, unter dem die Aufnahme als WAV-Datei gespeichert wird. Es gibt viele Werkzeuge, um eine WAV-Datei in ein MP3 zu wandeln, z.B. das Programm Audacity.

Hoffnung

Ich möchte Dich ermuntern, Deine Arbeiten zu teilen, und hoffe sehr, dass wir uns gegenseitig neue Sonic-Pi-Tipps und -Tricks beibringen werden. Ich bin schon sehr gespannt darauf, was Du mir zeigen wirst.


10.4 - Auftritte

Einer der aufregendsten Aspekte von Sonic Pi ist, dass Du von nun an Code als Musikinstrument verwenden kannst. Vor Publikum zu programmieren wird damit ein neuer Weg, um Musik aufzuführen.

Das nennen wir Live-Coding.

Zeig Deinen Bildschirm

Wenn Du live programmierst, empfehle ich Dir, Deinem Publikum Deinen Bildschirm zu zeigen. Beim Gitarrespielen versteckst Du ja auch nicht Deine Finger und die Saiten Deines Instruments. Wenn ich zu Hause übe, verwende ich einen Raspberry Pi und projiziere den Bildschirm mit einem kleinen Beamer an meine Wohnzimmerwand. Du könntest auch Deinen Fernseher oder einen Projektor in der Schule/Arbeit verwenden und eine kleine Show geben. Versuch es, das macht eine Menge Spaß.

Gründe eine Band

Spiele nicht nur alleine - gründe eine Live-Coding-Band! Mit anderen zu jammen macht großen Spaß. Einer könnte die Beats programmieren, ein anderer flächige Hintergrundklänge und so weiter. Probiert aus, welche interessanten Klangkombinationen Ihr finden könnt.

TOPLAP

Live-Coding ist nicht wirklich neu - eine kleine Gruppe von Enthusiasten macht das schon seit Jahren, typischerweise mit selbstgebauten, individuellen Systemen.

Bei TOPLAP erfährst Du mehr über diese anderen Live-Coder und ihre Geräte.

Algorave

Einige Live-Coder spielen auch in Nightclubs. Mehr über dieses spezielle Genre erfährst Du auf Algorave.


11 - Minecraft Pi

Raspbian, das Linux-Betriebssystem für Raspberry Pi, bringt eine spezielle Version von Minecraft als Teil der Vorinstallation mit. Und mit Sonic Pi kannst Du über eine einfache API jetzt auch Minecraft Pi steuern.

Keine Bibliotheken notwendig

Die Verbindung zwischen Minecraft Pi und Sonic Pi ist so einfach zu nutzen, dass Du nichts dafür vorbereiten musst. Starte einfach Minecraft Pi und baue eine Welt. Du kannst sofort die mc_*-Funktionen in Deinem Code genau wie play oder synth einsetzen. Es gibt nichts zu installieren und keine Bibliotheken zu importieren - alles ist fix und fertig und sofort startklar für Dich.

Automatische Verbindung

Die Minecraft-Pi-API kümmert sich automatisch um die Verbindung zur laufenden Minecraft-Pi-Applikation. Du musst also nichts dafür tun. Sonic Pi wird sich allerdings freundlich beschweren, wenn Du die API benutzen möchtest und Minecraft Pi nicht gleichzeitig läuft. Und falls Du die Minecraft-Pi-Applikation beendest, während Dein Code die API in einem live_loop ansprechen will, wird der Loop beendet und Du erhältst eine entsprechende Fehlermeldung. Starte dann Minecraft Pi wieder neu, die API wird sich von selbst damit verbinden und Dein Code funktioniert wieder.

Gemacht für Live-Coding

Die Minecraft-Pi-API ist dazu da, dass sie problemlos in in einem live_loop funktioniert. Das heißt, Du kannst damit Veränderungen in Deiner Minecraft-Welt mit Veränderungen in Deinen Sonic-Pi-Sounds synchronisieren. Zack, Minecraft-basierte Musik-Videos! Bedenke aber, dass Minecraft Pi eine Alpha-Version ist und die Software ein paar kleinere Bugs hat. Wenn ein solches Problem mit Minecraft Pi auftritt, starte es einfach neu. Sonic Pi nimmt dann automatisch eine neue Verbindung über seine API auf.

Raspberry Pi 2 empfohlen

Minecraft Pi und Sonic Pi mit seinen Sound-Möglichkeiten sind beides sehr rechenintensive Programme. Der alte Raspberry ist davon schnell überfordert und ein Raspberry Pi 2 mit seinem schnelleren Prozessor deshalb sehr zu empfehlen!

API-Support

Zur Zeit kann Sonic Pi einige Grundfunktionen zur Manipulation von Minecraft-Blöcken und dem Spieler ausführen. Details dazu findest Du im nächsten Abschnitt 11.1. Für ein späteres Release plane ich, auch Event-Callbacks aus Minecraft Pi zu unterstützen, so dass der Code in Sonic Pi von Ereignissen erfahren kann, die der Spieler in Minecraft Pi ausgelöst hat.


11.1 - Grundfunktionen der Minecraft-Pi-API

Folgende Aktionen kannst Du mit der API von Sonic Pi aus in Minecraft Pi auslösen:

Schauen wir uns diese der Reihe nach an.

Anzeige von Chat-Nachrichten

Ich zeige Dir mal, wie einfach es ist, von Sonic Pi aus die Kontrolle über Minecraft Pi zu übernehmen. Starte also zunächst Sonic Pi und Minecraft Pi und betrete eine Minecraft-Welt, in der Du herumlaufen kannst.

Jetzt schreibe folgenden Code in einem leeren Arbeitsbereich von Sonic Pi :

mc_message "Hallo, hier ist Sonic Pi"

Führe den Code aus und Du wirst die Nachricht im Minecraft-Fenster aufblitzen sehen. Gratuliere, das ist Dein erster Minecraft-Code! War doch gar nicht schwer, oder?

Die Spielerposition setzen

Und jetzt zaubern wir ein wenig. Teleportiere Dich einfach, wohin Du willst! Probiere das hier aus:

mc_teleport 50, 50, 50

Nach Klick auf Ausführen - Paff! - bist Du sofort an einem anderen Ort in Deiner Minecraft-Welt. Vermutlich irgendwie hoch oben in der Luft und Du bist aufs Land oder Wasser herunter gefallen. Was bedeuten diese Zahlen: 50, 50, 50? Das sind die Koordinaten der Zielposition für den Teleport. Probiere jetzt in Deinem Code ein paar Koordinaten aus, damit Du weißt, wie sie funktionieren. Koordinaten sind für Minecraft-Programme sehr sehr wichtig.

Koordinaten

Stelle Dir eine alte Piraten-Schatzkarte vor - beim großen X ist der Schatz vergraben. Die genaue Position des X lässt sich mit zwei Zahlen beschreiben - wie weit ist das Kreuz horizontal vom Papierrand entfernt und wie weit vertikal. Angenommen, es ist 10cm vom linken Rand und 8cm vom unteren Rand entfernt. Diese beiden Zahlen 10 und 8 sind Koordinaten. Auch andere vergrabene Schätze auf der Karte lassen sich mit ihrem jeweiligen Koordinaten-Zahlenpaar genau beschreiben. Etwa die große Goldkiste bei 2 von links und 9 von unten…

In Minecraft Pi reichen zwei Zahlen nicht mehr aus. Wir brauchen auch eine Höhenangabe und damit besteht eine Koordinate in Minecraft aus drei Zahlen:

Diese Minecraft-Koordinaten schreiben wir dann in der Reihenfolge x, y, z auf.

Wo befindest Du Dich?

Spielen wir also ein wenig mit den Koordinaten herum. Bewege Dich in Minecraft Pi an einen schönen Ort und wechsele dann zu Sonic Pi. Nun führe folgenden Code aus:

puts mc_location

Drücke Ausführen und im Log erscheinen die Koordinaten, an denen Du Dich in Minecraft befindest. Merke sie Dir, bewege Dich in Minecraft ein wenig weiter und führe den Code noch einmal aus. Hast Du gesehen, wie sich die Koordinaten geändert haben? Probiere das noch ein bisschen aus, damit Du ein Gefühl dafür bekommst, wie sich die Koordinaten mit Deiner Bewegung in der Minecraft-Welt verändern. Wenn Du erst einmal verstanden hast, wie Koordinaten funktionieren, wird das Programmieren mit der Minecraft-Pi-API ganz einfach.

Lass uns etwas bauen!

Jetzt weißt Du, wie Du Deine Position auslesen und Dich an beliebige Stellen teleportieren kannst. Als nächstes können wir mit Code Dinge in Minecraft bauen. Zum Beispiel ein Block aus Glas an Koordinate 40, 50, 60, das geht ganz einfach:

mc_set_block :glass, 40, 50, 60

Haha, das war ja wirklich ganz einfach. Nach getaner Arbeit springst Du schnell in die Nähe und schaust Dir das Ergebnis an:

mc_teleport 35, 50, 60

Dreh Dich ein wenig und Du wirst Deinen Glasblock sehen! Ändern wir kurz das Material und machen einen Block aus Diamant daraus:

mc_set_block :diamond, 40, 50, 60

Wenn Du in die richtige Richtung schaust, konntest Du eben sogar dabei zusehen, wie sich der Block verändert. Hier geschieht etwas aufregendes…

Blöcke ansehen

Du kannst Minecraft Pi auch fragen, welcher Typ Block sich an einer Koordinate befindet. Der folgende Code tut dies für den Diamantblock, den Du gerade gebaut hast:

puts mc_get_block 40, 50, 60

Yay! Es ist :diamond. Ändere das Material des Blocks wieder zu Glas und lese den Typ noch einmal aus - meldet der Code jetzt :glass zurück? Ich bin sicher, dass er das tut. :-)

Mögliche Materialtypen in Minecraft

Bevor Du jetzt mit Code durch Minecraft Pi tobst, hier noch eine praktische Liste aller Material-Typen für Minecraft-Blöcke:

    :air
    :stone
    :grass
    :dirt
    :cobblestone
    :wood_plank
    :sapling
    :bedrock
    :water_flowing
    :water
    :water_stationary
    :lava_flowing
    :lava
    :lava_stationary
    :sand
    :gravel
    :gold_ore
    :iron_ore
    :coal_ore
    :wood
    :leaves
    :glass
    :lapis
    :lapis_lazuli_block
    :sandstone
    :bed
    :cobweb
    :grass_tall
    :flower_yellow
    :flower_cyan
    :mushroom_brown
    :mushroom_red
    :gold_block
    :gold
    :iron_block
    :iron
    :stone_slab_double
    :stone_slab
    :brick
    :brick_block
    :tnt
    :bookshelf
    :moss_stone
    :obsidian
    :torch
    :fire
    :stairs_wood
    :chest
    :diamond_ore
    :diamond_block
    :diamond
    :crafting_table
    :farmland
    :furnace_inactive
    :furnace_active
    :door_wood
    :ladder
    :stairs_cobblestone
    :door_iron
    :redstone_ore
    :snow
    :ice
    :snow_block
    :cactus
    :clay
    :sugar_cane
    :fence
    :glowstone_block
    :bedrock_invisible
    :stone_brick
    :glass_pane
    :melon
    :fence_gate
    :glowing_obsidian
    :nether_reactor_core

12 - Abschluss

Damit bist Du am Ende des Tutorials von Sonic Pi angekommen. Hoffentlich hast Du etwas dabei gelernt. Falls Du das Gefühl hast, nicht alles verstanden zu haben - keine Angst, spiele einfach weiter und hab Spaß dabei. Dann wird immer mehr hängenbleiben. Und greife einfach auf das Tutorial zurück, wenn Du eine Frage hast, die in einem der vorherigen Kapitel behandelt worden sein könnte.

Sind noch Fragen übrig, die über die Einführung hinausgehen? Du kannst damit ins Sonic Pi Forum kommen und Dein Anliegen dort beschreiben. Dort sind viele nette Menschen, die Dir gerne weiterhelfen.

Du bist auch eingeladen, Dir den Rest der Dokumentation im Hilfe-System genauer anzuschauen. Es gibt noch eine Reihe von Features, die in dieser Einführung nicht behandelt wurden und darauf warten, von Dir entdeckt zu werden.

Also: Spiele herum, hab Spaß, teile Deine Code, tritt vor Freunden auf, zeige was Du auf dem Monitor hast und nicht vergessen:

There are no mistakes, only opportunities. (Es gibt keine Fehler, nur Möglichkeiten)

Sam Aaron