3 Punkte von GN⁺ 2024-08-11 | 1 Kommentare | Auf WhatsApp teilen
  • Sonic Pi wird als Umgebung vorgestellt, in der man auch ohne Instrumente und Equipment Musik machen kann; mit einer Ruby-basierten DSL lassen sich Noten, Akkorde, Skalen und Timing direkt schreiben
  • Mit Rubys Funktionen, Arrays, Bedingungen, Schleifen und Scopes lassen sich play, sleep, play_pattern_timed, chord und scale bündeln, um wiederholte Patterns und Arpeggios knapp zu konstruieren
  • Kombiniert man in_thread, ring, flatten, den Splat-Operator und with_fx, kann man mehrere „Instrumente“ gleichzeitig ausführen und überlagerte Töne sowie unterschiedliche Rhythmen schichten
  • Die Steuerung von attack, decay, sustain und release der ADSR-Hüllkurve zielt weniger auf eine realistische Chor-Nachbildung als darauf, Haltezeit und Trennschärfe passend einzustellen
  • live_loop kann laufenden Code aktualisieren und wiederholt ausführen; dadurch wird Sonic Pi zu einem Werkzeug für Live-Performances und lässt Code als lesbaren Text wie auch als schöpferische Handlung erscheinen

Sonic Pi per Code steuern

  • Sonic Pi ist im Unterschied zu üblichen Audio-Anwendungen ein Software-Synthesizer, der ausschließlich per Code gesteuert wird
  • Die eigene Steuersprache ist eine aus Ruby erweiterte domänenspezifische Sprache (DSL) und bildet Musik- und Audiokonzepte auf Ruby-Syntax ab
  • Die Grundelemente bestehen aus Ruby-Werten und Sonic-Pi-Funktionen
    • Notennamen wie :c4 werden als Symbole verwendet, die dem jeweiligen MIDI-Code entsprechen
    • Mit Argumenten für Grundton und Akkordstruktur, etwa chord(:d3, :maj7), lassen sich Akkorde erzeugen
    • play spielt einen Ton ab, und zusammen mit Rubys sleep werden Zeitabstände gesteuert
    • play_pattern_timed nimmt eine Liste von Tönen und Zeitabständen entgegen und verkürzt Code für wiederholte Wiedergabe
  • Ziel des Beispiels ist es, nur mit den Grundfunktionen von Sonic Pi und ohne externes MIDI oder Samples eine Demo-Begleitung per Code zu erstellen
  • Nach der Installation der Sonic-Pi-App kann man den Beispielcode einfügen und nachvollziehen; Sprachdokumentation und Tutorials sind ebenfalls enthalten

Wiederholte Patterns mit Ruby-Syntax erstellen

  • Das Grundbeispiel ändert mit use_bpm 70 das BPM und verwendet mit use_synth :pulse statt der standardmäßigen Sinuswelle einen Pulse-Synthesizer
  • Wiederholt man play :c2 und sleep 0.25, lassen sich Töne der Reihe nach abspielen; mit play_pattern_timed [ :c3, :d3, :e3, :g3 ], 0.25 kann dieselbe Struktur kürzer geschrieben werden
  • Da die Steuersprache auf Ruby aufsetzt, lassen sich Patterns mit Funktionen und Schleifen abstrahieren
    • Die Funktion arpeggiate nimmt einen Grundton und optional die Angabe, ob es Moll sein soll, und erzeugt ein auf- und absteigendes Pattern
    • Mit einer 4.times-Schleife wird dasselbe Pattern über mehrere Oktaven hinweg ausgeführt
    • Eine Bedingung ändert bei Moll die Terz, und mit map auf einem Array wird durch Addieren von Intervallen zum Grundton eine Tonliste erzeugt
  • Synthesizer-Standardoptionen lassen sich vorab setzen, etwa mit use_synth_defaults amp: 0.1; Optionen können auch direkt an play oder play_pattern_timed übergeben werden
  • In Ruby sind Klammern bei Funktionsaufrufen optional, doch bei Fällen wie play chord(:a3, maj7) kann es nötig sein, die Abgrenzung klarzumachen

