Skip to content

Instantly share code, notes, and snippets.

@heroheman
Last active March 27, 2026 00:57
Show Gist options
  • Select an option

  • Save heroheman/7ac4a565f2f13903c4e354b8af8b94f0 to your computer and use it in GitHub Desktop.

Select an option

Save heroheman/7ac4a565f2f13903c4e354b8af8b94f0 to your computer and use it in GitHub Desktop.
Cheatsheet for Strudel.cc - german and english (ai translation)

(english version below 🇬🇧)

Cheatsheet für Strudel.cc

1. Grundlegende Syntax und Muster

Zeichen Funktion Beispiel Beschreibung
< > Sequenz <a b c> Spielt a, dann b, dann c
[ ] Stack [bd hh] Spielt bd und hh gleichzeitig
/ Division bd/2 Spielt bd mit halber Geschwindigkeit (halbe Frequenz)
* Multiplikation sd*4 Spielt sd viermal so schnell
! Zufällige Auswahl sd!3 Wählt 3 Ereignisse aus dem Pattern zufällig aus
~ Pause / Stille <a ~ b> Spielt a, dann Pause, dann b
& Parallel a&b Spielt a und b gleichzeitig (wie Stack, aber flexibler)
, Zufällige Wahl <a,b,c> Wählt zufällig eins von a, b oder c
@ Zeit-Offset bd@2 Verschiebt das Pattern um 2 Einheiten nach vorn
s() Sample abspielen s("bd") Spielt das Bassdrum-Sample
n() Noten abspielen n("c4") Spielt die Note C4

2. Samples und Instrumente

Strudel hat eine Reihe von integrierten Samples und kann auch externe Pakete laden.

Shortcut Sample Beschreibung
bd kick Bassdrum
sd snare Snare-Drum
cp clap Händeklatschen
hh hi-hat Hi-Hat (geschlossen)
oh open hi-hat Hi-Hat (offen)
cr crash cymbal Crash-Becken
ride ride cymbal Ride-Becken
lt low tom Low Tom
mt mid tom Mid Tom
ht high tom High Tom

Allgemeine Instrumente:

  • s("synth"): Ein klassischer analoger Synthesizer.
  • s("fm"): Ein FM-Synthesizer.
  • s("superfm"): Ein FM-Synthesizer mit SuperSaw-ähnlicher Oszillator.
  • s("string"): Eine Streicher-ähnliche Klangerzeugung.
  • s("am"): Ein AM-Synthesizer.
  • s("sine"): Ein einfacher Sinuswellen-Oszillator.

General MIDI (GM) Sounds:

  • s("gm_acoustic_grand_piano"): Akustisches Klavier
  • s("gm_acoustic_guitar_steel"): Akustische Stahlgitarre
  • s("gm_electric_bass_finger"): E-Bass
  • s("gm_violin"): Violine
  • ... und viele mehr, erreichbar über gm_[instrumentname].

3. Effekte und Parameter-Modifikatoren

Effekte werden mit der Punkt-Syntax an ein Pattern angehängt.

Funktion Parameter Beispiel Beschreibung
gain() 0.0 - 1.0 .gain(0.5) Stellt die Lautstärke ein
room() 0.0 - 1.0 .room(.7) Fügt Hall hinzu
delay() Zeit in Zyklen .delay(.25) Fügt ein Echo hinzu
pan() -1.0 - 1.0 .pan(-1) Position im Stereo-Panorama
lpf() Frequenz (Hz) .lpf(1000) Tiefpassfilter
hpf() Frequenz (Hz) .hpf(8000) Hochpassfilter
shape() 0.0 - 1.0 .shape(.3) Verzerrungs-Effekt
crush() 1 - 16 .crush(8) Bit-Crusher
phaser() Frequenz .phaser(4) Phaser-Effekt
speed() Wert .speed(.5) Ändert die Abspielgeschwindigkeit von Samples
note() Skala .note().scale("c:minor") Spielt die Noten als Melodie aus der Skala
chord() Akkordname .chord("Cmaj7") Spielt einen Akkord

4. Zeit, Skalen und Generative Funktionen

Funktion Beispiel Beschreibung
setcps() setcps(0.75) Setzt die Geschwindigkeit in Cycles per Second (Zyklen pro Sekunde)
setbpm() setbpm(120) Setzt die Geschwindigkeit in Beats per Minute (Schläge pro Minute)
rand() rand.range(0,1) Erzeugt eine zufällige Zahl
perlin() perlin.range(.6, .9) Erzeugt sanft fließende Zufallswerte (Perlin-Noise)
sine() sine.range(1, 10) Erzeugt eine Sinuswelle
scale() scale("c:minor") Wandelt Noten in eine bestimmte Tonleiter um
pick() pick([a,b,c]) Wählt ein Pattern aus einer Liste aus
pickRestart() pickRestart([a,b]) Wählt ein Pattern und startet von vorn, wenn es beendet ist

