Strudel tutorial: your first loop
Every song in Shawarma is Strudel code: a language for making music by writing short patterns. You type a line, it plays in a loop, and you change it while it plays. This guide goes from one drum sound to a short song with drums, bass and chords. Each example runs as it is in Shawarma.
Cycles: how the code counts time
The music is built from cycles. A cycle is one turn of the loop, and a pattern fills one cycle unless you tell it otherwise. By default a cycle lasts two seconds. If you count four beats to a cycle, that is 120 beats per minute (BPM).
This is the one idea to hold on to: the more steps you put in a pattern, the shorter each step gets, because they all share the same cycle.
Your first loop
s plays sounds by name. bd is a bass drum (a kick) and sd is a snare:
s("bd sd")Add steps and they get shorter. hh is a closed hi-hat:
s("bd hh sd hh")The text inside the quotes is called mini-notation. It is a small language for rhythm, and most of the music happens inside those quotes.
Rests, repeats and groups
A ~ is a rest: the step is there but silent.
s("bd ~ sd ~")* repeats a step inside its own space. bd*2 plays two kicks where one would be:
s("bd*2 sd bd sd")Square brackets squeeze several steps into one. Here the second and fourth steps are split in two. oh is an open hi-hat:
s("bd [sd sd] hh [hh oh]")Angle brackets play one item per cycle, taking turns. This plays a snare on the first cycle and a clap (cp) on the next:
s("bd <sd cp> bd <sd [cp cp]>")Layers
A comma inside the quotes plays patterns at the same time. Three layers: a kick on every beat, hats between the beats, a snare on beats two and four.
s("bd*4, [~ hh]*4, ~ sd ~ sd")The same thing with stack, which keeps each layer on its own line. This is easier to read once layers get longer, and you can give each one its own effects.
stack(
s("bd*4"),
s("[~ hh]*4"),
s("~ sd ~ sd"),
)Notes and chords
note plays pitches. Write a note name, an optional # or b, and an octave: c4 is middle C, c3 the C below it. .s("piano") chooses the instrument; without it you hear a plain triangle-wave synth.
note("c3 e3 g3 b3") .s("piano")Numbers work too. They are MIDI note numbers, where 60 is middle C:
note("48 52 55 59") .s("piano")Put notes inside brackets with commas between them to play a chord. Inside angle brackets, you get one chord per cycle:
note("<[c3,e3,g3] [a2,c3,e3] [f2,a2,c3] [g2,b2,d3]>") .s("piano")Scales
With n and scale you write steps of a scale instead of note names. 0 is the first note of the scale, 2 the third, 4 the fifth. Any step stays in key, so it is hard to play a wrong note.
n("0 2 4 <6 7>") .scale("C4:minor") .s("piano")Scale names follow the root and octave after a colon: C4:major, A3:minor, D4:dorian, E3:phrygian, G4:pentatonic.
Choosing sounds
There are a few built-in synths: sawtooth, square, triangle and sine. This plays the same bass line through each in turn:
note("c2 c3 eb2 g2") .s("<sawtooth square triangle sine>")Instruments named gm_… are General MIDI recordings: guitars, strings, organs, brass and more (the cheat sheet lists some).
note("d4 f4 a4 c5") .s("gm_acoustic_guitar_nylon")Most drum sounds have several recordings. A number after a colon picks one, counting from 0:
s("hh hh:1 hh:2 hh:1")Tempo
setcpm sets the tempo in cycles per minute. With four beats to a cycle, divide the BPM you want by 4. You can write the sum and let the code work it out:
setcpm(124/4) // 124 BPM, four beats to a cycle
s("bd*4, [~ hh]*4")Effects
Functions after a dot change how a pattern sounds, and you can chain as many as you like. lpf is a low-pass filter (lower numbers sound darker), gain is volume, room is reverb.
note("c2 c2 eb2 g1") .s("sawtooth")
.lpf(600)
.gain(.6)
.room(.4)An effect can take a pattern too. Here the hats get a volume pattern, loud, soft, medium, soft, repeated twice per cycle, which makes a straight line of hats groove:
s("hh*8") .gain("[.9 .4 .6 .4]*2")Movement and change
sine is a value that rises and falls smoothly. range sets how far it moves and slow(8) makes one sweep take eight cycles. Used on the filter, it opens and closes the sound over time:
note("c2*8") .s("sawtooth") .lpf(sine .range(300, 2000) .slow(8))lastOf changes every fourth cycle (or any number you give it), which is a quick way to get a fill at the end of a phrase:
s("bd ~ sd ~") .lastOf(4, x => x .fast(2))Putting it together
Name each part with const, then stack them. This is how most songs in Shawarma are laid out, so you can find a part and change it.
setcpm(30) // 120 BPM
const drums = s("bd*4, [~ cp]*2, [~ hh]*4") .gain(.8)
const bass = note("<[c2*4] [a1*4] [f1*4] [g1*4]>") .s("sawtooth") .lpf(600) .gain(.5)
const keys = note("<[c4,e4,g4] [c4,e4,a4] [c4,f4,a4] [b3,d4,g4]>")
.s("piano") .struct("~ x ~ x") .gain(.5)
stack(drums, bass, keys)From here, try changing one thing at a time: a note in the bass, the number in lpf, a step in the drums. The drum patterns guide goes further with rhythm, and the example songs show longer pieces with an intro and sections built with arrange.
Try it in Shawarma
Shawarma is a music editor where every song is code. Your song plays on a loop; ask the assistant for a change in plain words, listen to it, and keep it only if you like it. Or edit the code yourself, as in this guide. The editor is free, with 5 assistant replies to try it; Pro starts with 7 days free.