Parallele Ausführung und Layering

  • in_thread do-Blöcke werden in Sonic Pi verwendet, um Code parallel auszuführen
  • Mit unterschiedlichen in_thread-Blöcken können zwei separate „Instrumente“ gleichzeitig laufen
    • Ein Thread kann ein Arpeggio-Pattern übernehmen
    • Ein anderer Thread kann mit use_synth :saw sowie einem Melodie-Array und einem Rhythmus-Array eine eigene Linie spielen
  • play_pattern_timed kann nicht nur eine Tonliste, sondern auch eine Liste von Zeitabständen entgegennehmen
    • [1] * 2 verlängert ein Array und wiederholt dessen Inhalt, also etwa zu [1, 1]
    • Verschachtelte Arrays werden von play_pattern_timed nicht unverändert akzeptiert, daher nutzt man flatten, um sie zu einem Array auf einer Ebene aufzufalten
  • Für überlagerte Töne wie in einem Chor lassen sich mehrere Töne mit ring(:c5, :e5) zusammenfassen
  • flatten kann auch die Liste innerhalb von ring zusammenführen; in diesem Fall nutzt man stattdessen den Splat-Operator *, um Listeninhalte in das übergeordnete Array zu entfalten

Scope, Effekte und Aufbau von Chorstimmen

  • Mit verschachtelten in_thread-Blöcken kann man Rhythmusfragmente aus dem äußeren Scope teilen und zugleich in jedem inneren Thread dieselben Variablennamen erneut verwenden
  • Teilt man Stimmen wie Sopran und Alt in eigene Threads auf, hat jeder Block seinen eigenen Scope und greift nicht direkt auf die Variablen der anderen zu
  • with_fx :reverb, mix: 0.2 erzeugt einen Effektblock; der Signalfluss beginnt in der innersten Ebene und wandert nach außen durch die Effektkette
  • mix bezeichnet das Mischverhältnis aus Wet- und Dry-Signal
    • Das Wet-Signal ist das Signal mit angewendetem Effekt
    • Das Dry-Signal ist das Signal ohne Effekt
  • Eine ganze Gruppe mit einem Effekt zu umhüllen, lässt sich ähnlich wie ein Bus in einer DAW verwenden; tieferes Routing ist jedoch manuell und muss wegen der Scopes meist von oben nach unten aufgebaut werden
  • Sonic Pi behandelt man natürlicher als Instrument denn als präzises Produktionswerkzeug

Tonlängen mit der ADSR-Hüllkurve anpassen

  • play_pattern_timed ergänzt einen sustain-Wert, sodass sich die Haltezeiten langer und kurzer Akkorde direkt anpassen lassen
  • attack, decay, sustain und release bilden die ADSR-Hüllkurve, die beschreibt, wie sich die Lautstärke über die Zeit verändert
    • attack ist die Zeit von 0 bis zum ersten Peak und entspricht dem anfänglichen Anschlag, etwa dem Zupfen einer Gitarrensaite oder dem Moment, in dem ein Klavierhammer trifft
    • decay ist die Zeit des Abfalls vom ersten Peak und entspricht der Phase, in der der Klang allmählich leiser wird, auch wenn eine Klaviertaste oder Gitarrensaite gehalten wird
    • sustain ist die Zeit, in der der Klang mit stabiler Lautstärke gehalten wird, etwa bei einer gestrichenen Saite oder einer lang gehaltenen Gesangsstimme
    • release ist die Zeit nach dem Loslassen des Klangs, bis er tatsächlich verstummt
  • Nicht jeder Klang besitzt alle ADSR-Elemente
    • Synthesizer-Töne sind erzeugte Klänge und haben daher nicht zwangsläufig einen anfänglichen Aufbau oder Nachhall
    • Bei natürlichen Instrumenten variiert das Verhältnis der Elemente je nach Spielweise
  • Die Chorsimulation im Beispiel konzentriert sich weniger auf Realismus als darauf, Töne genau für die richtige Dauer zu halten und zwischen Akkorden etwas Trennung zu schaffen
  • Die Funktion choral_rings notes, sus nimmt eine Tonliste und eine Haltezeit entgegen, spielt sie mit ring(*notes) gemeinsam ab, berechnet sustain und release und wartet dann mit sleep sus bis zum nächsten Ereignis