Strudel.cc Cheatsheet

1. Basic Syntax and Patterns

Symbol Function Example Description
< > Sequence <a b c> Plays a, then b, then c
[ ] Stack [bd hh] Plays bd and hh simultaneously
/ Division bd/2 Plays bd at half speed (half frequency)
* Multiplication sd*4 Plays sd four times as fast
! Random Pick sd!3 Randomly picks 3 events from the pattern
~ Rest / Silence <a ~ b> Plays a, then a pause, then b
& Parallel a&b Plays a and b simultaneously (like Stack, but more flexible)
, Random Choice <a,b,c> Randomly chooses one of a, b, or c
@ Time Offset bd@2 Shifts the pattern forward by 2 units
s() Play Sample s("bd") Plays the bass drum sample
n() Play Notes n("c4") Plays the note C4

2. Samples and Instruments

Strudel has a range of built-in samples and can also load external packages.

Shortcut Sample Description
bd kick Bass drum
sd snare Snare drum
cp clap Hand clap
hh hi-hat Hi-hat (closed)
oh open hi-hat Hi-hat (open)
cr crash cymbal Crash cymbal
ride ride cymbal Ride cymbal
lt low tom Low tom
mt mid tom Mid tom
ht high tom High tom

General Instruments:

  • s("synth"): A classic analog synthesizer.
  • s("fm"): An FM synthesizer.
  • s("superfm"): An FM synthesizer with a SuperSaw-like oscillator.
  • s("string"): A string-like sound generator.
  • s("am"): An AM synthesizer.
  • s("sine"): A simple sine wave oscillator.

General MIDI (GM) Sounds:

  • s("gm_acoustic_grand_piano"): Acoustic piano
  • s("gm_acoustic_guitar_steel"): Acoustic steel guitar
  • s("gm_electric_bass_finger"): Electric bass
  • s("gm_violin"): Violin
  • ... and many more, accessible via gm_[instrumentname].

3. Effects and Parameter Modifiers

Effects are attached to a pattern using dot syntax.

Function Parameter Example Description
gain() 0.0 - 1.0 .gain(0.5) Adjusts the volume
room() 0.0 - 1.0 .room(.7) Adds reverb
delay() Time in cycles .delay(.25) Adds an echo
pan() -1.0 - 1.0 .pan(-1) Position in the stereo field
lpf() Frequency (Hz) .lpf(1000) Low-pass filter
hpf() Frequency (Hz) .hpf(8000) High-pass filter
shape() 0.0 - 1.0 .shape(.3) Distortion effect
crush() 1 - 16 .crush(8) Bit-crusher
phaser() Frequency .phaser(4) Phaser effect
speed() Value .speed(.5) Changes sample playback speed
note() Scale .note().scale("c:minor") Plays notes as a melody from the scale
chord() Chord name .chord("Cmaj7") Plays a chord

4. Time, Scales, and Generative Functions

Function Example Description
setcps() setcps(0.75) Sets speed in Cycles per Second
setbpm() setbpm(120) Sets speed in Beats per Minute
rand() rand.range(0,1) Generates a random number
perlin() perlin.range(.6, .9) Generates smooth random values (Perlin noise)
sine() sine.range(1, 10) Generates a sine wave
scale() scale("c:minor") Maps notes to a specific scale
pick() pick([a,b,c]) Selects a pattern from a list
pickRestart() pickRestart([a,b]) Selects a pattern and restarts it when finished

