making music with code, in the web with js

more detailed notes

my attempts

⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⣼⣿⣿⣦⠀⠀⠀ ⠀⠀⠀⠀⠀⢰⣿⠁⠀⢹⡄⠀⠀ ⠀⠀⠀⠀⠀⢸⣿⠀⠀⣾⡇⠀⠀ ⠀⠀⠀⠀⠀⠈⣿⢀⣾⣿⠀⠀⠀ ⠀⠀⠀⠀⠀⣀⣿⣿⣿⠃⠀⠀⠀ ⠀⠀⠀⣠⣾⣿⣿⡟⠁⠀⠀⠀⠀ ⠀⢠⣾⣿⠟⠁⠘⡇⠀⠀⠀⠀⠀ ⢀⣿⡟⠁⠀⣠⣶⣿⣶⣶⣤⡀⠀ ⢸⣿⠀⠀⣼⣿⠟⢻⡛⠻⣿⣷⠀ ⠘⣿⡀⠀⢹⣇⠀⠘⡇⠀⠘⣿⠇ ⠀⠙⣷⡄⠀⠙⠂⠀⣷⠀⣸⡟⠀ ⠀⠀⠈⠙⠷⢦⣤⣤⣼⡞⠋⠀⠀ ⠀⠀⠀⠀⢀⣀⡀⠀⠸⡇⠀⠀⠀ ⠀⠀⠀⠀⣿⣿⣿⠀⢠⡇⠀⠀⠀ ⠀⠀⠀⠀⠈⠛⠷⠖⠋⠀⠀⠀⠀

Basic Tutorial!

https://strudel.cc/workshop/first-sounds/ i had a lot more fun with this than i expected

all functions covered: https://strudel.cc/workshop/recap/

drums + sequencing

  • bd = bass drum
    • base
  • sd = snare drum
  • rim = rimshot
    • brief
  • hh = hihat
    • soft
  • oh = open hihat
    • rings
  • lt = low tom
    • deep low
  • mt = middle tom
  • ht = high tom
  • rd = ride cymbal
    • light cymbal
  • cr = crash cymbal
  • .bank("") to specify drum machine

drum examples:

  • RolandTR909
    • famous for house and techno beats
  • AkaiLinn
    • 80s
  • RhythmAce
    • analog sound
  • RolandTR707

Sequences

  • space-separated arrays - longer = faster
    • sound("bd hh sd oh rim")
  • sequence content is squished into a cycle
  • < > plays one sound per cycle
    • change speed with *n
  • can also set tempo setcpm(90/4) - cycles per minute
    • default is 120cycles/4min = 1 cycle per 2 seconds
  • - for pauses
  • [ ] for sub-sequences, which are squished and same as sequences
  • can create pitch with really fast rhythmns like hh*32
  • use commas to play sequences in parallel
    • sound(hh hh hh, bd casio)
  • can select samples granularly or with n function
    • sound("jazz:0 jazz:1 [jazz:4 jazz:2] jazz:3*2")
    • n("0 1 [4 2] 3*2").sound("jazz")

examples

  • Rock:
setcpm(100/4)
sound("[bd sd]*2, hh*8").bank("RolandTR505")
  • Classic House
sound("bd*4, [- cp]*2, [- hh]*4").bank("RolandTR909")
- `cp` = clap
setcpm(90/4)
sound(`
[-  -  oh - ] [-  -  -  - ] [-  -  -  - ] [-  -  -  - ],
[hh hh -  - ] [hh -  hh - ] [hh -  hh - ] [hh -  hh - ],
[-  -  -  - ] [cp -  -  - ] [-  -  -  - ] [cp -  -  - ],
[bd -  -  - ] [-  -  -  bd] [-  -  bd - ] [-  -  -  bd]
`)

notes

note("48 52 55 59").sound("piano")
note("c e g b").sound("piano")
note("c# d# fb g# a#").sound("piano") // mysterious
note("c2 e3 g4 b5").sound("piano") // octaves