Live-Coding mit live_loop

  • Mit live_loop lässt sich Code unbegrenzt wiederholt ausführen
  • Sonic Pi ist stark auf Live-Performances ausgelegt, und Code innerhalb von live_loop läuft, bis das Programm gestoppt wird
  • Auch während der Wiedergabe kann man den Loop-Inhalt ändern; führt man den Startbefehl erneut aus, wird der aktualisierte Loop ab der nächsten Wiederholung angewendet
  • Vorhandene äußere in_thread-Schleifen lassen sich in die Form live_loop :some_unique_name ändern
  • Die Effektkette wird bei jedem Loop-Durchlauf erneut erzeugt; je mehr Effekte man stapelt, desto günstiger ist es aus Ressourcensicht, sie außerhalb von live_loop zu platzieren
  • Das finale Beispiel besteht aus live_loop :harp und live_loop :choir
    • Der Loop :harp verwendet den Synthesizer :square und ein Arpeggio-Pattern der Länge 0.25
    • Der Loop :choir verwendet den Synthesizer :saw, sleep 64, with_fx :reverb, mix: 0.75 und Aufrufe der Funktion choral_rings, um Chorakkorde abzuspielen

Programmieren als schöpferische Handlung verstehen

  • Technische Arbeit wird meist aus der Perspektive der Informatik diskutiert, doch auch Programmierung kann Kunst sein
  • Künstlerisch ist sie nicht nur dann, wenn sie bewusst kreative Ergebnisse erzeugt, etwa Audiogenerierung oder CSS-Layouts
  • Code ist nicht nur ein für Maschinen optimierter Befehlssatz, sondern organisierter Text, den andere Menschen und das zukünftige Ich lesen
  • Guter Code ist Code, der so geschrieben ist, dass andere oder man selbst in sechs Monaten ihn auf einen Blick verstehen können
  • Manchmal wird die Kunstfertigkeit von Code zum Selbstzweck; das Sonic-Pi-Beispiel zeigt diesen Punkt anhand der Musikproduktion