Schlüsselkonzepte

  1. Patterns: Strudel arbeitet ausschließlich mit Patterns. Ein Pattern ist ein sich wiederholendes Muster, das musikalische Ereignisse über einen bestimmten Zeitraum hinweg erzeugt. Das System basiert auf Zyklen, wobei ein Zyklus die Dauer eines Patterns angibt.
  2. Mini-Notation: Die Mini-Notation ist die Sprache von Strudel. Sie verwendet Symbole wie < >, [ ], /, *, und @, um komplexe rhythmische und melodische Strukturen zu beschreiben.
    • < > gruppiert Patterns und spielt sie nacheinander ab. Beispiel: <bd sd hh> spielt Bassdrum, Snare und Hi-Hat in dieser Reihenfolge.
    • [ ] stapelt Patterns und spielt sie gleichzeitig ab. Beispiel: [bd hh] spielt Bassdrum und Hi-Hat gleichzeitig.
    • * wiederholt Patterns. Beispiel: bd*4 spielt die Bassdrum viermal pro Zyklus.
    • / teilt Patterns auf. Beispiel: bd/2 spielt die Bassdrum mit halber Geschwindigkeit.
    • ! wählt Patterns aus einer Liste. Beispiel: bd!2 wählt zwei Patterns nach dem Zufallsprinzip aus.
    • @ ändert die Abspielgeschwindigkeit oder verzögert. Beispiel: bd@2 spielt die Bassdrum in doppelter Geschwindigkeit.
  3. Generative Musik: Strudel ermöglicht es, dynamische und sich ständig verändernde Musik zu kreieren. Funktionen wie sine, perlin, oder rand können verwendet werden, um Parameter wie Lautstärke, Tonhöhe oder Tempo kontinuierlich zu modulieren.

Annotation der Beispielsongs

1. "coastline" - Link

Dieser Song zeigt, wie man komplexe, sich überlagernde Rhythmen und Melodien erzeugt und dabei Patterns mit Effekten moduliert.

  • samples('github:eddyflux/crate'): Lädt ein externes Sample-Pack von GitHub, das unter dem Namen 'crate' verfügbar ist.
  • setcps(.75): Setzt die Geschwindigkeit auf 0.75 Cycles per Second (Zyklen pro Sekunde), was ein langsameres Tempo ergibt.
  • let chords = chord("<Bbm9 Fm9>/4").dict('ireal'): Definiert ein Pattern von Akkorden. Die Notation <Bbm9 Fm9>/4 bedeutet, dass die Akkorde in Gruppen von vier Vierteln pro Zyklus gespielt werden. .dict('ireal') ist eine Funktion, die die Akkordnamen in spielbare Noten umwandelt.
  • stack( ... ): Stapelt mehrere Patterns, sodass sie gleichzeitig laufen. Dies wird für die Schlagzeug-, Akkord- und Melodie-Patterns verwendet.
  • s("bd").struct("<[x*<1 2> [~@3 x]] x>"): Spielt das bd (Bassdrum) Sample ab. .struct(...) wendet eine komplexe rhythmische Struktur an, die von [x*<1 2> [~@3 x]] und x beschrieben wird, um einen vielschichtigen Beat zu erzeugen.
  • n("[0 <1 3>]*<2!3 4>").s("hh"): Spielt die Hi-Hat. n(...) wählt die Noten. [0 <1 3>]*<2!3 4> ist eine rhythmische und melodische Mini-Notation, die die Noten 0, 1 und 3 in einem bestimmten Muster spielt, das von den folgenden rhythmischen Modifikatoren beeinflusst wird.
  • .mask("<[0 1] 1 1 1>/16"): Wendet eine Maske auf das Pattern an. Die Maske lässt nur bestimmte Teile des Patterns durch, was einen Effekt wie beim Clave-Rhythmus erzeugt. Die Notation <[0 1] 1 1 1>/16 spielt in einem 16-tel-Raster, wobei nur die erste Note des ersten Patterns durchkommt.
  • .phaser(4).room(.5): Fügt einen Phaser-Effekt mit einer Frequenz von 4 und einen Hall-Effekt (room) mit einer Stärke von 0.5 hinzu.
  • .gain(perlin.range(.6, .9)): Moduliert die Lautstärke (gain) mit einem Perlin-Noise-Pattern, das zufällige, aber sanft fließende Werte zwischen 0.6 und 0.9 erzeugt.
// "coastline" @by eddyflux
// @version 1.0
samples('github:eddyflux/crate')
setcps(.75)
let chords = chord("<Bbm9 Fm9>/4").dict('ireal')
stack(
  stack( // DRUMS
    s("bd").struct("<[x*<1 2> [~@3 x]] x>"),
    s("~ [rim, sd:<2 3>]").room("<0 .2>"),
    n("[0 <1 3>]*<2!3 4>").s("hh"),
    s("rd:<1!3 2>*2").mask("<0 0 1 1>/16").gain(.5)
  ).bank('crate')
  .mask("<[0 1] 1 1 1>/16".early(.5))
  , // CHORDS
  chords.offset(-1).voicing().s("gm_epiano1:1")
  .phaser(4).room(.5)
  , // MELODY
  n("<0!3 1*2>").set(chords).mode("root:g2")
  .voicing().s("gm_acoustic_bass"),
  chords.n("[0 <4 3 <2 5>>*2](<3 5>,8)")
  .anchor("D5").voicing()
  .segment(4).clip(rand.range(.4,.8))
  .room(.75).shape(.3).delay(.25)
  .fm(sine.range(3,8).slow(8))
  .lpf(sine.range(500,1000).slow(8)).lpq(5)
  .rarely(ply("2")).chunk(4, fast(2))
  .gain(perlin.range(.6, .9))
  .mask("<0 1 1 0>/16")
)
.late("[0 .01]*4").late("[0 .01]*2").size(4)

