Am 2. Mai hatte ich die Gelegenheit auf der Re:publica TEN Sonic Pi vorzustellen. Dies ist der Blogbeitrag zu Präsentation: mit Hintergrundinfos, dem Code-Beispielen und Links zu Sonic Pi.
Wer nicht programmieren kann, für den erscheint Code undurchsichtig und abstrakt. Tatsache ist, dass vieles von dem, was wir wissen, wünschen, hoffen und konsumieren seinen Niederschlag in Programmcode findet. Grund genug, sich nicht nur vorgegebenen Ergebnissen abzufinden, sondern selbst Hand anzulegen.
Sonic Pi wurde von Sam Aaron im Rahmen eines Projekts an der Cambridge University entwickelt. Es ging darum, das Curriculum an britischen Grundschulen umzusetzen. Dort steht nämlich, dass Schüler und Schülerinnen sich nicht nur oberflächlich mit digitaler Technologie beschäftigen, sondern einen tieferen Einblick erhalten sollten: Sie sollen das Programmieren lernen. Dabei hilft Sonic Pi.
Was ist Sonic Pi?
Trojanisches Pferd zu pädagogischen Zwecken: Sam Aaron berichtet, dass es in einer britischen Schulklasse voller 10-jähriger unmöglich ist, zwei zusammenhängende Sätze zu sprechen. Zunächst undenkbar, in so einer Atmosphäre etwas über Funktionen, Variablen oder noch kompliziertere Konzepte der Programmierung zu referieren. Das ist aber auch gar nicht nötig. Zwei Kommandos, nämlich play und sleep reichen aus, um die Kids ans spielen, arbeiten und verstehen zu bringen. Daraus ergibt sich das weitere. Sonic Pi ermöglicht ‚audible programming‘: Unmittelbares Feedback in Form von Tönen und Musik überführt die Abstraktheit des Codes in sinnliches Erleben (und wieder zurück).
Programmierumgebung: Auf der Basis von Ruby bietet Sonic Pi eine Vielzahl von Ausdrücken, mit denen Musik erzeugt, gesteuert und organisiert werden kann. Sonic Pi enthält einen Editor und eine Laufzeitumgebung, in das Geschriebene ausgeführt und verändert werden kann.
Synthesizer: Sonic Pi liefert aktuell 39 unterschiedliche Synthesizer-Sounds. Hinzu kommen eine Vielzahl von Filtern und Effekten, mit denen diese Palette noch erweitert werden kann. (Genauer gesagt, stellt nicht Sonic Pi diese Sounds zur Verfügung, sondern SuperCollider.)
Sequencer und Sampler: Mit Sonic Pi können musikalische Strukturen hergestellt und organisiert werden. Man kann unterschiedliche Klänge mehrstimmig ablaufen lassen, loopen oder auch abhängig vom Zufall auftauchen lassen. Sonic Pi versteht auch den Umgang mit Samples. 130 davon bringt es aktuell mit. Aber auch Klangdateien von der eigenen Festplatte können eingebunden werden (in .wav- oder .aiff-Format). Samples können u.a. gedehnt, gestaucht oder partiell abgespielt werden.
Musikalische Experimentierwerkstatt: Mit Sonic Pi kann man musikalische Experimente durchführen, Kompositionen nachbauen und verstehen und davon ausgehend eigenes entwerfen.
Live Coding-Instrument: Schließlich wird Sonic Pi zunehmend auch für das Live Coding eingesetzt. Statt D(isk) J(ockey) steht der C(ode) J(ockey) hinter seinem Laptop und kreiert Live-Musik, zu der getanzt wird. Sam Aaron beherrscht sein Intrument mittlerweile beeindruckend virtuos.
Code-Beispiele
Sonic Pi enthält ein hervorragendes Tutorial. Deshalb spare ich es mir an dieser Stelle, die Beispiele aus der Präsentation ausführlich zu kommentieren. Meine Empfehlung: Sonic Pi herunterladen und installieren, das Tutorial im Programm aufrufen (Shortcut: Alt-i) ansehen und dann gleich anfangen. Noch ein kleiner Hinweis: Das deutschprachige Tutorial ist im Moment nicht ganz auf dem neuesten Stand (vermutlich jedoch in der nächsten Version 2.11). Wer also des englischen mächtig ist, kann die englischen Seiten online lesen.
Die Code-Beispiele enthalten teilweise mehrere Abschnitte, die nicht unbedingt parallel gespielt werden können. Aus diesem Grund sind Teile auskommentiert. Das geschieht in Sonic Pi u.a. mit folgendem Befehl:
comment do # Was hier steht, wird nicht berücksichtigt, wenn man auf 'Run' klickt. end uncomment do # Dieses hier aber schon. end
Also, falls man nichts oder zuviel hört, bitte nach „comment“ oder „uncomment“ suchen.
Play & Sleep
Mit diesen beiden Kommandos kann man schon sehr viel anfangen. Das nachfolgende Beispiel benutzt weiter unten auch noch den Befehl „play_pattern_timed“, eine Kombination aus „play“ und „sleep“; wenn man zwei musikalische Abschnitte gleichzeitig hören möchte, dann hilft der Befehl „in_thread“:
# Beethoven: Ode an die Freude use_bpm 200 uncomment do play :e sleep 1 play :e sleep 1 play :f sleep 1 play :g sleep 1 play :g sleep 1 play :f sleep 1 play :e sleep 1 play :d sleep 1 play :c sleep 1 play :c sleep 1 play :d sleep 1 play :e sleep 1 play :e sleep 1.5 play :d sleep 0.5 play :d sleep 2 play :e sleep 1 play :e sleep 1 play :f sleep 1 play :g sleep 1 play :g sleep 1 play :f sleep 1 play :e sleep 1 play :d sleep 1 play :c sleep 1 play :c sleep 1 play :d sleep 1 play :e sleep 1 play :d sleep 1.5 play :c sleep 0.5 play :c sleep 2 end comment do in_thread do play_pattern_timed [:e, :e, :f, :g, :g, :f, :e, :d, :c, :c, :d, :e], 1 play_pattern_timed [:e, :d, :d],[1.5, 0.5, 2] play_pattern_timed [:e, :e, :f, :g, :g, :f, :e, :d, :c, :c, :d, :e], 1 play_pattern_timed [:d, :c, :c],[1.5, 0.5, 2] play_pattern_timed [:d, :d, :e, :c, :d], 1 play_pattern_timed [:e, :f], 0.5 play_pattern_timed [:e, :c, :d], 1 play_pattern_timed [:e, :f], 0.5 play_pattern_timed [:e, :d, :c, :d, :g3, :e], [1, 1, 1, 1, 1, 2] play_pattern_timed [:e, :f, :g, :g, :f, :e, :d, :c, :c, :d, :e], 1 play_pattern_timed [:d, :c, :c],[1.5, 0.5, 2] end play_pattern_timed [:c3, :g2, :c3, :g2], 4, release: 5, amp: 0.5 play_pattern_timed [:c3, :g2, :c3], 4, release: 5, amp: 0.5 play_pattern_timed [:g2, :c3], 2, release: 3, amp: 0.5 play_pattern_timed [:g2, :g2, :g2], 4, release: 5, amp: 0.5 play_pattern_timed [:g2, :g2], [2, 2], release: 5, amp: 0.5 play_pattern_timed [:c3, :g2, :c3], 4, release: 5, amp: 0.5 play_pattern_timed [:g2, :c3], 2, release: 3, amp: 0.5 end
Samples & live_loop
Mit Samples kann man sich in Sonic Pi stundenlang vergnügen. Spätestens hier sollte man die „live_loop“ kennenlernen. Sie ermöglicht u.a., dass man einen Sound/Sample verändert, ohne dass dieser beim erneuten Klick auf „Run“ vervielfacht wird. „Live Loops“ sind auch die Basis für das Live Coding: Geht etwas schief beim Coden, dann läuft der Sound weiter (bis auf die Schleife, bei der man den Fehler gemacht hat). Das ist besonders dann von Vorteil, wenn man vor sich einige hundert Leute hat, die weitertanzen möchten.
Hier einige Beispiele zum Thema „Samples“, die ich in der Präsentation gezeigt habe:
uncomment do live_loop :amen do sample :loop_amen, rate: 1 sleep sample_duration(:loop_amen, rate: 1) end end # Hip-Hop comment do live_loop :amen do sample :loop_amen, rate: 0.75 sleep sample_duration(:loop_amen, rate: 0.75) end end # Jungle comment do live_loop :amen do sample :loop_amen, rate: 1.25 sleep sample_duration(:loop_amen, rate: 1.25) end end # Backwards comment do live_loop :amen do sample :loop_amen, rate: -1 sleep sample_duration(:loop_amen, rate: 1) end end # Samples nur teilweise spielen comment do live_loop :sample do sample :ambi_glass_rub #, start: 0.3, finish: 0.6, rate: [0.25, 0.75, 1.25].choose sleep 0.5 end end
Clapping Music von Steve Reich
William Denton hat die „Clapping Music“ von Steve Reich in Sonic Pi umgesetzt. Solche Experimente kann man gut als Basis für eigene Versuche verwenden:
# https://www.miskatonic.org/2015/01/12/clapping-music-on-sonic-pi/ # Steve Reich's 'Clapping Music' on Sonic Pi by William Denton uncomment do use_bpm 400 load_sample :drum_tom_lo_soft load_sample :drum_tom_mid_soft clapping = (ring 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0) 13.times do |cycle| puts "Zyklus: #{cycle}" 1.times do 12.times do sample :drum_tom_lo_soft, rate: 2, pan: -0.5, amp: 1.25 if clapping.tick == 1 second = look + cycle sample :drum_tom_mid_soft, rate: 2, pan: 0.5 if clapping[second] == 1 sleep 1 end end end end # Clapping Variation, by MB comment do use_bpm 500 clapping = (ring 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0) use_synth :fm use_synth_defaults divisor: 0.05 , depth: 1, attack: 0, sustain: 0, release: 1 13.times do |cycle| 2.times do |reps| with_fx :reverb, room: 0.5, mix: 0.25 do 12.times do play :c3, pan: -1, amp: 1.25 if clapping.tick == 1 second = look + cycle play :f4, pan: -0.5, amp: 1.25 if clapping[second] == 1 third = look + (cycle * 2) play :g5, pan: -0.25, amp: 1 if clapping[third] == 1 fourth = look + (cycle * 3) play :bb3, pan: 0, amp: 1 if clapping[fourth] == 1 fifth = look + (cycle * 4) play :d4, pan: 0.5, amp: 0.75 if clapping[fifth] == 1 sixth = look + (cycle * 5) play :g5, pan: 1, amp: 0.5 if clapping[sixth] == 1 sleep 1 end end end end end
Drums
Ein einfaches Beispiel für ein Drum-Pattern, Bass, einen Hintergrundakkord und einer pentatonischen Melodie, die per Zufall variiert wird:
# Start with a very basic drum rhythm as base for a simple tune use_bpm 125 # 00: The Hihat live_loop :hihat do use_synth :cnoise use_synth_defaults release: 0.15 with_fx :hpf, cutoff: 120 do play :c sleep 0.25 end end # 01: This loop triggers a heart beat every bar # It is initially synchronized with the :hihat live_loop :bar, sync: :hihat do sleep 4 end # 02: This is the kick drum live_loop :kick, sync: :bar do with_fx :lpf, cutoff: 110 do sample :bd_haus sleep 0.25 sample :bd_haus sleep 1.5 sample :bd_haus sleep 0.25 sample :bd_haus sleep 2 end end # 03: The snare drum live_loop :snare, sync: :bar do sleep 1 with_fx :reverb, room: 0.5, mix: 0.5 do sample :drum_snare_hard, amp: 0.25 end sleep 1 end # 04: The bass bassline = (ring\ :c3, :c3, :r, :r, :r, :c3, :r, :c3, :c3, :r, :r, :r, :r, :r, :r, :r, :bb2, :bb2, :r, :r, :r, :bb2, :r, :bb2, :bb2, :r, :r, :r, :r, :eb3, :r, :bb2) live_loop :bass, sync: :bar do use_synth :fm use_synth_defaults divisor: 2, depth: 2, release: 0.25 play bassline.tick sleep 0.25 end # 05: A very simple chord pattern live_loop :chords, sync: :bar do use_synth :blade play chord(:f4, :sus4), release: 3, amp: 0.5 sleep 4 end # 06: A random melody from a pentatonic scale live_loop :melody, sync: :bar do with_fx :reverb, room: 0.5, mix: 0.5 do 8.times do play scale(:c5, :minor_pentatonic, num_octaves: 2).choose, amp: 0.25, release: 0.25 sleep [0.25, 0.5, 0.75].choose end end end
Tiny Hommage to early Detroit Techno
Schließlich ein schon aufwändigeres Beispiel. Um die einzelnen „live_loops“ zu hören, muss man im ‚Mixer‘ bei jeweiligen Instrument statt einer „0“ eine „1“ eingeben. Die „live_loop : synth2“ wird eingeblendet. Es dauert also eine Weile, bis man etwas hört:
# Re:publica 2016 # Early Detroit Techno-like Tune with Sonic Pi # Inspired by "Particle Shower" by The Martian use_bpm 125 set_sched_ahead_time! 0.5 use_debug false # Very simple Mixer ------------------------------------------------- bass = 0 kick = 0 kick_plus = 0 shaker = 0 cabasa = 0 hihat = 0 tom = 0 xylo_lo = 0 xylo_hi = 0 cowbell = 0 snare = 0 synth1 = 0 # funky synth2 = 0 # climb to the top synth3 = 0 # background melody = 0 # sweet bell synth2_vol = (range 0, 0.75, step: 0.05).ramp #synth2_vol = (ring 0.75) # Timer Loops ------------------------------------------------------- live_loop :half_beat do sleep 0.5 end live_loop :beat4 do # stop sync :half_beat sleep 4 end live_loop :beat16 do sync :half_beat # sample :elec_beep, amp: 0.75 sleep 16 end # Bass Loop -------------------------------------------------------- bs = 0.5 # sound bp = 0.095 # percussion bass_rel = (ring\ bs, bs, 0, bp, bp, bs, 0, bs, bs, 0, bp, bp, bp) bass_dur = (ring\ 0.5, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25) bass_amp = (ring\ 1.25, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1.5, 1, 1) live_loop :bass do stop if bass == 0 sync :beat4 use_synth :fm #use_synth_defaults divisor: 1, depth: 2, attack: 0, sustain: 0, cutoff: 120 use_synth_defaults divisor: 1, attack: 0, sustain: 0, amp: 1, cutoff: 130, depth: 3 #with_fx :bpf, centre: 30, res: 0.25 do 13.times do play :f1, release: bass_rel.tick, amp: bass_amp.look sleep bass_dur.look end #end end # Kick ---------------------------------------------------------------- live_loop :kick do stop if kick == 0 sync :beat4 with_fx :lpf, cutoff: 40 do 4.times do sample :bd_gas, rate: 1, amp: 3 sleep 1 end end end live_loop :kick_plus do stop if kick_plus == 0 sync :beat4 with_fx :lpf, cutoff: 40, mix: 1 do 4.times do sample :bd_zum, rate: 1, amp: 1 sleep 1 end end end # Pedal Hihat -------------------------------------------------------------- live_loop :hihat do stop if hihat == 0 sync :beat4 4.times do sleep 0.5 sample :drum_cymbal_open, start: 0.025, finish: 0.15, rate: 1.1, pan: -0.3, amp: 0.35 sleep 0.5 end end # Shaker -------------------------------------------------------------------- live_loop :shaker do stop if shaker == 0 sync :beat4 use_synth :cnoise use_synth_defaults attack: 0, sustain: 4, release: 0, amp: 5 with_fx :slicer, phase: 0.25, pulse_width: 0.35 do with_fx :hpf, cutoff: 130 do play 60 end sleep 4 end end # Tambourine --------------------------------------------------------------- live_loop :cabasa do stop if cabasa == 0 sync :beat4 use_synth :noise use_synth_defaults attack: 0.0, decay: 0.02, release: 0.05, pan: 0.75, amp: 2 with_fx :rhpf, cutoff: 123, res: 0.75, reps: 16 do if (spread 11, 16).tick then play :c1 end sleep 0.25 end end # Tom ----------------------------------------------------------------- tom_ptn = (ring 5 * 0.25, 2 * 0.25, 5 * 0.25, 2 * 0.25, 2 * 0.25) #tom_rate = (ring 1.8, 1.8, 1.8, 1.8, 1.8, 1.8, 1.8, 1.8, 2.05, 1.8) # values for fuzz tom tom_rate = (ring 2, 2, 2, 2, 2, 2, 2, 2, 2.25, 2) live_loop :tom do stop if tom == 0 sync :beat16 with_fx :reverb, room: 0.5 do 20.times do # pattern for 4 bars sample :elec_bong, start: 0, rate: tom_rate.look, amp: 1 #sample :elec_fuzz_tom, start: 0.1, finish: 1, rate: tom_rate.look, amp: 0.75 sleep tom_ptn.tick end end end # Cowbell ------------------------------------------------------------ cowbell_ptn = (ring\ 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0) cowbell_ptn2 = (ring\ 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0) live_loop :cowbell do stop if cowbell == 0 sync :beat16 with_fx :reverb, room: 0.25, mix: 0.5 do 64.times do if cowbell_ptn.tick > 0 then sample :elec_bell, rate: 2.04, pan: 0.75, amp: cowbell_ptn.look, amp: 0.75 end if cowbell_ptn2.look > 0 then #sample :elec_bell, rate: 4.08, pan: 0.75, amp: cowbell_ptn2.look * 0.75 sample :elec_bell, rate: 2.74, pan: 0.75, amp: cowbell_ptn2.look * 0.75 end sleep 0.25 end end end # xylo: lo ------------------------------------------------------------ live_loop :xylo_lo do stop if xylo_lo == 0 sync :beat4 use_synth :fm use_synth_defaults divisor: 0, depth: 1, attack: 0, sustain: 0, release: 0.25, pan: 0.3, amp: 0.5 with_fx :reverb, room: 0.5, mix: 0.5 do 4.times do sleep 0.75 play :eb4, attack: 0.25 sleep 0.25 play :g4, release: 0.25 sleep 0.25 play :f4, release: 0.25 sleep 0.75 end end end # Xylo: hi ------------------------------------------------------------ xylo_hi_nte = (ring :c5, :eb5, :c5, :c5, :c5, :eb5, :d5, :eb5) xylo_hi_ptn = (ring\ 2 * 0.25, 3 * 0.25, 2 * 0.25, 2 * 0.25, 1 * 0.25, 2 * 0.25, 2 * 0.25, 2 * 0.25) live_loop :xylo_hi do stop if xylo_hi == 0 sync :beat4 use_synth :fm use_synth_defaults divisor: 0, depth: 1, attack: 0, sustain: 0, release: 0.25, amp: 0.5, pan: 0.3 with_fx :reverb, room: 0.5, mix: 0.5 do 32.times do play xylo_hi_nte.tick sleep xylo_hi_ptn.look end end end # Snare --------------------------------------------------------------- live_loop :snare do stop if snare == 0 sync :beat4 ##| with_fx :echo, phase: [0.25, 0.5, 0.75].choose, decay: 8, mix: 0.5 do with_fx :reverb, room: 0.5, mix: 0.25 do 2.times do sleep 1 #sample :drum_snare_hard, rate: 2, pan: -0.3, amp: 1 sample :elec_hi_snare, finish: 0.75, rate: 0.75, pan: -0.3, amp: 1.0 sleep 1 end end ##| end end # Synth 1: funky ------------------------------------------------ c1 = chord_invert(chord(:c2, 'm7'), 2) c2 = chord_invert(chord(:c2, 'm7'), 1) c3 = chord_invert(chord(:c2, 'm7+9'), 1) c1 = chord_invert(chord(:c3, 'm7'), 2) c2 = chord_invert(chord(:c3, 'm7'), 1) c3 = chord_invert(chord(:c3, 'm7+9'), 1) s1_chrds = (ring\ c1, 0, c2, 0, 0, c1, 0, c1, 0, c2, 0, c3, 0, c1, c2, c3, 0, 0, c1, 0, 0, c1, 0, c1, 0, 0, c1, c1, 0, c1, c2, c3) live_loop :synth1 do stop if synth1 == 0 sync :beat16 # organ like # use_synth :fm # use_synth_defaults divisor: 0.5, depth: 2, attack: 0, sustain: 0, release: 0.25, pan: -0.5, amp: 1.5 # clavinet like use_synth :pluck use_synth_defaults release: 0.25, noise_amp: 1, coef: 0.5, amp: 5 with_fx :reverb, room: 0.25, mix: 0.25 do 128.times do if s1_chrds.tick != 0 then play s1_chrds.look end sleep 0.25 end end end # Synth 2: climb to the top ------------------------------------------------------- live_loop :synth2_climb do stop if synth2 == 0 sync :beat16 vol = synth2_vol.tick use_synth :tri use_synth :fm use_synth_defaults release: 0.25 with_fx :flanger do 8.times do sleep 0.75 play :eb5, amp: 0.4 * vol, pan: -0.6 play :c5, amp: 0.15 * vol, pan: -0.3 sleep 0.25 play :g5, amp: 0.4 * vol, pan: -0.3 play :eb5, amp: 0.15 * vol, pan: -0.1 sleep 0.25 play :f5, amp: 0.4 * vol, pan: -0.1 play :d5, amp: 0.15 * vol, pan: 0 sleep 0.25 play :a5, sustain: 0.25, release: 0.5, amp: 0.3 * vol, pan: 0.2 play :f5, sustain: 0.25, release: 0.5, amp: 0.15 * vol, pan: 0.4 sleep 0.5 end end end live_loop :synth2_top do stop if synth2 == 0 sync :beat16 vol = synth2_vol.tick use_synth :tri use_synth :fm with_fx :flanger do 8.times do sleep 0.5 play :c6, sustain: 0.25, release: 0.15, amp: 0.5 * vol, pan: 0.5 play :eb6, sustain: 0.25, release: 0.15, amp: 0.25 * vol, pan: 0.75 sleep 1.25 play :c6, sustain: 0.25, release: 0.25, amp: 0.5 * vol, pan: -0.8 play :eb6, sustain: 0.25, release: 0.5, amp: 0.15 * vol, pan: -0.8 sleep 0.25 end end end # Synth 3: background ----------------------------------------------------- synth3_inv = (ring 0, 4, 3, 4, 0) live_loop :synth3 do stop if synth3 == 0 sync :beat16 use_synth :blade use_synth_defaults vibrato_depth: 0.05, vibrato_rate: 0.5 #use_synth :dpulse #use_synth_defaults amp: 0.25, detune: 0.1, pulse_width: 0.5, dpulse_width: 0.99, cutoff: 130 with_fx :reverb, room: 0.5, mix: 0.5 do play chord_invert((ring :f5, :a5, :bb5, :c5, :eb5), synth3_inv.tick), attack: 3, sustain: 5, release: 5 sleep 16 end end # Melody: Sweet Bell ------------------------------------------------------ live_loop :melody do stop if melody == 0 sync :beat16 use_synth :beep use_synth_defaults attack: 0, sustain: 0.25, release: 0.75, pan: 0.5, amp: 0.5 with_fx :reverb, room: 0.5, mix: 0.5 do play :f6, sustain: 0.5, release: 0.5, amp: 0.8, pan: -1 sleep 0.5 * 3 play :f5, release: 0.75, pan: 0.5 sleep 0.5 * 4 play :c6, release: 0.3, pan: -0.5 sleep 0.5 * 2 play :eb6, release: 0.75, pan: 1 sleep 0.5 * 7 play :c6, release: 0.3, pan: -0.1 sleep 0.5 * 4 play :a5, sustain: 0.1, release: 0.1, pan: -1 sleep 0.5 * 1 play :bb5, sustain: 0.1, release: 0.1, pan: 1 sleep 0.5 * 1 play :c6, sustain: 0.1, release: 0.1, pan: 0 sleep 0.5 * 1 play :f5, sustain: 0.75, release: 0.1, pan: 0.5 sleep 0.5 * 9 end end
Links:
Website | http://sonic-pi.net/ |
Github | https://github.com/samaaron/sonic-pi |
Google Groups | https://groups.google.com/forum/#!forum/sonic-pi |
Live Coding-Channel (Sam Aaron) | https://www.livecoding.tv/samaaron/ |
Github (Leuphana Universität) | https://github.com/mbutz/sonicpi-leuphana-ws1516 |
Support Sonic Pi | https://www.patreon.com/samaaron |