1 Kommentare

 
GN⁺ 2024-08-11
Meinungen auf Hacker News
  • Wenn ihr euch für Live-Coding interessiert, ist auch Glicol(https://glicol.org) einen Versuch wert.
    Es gibt auch TidalCycles, und die Fähigkeit von Haskell und Ruby, DSLs zu bauen, ist wirklich lobenswert.
    Glicol konzentriert sich auf eine von Synthesizern inspirierte Syntax, Kompositionsgeschwindigkeit und Komfort beim Sounddesign. Die Idee ist, eine DSL zu entwerfen, die bestehende Programmiergewohnheiten aufgreift, ohne an eine bestimmte Sprache gebunden zu sein.

  • Vor ein paar Jahren habe ich auf YouTube ein Video gesehen, in dem jemand mit Sonic Pi die THX Deep Note nachgebaut hat.
    Am Anfang erklärte er nicht, was er bauen würde, sondern erzeugte einen einzelnen „Ton“ des Klangs und nannte ihn eine Biene. Er passte dieses Bienengeräusch nach und nach an und spielte es vor. Am Ende ging es dann ungefähr so weiter: „Machen wir ein paar hundert dieser Bienen und schauen wir, wie das in einem Bienenstock klingt“ — und in diesem Moment erschien die Deep Note.
    Das Video war wirklich großartig, aber ich habe es seitdem nicht wiedergefunden. Wenn jemand den Link kennt, wäre es schön, wenn er ihn teilen könnte.

  • Ich denke, das ist einer der Fälle, in denen Ruby glänzt. Dank Metaprogrammierung kann man die Syntax fast wie Englisch aussehen lassen.

    • Stimmt, aber die Sonic-Pi-DSL fühlt sich weniger nach natürlicher Sprache an und eher ein bisschen wie Lisp.
    • Ja, das ist Metaprogrammierung.
  • Vor ein paar Jahren habe ich Sam Aaron, also den Schöpfer von Sonic Pi, live mit Sonic Pi auftreten sehen.
    Jedes Mal, wenn sich der Code in Echtzeit änderte, entwickelte sich auch die Musik weiter, und es war tatsächlich gut.

    • Ich habe Sam auch einmal getroffen. Um 2008–2010 herum hat er auf der Clojure Conj einen Vortrag gehalten, danach haben wir zusammen zu Abend gegessen. Schon damals war er ein wirklich netter Mensch, und der Vortrag war großartig.
  • Wenn ihr Beispiele für Künstler sucht, die Sonic Pi verwenden: Vor einiger Zeit bin ich auf DJ_Dave gestoßen. Ich finde, das ist ein gutes Beispiel dafür, wie eine talentierte und erfahrene Musikerin dieses Tool gut einsetzt.
    Sie hat früher auch ein AMA auf Reddit gemacht, und auf GitHub scheint es ebenfalls Arbeiten von ihr zu geben.
    [1] https://www.youtube.com/watch?v=JiQHclg_648
    [2] https://www.reddit.com/r/audius/comments/19dxmy6/hey_audius_...
    [3] https://github.com/algorave-dave

  • Als Ruby-Entwickler sieht das wirklich cool aus. Für algorithmisch generierte Musik könnte es Spaß machen, und ich wollte schon einmal laute Ereignisse in einem git-Repository in irgendeine algorithmische Musik umwandeln; dafür scheint es gut zu passen.
    Aus Sicht eines Musikers mit mehreren Tasteninstrumenten verstehe ich allerdings nicht so recht, warum man Musiksequenzen ausgerechnet in Ruby schreiben sollte, wenn man zum Komponieren einfach auf einem MIDI-Keyboard spielen oder ein akustisches Instrument aufnehmen und loopen kann. Ich verstehe, dass man in der Ruby-DSL eingeben kann, was man will, aber im Vergleich zu einer Klaviatur würde ich die User Experience nicht als besser bezeichnen.
    Anders gesagt: Ich glaube nicht, dass ich das als Ersatz für Logic verwenden würde. Das ist natürlich persönliche Vorliebe.
    Hinweis: http://listen.hatnote.com/

    • In mancher Hinsicht drückt eine Ruby-DSL die Absicht allerdings klarer aus als eine MIDI-Sequenz.
      Tatsächlich denkt man manchmal in Begriffen wie „jetzt ein c-Moll-Arpeggio, jetzt ein F-Dur-Arpeggio“, und es ist schön, solche Absichten sehr klar als Funktionen komponieren zu können.
    • Sonic Pi scheint weniger ein allgemeines Kompositionswerkzeug zu sein, sondern stärker auf algorithmisch erzeugte Musik, insbesondere Live-Coding, ausgerichtet.
      Der Kern scheint eher darin zu liegen, Musik algorithmisch zu erzeugen, statt jede einzelne Note einzuspielen.
      Trotzdem passt es ziemlich gut zu den Interessen von Hacker News, ein Tool, das man normalerweise nicht verwenden würde, wegen ungewöhnlicher Einschränkungen auf interessante Weise einzusetzen.
    • Für Musiktheoretiker mit mangelnder Koordination und Feinmotorik könnte es passen.
    • Wie auch im Originalbeitrag angedeutet, liegt es meistens an praktischen Einschränkungen.
      Ich habe ein Keyboard, das mir gefällt, und theoretisch könnte ich es dafür verwenden, aber aus komplizierten persönlichen Gründen sind meine Instrumente seit einiger Zeit alle eingelagert.
  • Vor ein paar Tagen musste ich zufällig an Sonic Pi denken und habe mir ein paar Online-Videos angesehen.
    Ich hatte es vor ein paar Jahren nur kurz ausprobiert und damals klassische Stücke wie Old MacDonald und Hot Cross Buns eingetippt.

  • Wenn ihr andere Ansätze für Musikprogrammierung sehen wollt: Nicht live, aber scamp[0] für Python ist ebenfalls einen Blick wert.
    Der Entwickler hat auf YouTube viele Videos mit Arbeiten gepostet, die er damit gemacht hat, zum Beispiel das Video Fourier Elise[1].
    [0] http://scamp.marcevanstein.com/
    [1] https://www.youtube.com/watch?v=zq32bIud3OM

  • HTML-Kommentare scheinen nicht zu funktionieren. Der Editor hat wohl die zwei Bindestriche -- in einen einzelnen em dash umgewandelt.

    • Gut erkannt. Tatsächlich habe ich Suchen/Ersetzen zu überhastet laufen lassen und dabei ein paar solcher Stellen übersehen XD
  • Ich empfehle außerdem meinen liebsten Sonic-Pi-Live-Coder alsoknownasrox.
    https://www.youtube.com/watch?v=wXIvXrBQFkE