2. "Waltz #2" (cps function demo) - Link

Dieses Stück demonstriert die dynamische Modulation des Tempos.

  • setDefaultVoicings('legacy'): Setzt das Standard-Voicing für Akkorde auf 'legacy', was die Art und Weise der Notenverteilung in Akkorden beeinflusst.
  • melody: "<...>" .scale("c4:minor").note().s("gm_oboe:2"): Definiert ein Melodie-Pattern, das mit pickRestart aus einer Liste von Unter-Patterns zufällig ausgewählt wird. .scale("c4:minor") wendet eine c-Moll-Tonleiter an, wodurch alle Noten innerhalb dieser Skala bleiben. s("gm_oboe:2") weist der Melodie den Klang einer Oboe zu.
  • tempochanges: cps(sine.segment(32).slow(16).mul(30).add(160).div(60*3)): Dies ist der komplexeste Teil. Es moduliert das Tempo (cps) dynamisch.
    • sine: Erzeugt ein Sinuswellen-Pattern, das sanfte, periodische Werte erzeugt.
    • .segment(32): Teilt die Sinuswelle in 32 Segmente pro Zyklus.
    • .slow(16): Verlangsamt das Pattern auf 1/16 der Normalgeschwindigkeit.
    • .mul(30).add(160).div(60*3): Skaliert und verschiebt die Werte der Sinuswelle, um ein Tempo im Bereich von ca. 1.6 bis 3.1 Zyklen pro Sekunde (96 bis 186 BPM) zu erzeugen, und konvertiert dieses auf eine für cps verständliche Zahl.
  • all(x=>x.room(0.6)): Wendet den Raum-Effekt (room) mit einer Stärke von 0.6 auf alle aktiven Patterns an.
// "Waltz #2" (cps function demo)
// composed @by Dmitri Shostakovich
// script @by eefano
setDefaultVoicings('legacy')

melody: "<~@4 0@16 1@7 2@11.5 ~@3.5>".pickRestart([
  `<4 [2@2 1] [0@4 0 1]@2 [2 0 2] [4@2 5] 4 3 
    3 [1@2 0] [0b@4 -3 0b]@2 [1 0b 1] [3 4 5] 4b 4>`,
    "<[9,7] [[8,6]@2 [7,5]] [[6,4]@2 [5,3]] [3,0] [8,6] [[7,5]@2 [6,4]] [6,4]>", 
  "<[~ [2 ~] [3 ~]] [[4 ~] [4 3] [4 5]] [[3 ~] [3 2] [3 4]] [[2 ~] ~ [4 ~]] > ".sub("<0 0 [0,2]>/4") ])
      .scale("c4:minor").note().s("gm_oboe:2").gain(0.7)._pianoroll({minMidi:10})
   
piano: "<0@28 1@10 0@4>".pickRestart([
     n("<<0 -1> [4,5]!2>*3").chord("<Cm@10 Fm@4 G@4 Cm@4 Fm@2 Bb@2 Eb Ab>"),
     n("<3 <[4,5] > ~>*3").chord("<G Ab Cm Ab>")
          ]).anchor('f2').mode('root').voicing().piano()._pianoroll()

tempochanges: cps(sine.segment(32).slow(16).mul(30).add(160).div(60*3)).gain(0)

all(x=>x
  //.ribbon(24,16)
  .room(0.6))
// @version 1.2

3. "Pyramid Song (wip)" - link

