Randomisierung

Zufallszahlen sind eine tolle Möglichkeit, Deine Musik interessant zu gestalten. In Sonic Pi sind einige Funktionen enthalten, 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 in einem bestimmten Wertebereich.) Hier eine zufällig ausgewählte Note:

play rrand(50, 95)

Oh, eine zufällige Note wird gespielt. Es war die Note 83.7527. 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 83.7527, 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 den Zufallsgenerator einbaust.

Klar, wenn in einem bestimmten Musikstück jedesmal die 83.7527 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, 95)
  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 Murmeltier-Tag 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 Endlosschleife 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 Ausfiltern bzw. Abschneiden hoher Töne 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_seed 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ässt, 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ützliche 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 sein, also keine ganze Zahl, sondern eine mit einem Komma. (Ok, wir schreiben sie mit einem Komma, aber im englischen Sprachraum heißen sie Floating Point - oder kurz: Float - und man schreibt sie mit einem Punkt.) 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_i. (Das “i” steht hier für das englische Wort Integer, also ganze Zahl.) 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 zufällige ganze Zahl zwischen 0 und dem 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, wie viele 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, dass 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 späteren Kapitel dieses Tutorials besprechen.

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