note("36 43, 52 59 62 64").sound("sawtooth") // i like how this sounds

  • numbers for pitch! use decimals for microtonal pitches
  • letters for pitch! add b or # for sharps/flats
  • specify octaves with numbers (1-8)
    • lower octaves more ominous

note sounds

  • piano
  • sawtooth (good for game)
  • square (makes me think of distortion and fnaf animatronics)
  • triangle (muted electronic sounding)
  • can also pitch drums
  • gm_electric_guitar_muted
  • gm_voice_oohs (veeery creepy game vibes)
  • gm_blown_bottle

switch between sounds (by beat/cycle count)

note("48 67 63 [62, 58]")
.sound("piano gm_electric_guitar_muted")

stack sounds

note("48 67 63 [62, 58]")
.sound("piano, gm_electric_guitar_muted")

// use $: to stack multiple lines
  • multiply / divide sequences to change speed
  • angle brakets useful for longer melodies

play one sequence per cycle

  • for ex., repetitive bassline
note("<[36 48]*4 [34 46]*4 [41 53]*4 [39 51]*4>")
.sound("gm_acoustic_bass")

can alternate between things

note("60 <63 62 65 63>")
.sound("gm_xylophone")

// good for beats
sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
.bank("RolandTR909")

can use scales and relative pitch

setcpm(60)
n("0 2 4 <[6,8] [7,9]>")
.scale("D:dorian").sound("piano")

can automate scales with a pattern

setcpm(60)
n("<0 -3>, 2 4 <[6,8] [7,9]>")
.scale("<C:major D:mixolydian>/4")
.sound("piano")

repeat and elongate notes - @unit

  • note("c@3 eb").sound("gm_acoustic_bass")

example: shuffle groove / triplet swing

setcpm(60)
n("<[4@2 4] [5@2 5] [6@2 6] [5@2 5]>*2")
.scale("<C2:mixolydian F2:mixolydian>/4")
.sound("gm_acoustic_bass")
  • * affects speed within the unit/count, ! affects speed within the cycle??
setcpm(60)
note("c!4 [eb,<g a bb a>]").sound("piano")

effects

note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("sawtooth").lpf(800)

// can pattern the filter, which does not affect rhythmn
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("sawtooth").lpf("200 1000 200 1000")

  • .lpf() = low-pass filter

  • .vowel() - a e i o

  • .gain() - gain

  • attack

  • decay

  • sustain

  • release

  • short notation

    • adsr(".1:.1:.5:.2")
  • delay

    • .delay(".8:.06:.8")
    • a: delay volume
    • b: delay time
    • c: feedback (smaller num = quicker fade)
  • reverb

    • .room(2)
  • pan

    • .pan(0 0.3 .6 1)
  • speed (of pitch?)

    • sound("bd rim [~ bd] rim").speed("<1 2 -1 -2>").room(.2)

modulation w waves

  • sound(hh*16).gain(sine)
    • sine
    • saw (like crescendo or decrescendo)
    • square
    • tri
    • rand
    • perlin
  • can change values that waves oscillate between
sound("hh*16").lpf(saw.range(500, 2000))

// can change modulation speed with .slow or .fast, which replace * and /
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("sawtooth")
.lpf(sine.range(100, 2000).slow(4))

pattern effects

…more complicated stuff

  • multiple tempos
  • reverse patterns, .jux splits left/right
  • ply
  • add numbers to notes to change pitch within patterns
setcpm(60)
note("c2 [eb3,g3] ".add("<0 <1 -1>>"))
.color("<cyan <magenta yellow>>").adsr("[.1 0]:.2:[1 0]")
.sound("gm_acoustic_bass").room(.5)
  • .off - offset the given pattern
n("0 [4 <3 2>] <2 3> [~ 1]"
.off(1/16, x=>x.add(4))
//.off(1/8, x=>x.add(7))
).scale("<C5:minor Db5:mixolydian>/2")
.s("triangle").room(.5).dec(.1)

Synths

todo https://strudel.cc/learn/synths/


technical

https://loophole-letters.vercel.app/strudel