Dieses Beispiel demonstriert fortgeschrittene Techniken, darunter benutzerdefinierte Funktionen und komplexe Pattern-Manipulation.

  • setcps(104/60/4): Stellt das Tempo auf 104 BPM, aber geteilt durch 4, was ein sehr langsames, atmosphärisches Tempo erzeugt.
  • const split = register(...): register ist eine der wichtigsten Funktionen dieses Stücks. Sie wird verwendet, um eine neue, benutzerdefinierte Funktion zu definieren, die in diesem Fall split genannt wird. Diese Funktion ist nicht standardmäßig in Strudel enthalten und ermöglicht es dem Programmierer, eine völlig neue Art der Pattern-Verarbeitung zu erschaffen.
  • let chr = { ... }: Definiert ein Objekt (chr), das Akkorde als Key-Value-Paare speichert. Dies dient als Nachschlagewerk für die Akkord-Sequenzierung.
  • piano: "<...>" .split([0,.5],(x)=>x[0].pickOut(chr).velocity(x[1])): Das Piano-Pattern ist extrem komplex. Es verwendet die benutzerdefinierte split-Funktion, um das Hauptpattern <[i1 i2 i3 i4] ooooh ...> aufzuteilen und zu verarbeiten. [0, .5] sind die Werte, die für die Verarbeitung übergeben werden. Die Funktion verwendet .pickOut(chr) um Noten aus dem chr-Objekt basierend auf den in der Notation definierten Keys (z.B. X, Y, Z) auszuwählen. velocity(x[1]) verwendet den zweiten Wert 0.5 der split-Funktion, um die Anschlagsstärke der Noten zu bestimmen.
  • ooooh: "<~ 0 ~@4 0@2 ~@8>/8" ... .penv(x[1]).patt(0.04).s("triangle")...: Dieses Pattern erzeugt einen atmosphärischen Synthesizer-Sound. .s("triangle") wählt einen einfachen Dreieckswellen-Synth.
    • .penv(x[1]): Steuert die Hüllkurve (Anschlag, Sustain, Decay). x[1] ist hier wieder der Wert aus der split-Funktion, was zeigt, wie die Notenhülle dynamisch gesteuert wird.
    • .vmod(.1).vib(5): Fügt einen Vibrato-Effekt mit einer Stärke von 0.1 und einer Frequenz von 5 hinzu.
// "Pyramid Song (wip)"
// song @by Radiohead
// script @by eefano
setcps(104/60/4)
const split = register('split', (deflt, callback, pat) => callback(deflt.map((d,i)=> pat.withValue((v)=>{
  const isobj = v.value !== undefined; const value = isobj ? v.value : v;
  const result = Array.isArray(value)?(i<value.length?value[i]:d):(i==0?value:d);
  return (i==0 && isobj) ? {...v,value:result} : result; }))));

let chr = {X:"f#2,c#3,a#3,c#4,f#4", Y:"g2,d3,b3,d4,f#4", Z:"a2,e3,a3,c#4,f#4", J:"g2,d3,b3,d4,g4", K:"f#2,c#3,a#3,c#4,g4",
           V:"f#2,c#3,a3,c#4,f#4", W:"e2,b2,g#3,b3,f#4"}

piano: "<[i1 i2 i3 i4] ooooh [v1 v2]!4 ooooh@2 [v1 v2]!3 [v1 v3] [v3 v2] [i1 i2 i3 i2] [i3 i2 i3 i2] end>/8".pickRestart(
 {i1:`<[[X:.6 X:.8]@3 Y:.5@2 [Z:.5 Z:.5]@3]>/2`, i2: `<[[Z:.4 Y:.4]@3 Y:.3@2 [J:.6 J:.9]@3]>/2`, 
  i3:`<[[K:.8 X:.6]@3 Y:.5@2 [Z:.5 Z:.5]@3]>/2`, i4: `<[[Z:.4 Y:.4]@3 Y:.4@2 [Y:.4 Y:.7]@3]>/2`,
  ooooh:`<[[X X]@3 Y@2 [Z Z]@3] [[Z Y]@3 Y@2 [X X]@3] [[X X]@3 Y@2 [Z Z]@3] [[Z Y]@3 Y@2 [Y Y]@3]>/2`,
  v1:`<[[X X]@3 Y@2 [Z Z]@3] [[Z Y]@3 Y@2 [X X]@3]>/2`,
  v2:`<[[V V]@3 W@2 [W W]@3] [[Y Y]@3 Y@2 [Y Y]@3]>/2`,
  v3:`<[[V V]@3 W@2 [W W]@3] [[Y Y]@3 X@2 [X X]@3]>/2`,
  end:`<X:1>/8`, 
 }).split([0,.5],(x)=>x[0].pickOut(chr).velocity(x[1])).note().piano().gain(0.8).room(.6)

ooooh: "<~ 0 ~@4 0@2 ~@8>/8".pickRestart([
  "<f#5@11 e5:-2 g#5:4 e5:-4 [f#5:2 ~] [~ g#5 e5] f#5@4 g#5 f#5 e5 d5 c#5@5 ~@3>*4"
  ]).split([0,0],(x)=>x[0].penv(x[1])).patt(0.04).s("triangle").attack(.08).release(.08).note().vmod(.1).vib(5).gain(0.3).lpf(2000).room(1.5)

drums: "<~@6 [~@15 0@15 1@2] [2,3]@8 3>/8".pick([
  "<[bd,rd] ~ [~ sf*3] [bd,rd] ~ [~ sf*3] [bd,rd] ~ ~ [~ sf*3] [bd,rd] ~ [~ sf*3] [bd,rd] ~ [~ sf*3]>*8",
  "<[sd sf bd] [sf sd sd]>*4",
  "<[rd*4],[<~ ~ ~ bd ~ bd ~ ~ bd ~ bd ~ ~ bd ~ bd> <~!14 sf!2> <~ sd bd ~ sd ~ sd bd ~ sd ~ ~ sd ~ sd sd>]*4>",
  "<cr,bd>/8",
]).pickOut({
  bd: s('bd').bank('Linn9000').lpf(1000),
  sd: s('sd').bank('RolandMT32').velocity(.5),
  sf: s('sd').bank('RolandMT32').velocity(.2),
  rd: s('rd').bank('Linn9000').velocity(0.3).hpf(8000),
  mt: s('mt').bank('RolandMT32'),
  lt: s('lt').bank('RolandMT32'),
  cr: s('cr').bank('Linn9000').speed(0.4).velocity(0.3).hpf(4000),
}).room(.2).gain(0.5)
// @version 1.2

Key Concepts

  1. Patterns: Strudel works exclusively with patterns. A pattern is a repeating cycle that generates musical events over a specific period. The system is based on cycles, where one cycle defines the duration of a pattern.
  2. Mini-Notation: Mini-notation is the language of Strudel. It uses symbols like < >, [ ], /, *, and @ to describe complex rhythmic and melodic structures.
    • < > groups patterns and plays them sequentially. Example: <bd sd hh> plays bass drum, snare, and hi-hat in that order.
    • [ ] stacks patterns and plays them simultaneously. Example: [bd hh] plays bass drum and hi-hat at the same time.
    • * repeats patterns. Example: bd*4 plays the bass drum four times per cycle.
    • / divides patterns. Example: bd/2 plays the bass drum at half speed.
    • ! selects patterns from a list. Example: bd!2 selects two patterns randomly.
    • @ changes playback speed or adds delay. Example: bd@2 plays the bass drum at double speed.
  3. Generative Music: Strudel allows for the creation of dynamic and ever-changing music. Functions like sine, perlin, or rand can be used to continuously modulate parameters such as volume, pitch, or tempo.

Annotation of Example Songs

1. "coastline" - Link

This song demonstrates how to create complex, overlapping rhythms and melodies while modulating patterns with effects.

  • samples('github:eddyflux/crate'): Loads an external sample pack from GitHub, available under the name 'crate'.
  • setcps(.75): Sets the speed to 0.75 Cycles per Second, resulting in a slower tempo.
  • let chords = chord("<Bbm9 Fm9>/4").dict('ireal'): Defines a pattern of chords. The notation <Bbm9 Fm9>/4 means chords are played in groups of four quarter-notes per cycle. .dict('ireal') converts chord names into playable notes.
  • stack( ... ): Layers multiple patterns so they run simultaneously. Used here for drums, chords, and melody.
  • s("bd").struct("<[x*<1 2> [~@3 x]] x>"): Plays the bd (bass drum) sample. .struct(...) applies a complex rhythmic structure to create a multi-layered beat.
  • n("[0 <1 3>]*<2!3 4>").s("hh"): Plays the hi-hat. n(...) selects the notes. The mini-notation plays notes 0, 1, and 3 in a pattern influenced by rhythmic modifiers.
  • .mask("<[0 1] 1 1 1>/16"): Applies a mask to the pattern. It only lets specific parts through, creating an effect similar to a clave rhythm.
  • .phaser(4).room(.5): Adds a phaser effect (freq 4) and reverb (room, strength 0.5).
  • .gain(perlin.range(.6, .9)): Modulates the volume (gain) using a Perlin noise pattern, creating smooth, random fluctuations between 0.6 and 0.9.
// "coastline" @by eddyflux
// @version 1.0
samples('github:eddyflux/crate')
setcps(.75)
let chords = chord("<Bbm9 Fm9>/4").dict('ireal')
stack(
  stack( // DRUMS
    s("bd").struct("<[x*<1 2> [~@3 x]] x>"),
    s("~ [rim, sd:<2 3>]").room("<0 .2>"),
    n("[0 <1 3>]*<2!3 4>").s("hh"),
    s("rd:<1!3 2>*2").mask("<0 0 1 1>/16").gain(.5)
  ).bank('crate')
  .mask("<[0 1] 1 1 1>/16".early(.5))
  , // CHORDS
  chords.offset(-1).voicing().s("gm_epiano1:1")
  .phaser(4).room(.5)
  , // MELODY
  n("<0!3 1*2>").set(chords).mode("root:g2")
  .voicing().s("gm_acoustic_bass"),
  chords.n("[0 <4 3 <2 5>>*2](<3 5>,8)")
  .anchor("D5").voicing()
  .segment(4).clip(rand.range(.4,.8))
  .room(.75).shape(.3).delay(.25)
  .fm(sine.range(3,8).slow(8))
  .lpf(sine.range(500,1000).slow(8)).lpq(5)
  .rarely(ply("2")).chunk(4, fast(2))
  .gain(perlin.range(.6, .9))
  .mask("<0 1 1 0>/16")
)
.late("[0 .01]*4").late("[0 .01]*2").size(4)

2. "Waltz #2" (cps function demo) - Link

This piece demonstrates the dynamic modulation of tempo.

  • setDefaultVoicings('legacy'): Sets default chord voicing to 'legacy', affecting how notes are distributed in chords.
  • melody: "<...>" .scale("c4:minor").note().s("gm_oboe:2"): Defines a melody pattern randomly selected from a list using pickRestart. .scale("c4:minor") applies a C minor scale. s("gm_oboe:2") assigns an oboe sound.
  • tempochanges: cps(sine.segment(32).slow(16).mul(30).add(160).div(60*3)): The most complex part, modulating tempo (cps) dynamically:
    • sine: Generates a smooth periodic wave.
    • .segment(32): Samples the wave into 32 segments per cycle.
    • .slow(16): Slows the pattern to 1/16 speed.
    • .mul(30).add(160).div(60*3): Scales and shifts values to a range of approx. 1.6 to 3.1 cycles per second (96 to 186 BPM).
  • all(x=>x.room(0.6)): Applies reverb (room) at 0.6 strength to all active patterns.
// "Waltz #2" (cps function demo)
// composed @by Dmitri Shostakovich
// script @by eefano
setDefaultVoicings('legacy')

melody: "<~@4 0@16 1@7 2@11.5 ~@3.5>".pickRestart([
  `<4 [2@2 1] [0@4 0 1]@2 [2 0 2] [4@2 5] 4 3 
    3 [1@2 0] [0b@4 -3 0b]@2 [1 0b 1] [3 4 5] 4b 4>`,
    "<[9,7] [[8,6]@2 [7,5]] [[6,4]@2 [5,3]] [3,0] [8,6] [[7,5]@2 [6,4]] [6,4]>", 
  "<[~ [2 ~] [3 ~]] [[4 ~] [4 3] [4 5]] [[3 ~] [3 2] [3 4]] [[2 ~] ~ [4 ~]] > ".sub("<0 0 [0,2]>/4") ])
      .scale("c4:minor").note().s("gm_oboe:2").gain(0.7)._pianoroll({minMidi:10})
   
piano: "<0@28 1@10 0@4>".pickRestart([
     n("<<0 -1> [4,5]!2>*3").chord("<Cm@10 Fm@4 G@4 Cm@4 Fm@2 Bb@2 Eb Ab>"),
     n("<3 <[4,5] > ~>*3").chord("<G Ab Cm Ab>")
          ]).anchor('f2').mode('root').voicing().piano()._pianoroll()

tempochanges: cps(sine.segment(32).slow(16).mul(30).add(160).div(60*3)).gain(0)

all(x=>x
  //.ribbon(24,16)
  .room(0.6))
// @version 1.2

3. "Pyramid Song (wip)" - Link

This example demonstrates advanced techniques, including custom functions and complex pattern manipulation.

  • setcps(104/60/4): Sets the tempo to 104 BPM divided by 4, creating a very slow, atmospheric pace.
  • const split = register(...): register is used to define a new, custom function called split. This allows the creator to build entirely new pattern processing logic not included in standard Strudel.
  • let chr = { ... }: Defines an object (chr) that stores chords as key-value pairs, serving as a lookup table for chord sequencing.
  • piano: "<...>" .split([0,.5],(x)=>x[0].pickOut(chr).velocity(x[1])): The piano pattern is extremely complex. It uses the custom split function to process the main pattern. .pickOut(chr) selects notes from the chr object based on keys like X, Y, Z. velocity(x[1]) uses the split value to determine touch sensitivity.
  • ooooh: "<~ 0 ~@4 0@2 ~@8>/8" ... .penv(x[1]).patt(0.04).s("triangle")...: Creates an atmospheric synth sound. .s("triangle") selects a simple triangle wave.
    • .penv(x[1]): Controls the envelope (attack, sustain, decay) dynamically.
    • .vmod(.1).vib(5): Adds a vibrato effect (strength 0.1, frequency 5).
// "Pyramid Song (wip)"
// song @by Radiohead
// script @by eefano
setcps(104/60/4)
const split = register('split', (deflt, callback, pat) => callback(deflt.map((d,i)=> pat.withValue((v)=>{
  const isobj = v.value !== undefined; const value = isobj ? v.value : v;
  const result = Array.isArray(value)?(i<value.length?value[i]:d):(i==0?value:d);
  return (i==0 && isobj) ? {...v,value:result} : result; }))));

let chr = {X:"f#2,c#3,a#3,c#4,f#4", Y:"g2,d3,b3,d4,f#4", Z:"a2,e3,a3,c#4,f#4", J:"g2,d3,b3,d4,g4", K:"f#2,c#3,a#3,c#4,g4",
           V:"f#2,c#3,a3,c#4,f#4", W:"e2,b2,g#3,b3,f#4"}

piano: "<[i1 i2 i3 i4] ooooh [v1 v2]!4 ooooh@2 [v1 v2]!3 [v1 v3] [v3 v2] [i1 i2 i3 i2] [i3 i2 i3 i2] end>/8".pickRestart(
 {i1:`<[[X:.6 X:.8]@3 Y:.5@2 [Z:.5 Z:.5]@3]>/2`, i2: `<[[Z:.4 Y:.4]@3 Y:.3@2 [J:.6 J:.9]@3]>/2`, 
  i3:`<[[K:.8 X:.6]@3 Y:.5@2 [Z:.5 Z:.5]@3]>/2`, i4: `<[[Z:.4 Y:.4]@3 Y:.4@2 [Y:.4 Y:.7]@3]>/2`,
  ooooh:`<[[X X]@3 Y@2 [Z Z]@3] [[Z Y]@3 Y@2 [X X]@3] [[X X]@3 Y@2 [Z Z]@3] [[Z Y]@3 Y@2 [Y Y]@3]>/2`,
  v1:`<[[X X]@3 Y@2 [Z Z]@3] [[Z Y]@3 Y@2 [X X]@3]>/2`,
  v2:`<[[V V]@3 W@2 [W W]@3] [[Y Y]@3 Y@2 [Y Y]@3]>/2`,
  v3:`<[[V V]@3 W@2 [W W]@3] [[Y Y]@3 X@2 [X X]@3]>/2`,
  end:`<X:1>/8`, 
 }).split([0,.5],(x)=>x[0].pickOut(chr).velocity(x[1])).note().piano().gain(0.8).room(.6)

ooooh: "<~ 0 ~@4 0@2 ~@8>/8".pickRestart([
  "<f#5@11 e5:-2 g#5:4 e5:-4 [f#5:2 ~] [~ g#5 e5] f#5@4 g#5 f#5 e5 d5 c#5@5 ~@3>*4"
  ]).split([0,0],(x)=>x[0].penv(x[1])).patt(0.04).s("triangle").attack(.08).release(.08).note().vmod(.1).vib(5).gain(0.3).lpf(2000).room(1.5)

drums: "<~@6 [~@15 0@15 1@2] [2,3]@8 3>/8".pick([
  "<[bd,rd] ~ [~ sf*3] [bd,rd] ~ [~ sf*3] [bd,rd] ~ ~ [~ sf*3] [bd,rd] ~ [~ sf*3] [bd,rd] ~ [~ sf*3]>*8",
  "<[sd sf bd] [sf sd sd]>*4",
  "<[rd*4],[<~ ~ ~ bd ~ bd ~ ~ bd ~ bd ~ ~ bd ~ bd> <~!14 sf!2> <~ sd bd ~ sd ~ sd bd ~ sd ~ ~ sd ~ sd sd>]*4>",
  "<cr,bd>/8",
]).pickOut({
  bd: s('bd').bank('Linn9000').lpf(1000),
  sd: s('sd').bank('RolandMT32').velocity(.5),
  sf: s('sd').bank('RolandMT32').velocity(.2),
  rd: s('rd').bank('Linn9000').velocity(0.3).hpf(8000),
  mt: s('mt').bank('RolandMT32'),
  lt: s('lt').bank('RolandMT32'),
  cr: s('cr').bank('Linn9000').speed(0.4).velocity(0.3).hpf(4000),
}).room(.2).gain(0.5)
// @version 1.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment