Skip to content

Instantly share code, notes, and snippets.

@brettbuddin
Last active September 10, 2018 15:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brettbuddin/2fea8b4a2fa6164c82e5052ad01bf466 to your computer and use it in GitHub Desktop.
Save brettbuddin/2fea8b4a2fa6164c82e5052ad01bf466 to your computer and use it in GitHub Desktop.
GopherCon 2018 Lightning Talk Patches for Shaden

This is a collection of patches for the Shaden synthesizer that I played during my lightning talk at GopherCon 2018.

(define clock (unit/clock))
(define clock/div/2 (unit/clock-div (table :div 2)))
(define clock/div/4 (unit/clock-div (table :div 4)))
(define clock/div/8 (unit/clock-div (table :div 8)))
(define clock/div/16 (unit/clock-div (table :div 16)))
(define clock/mult/2 (unit/clock-mult (table :mult 2)))
(-> clock
(table :tempo (hz 3)
:shuffle 0))
(each
(fn (_ u) (-> u :in (<- clock)))
(list clock/div/2
clock/div/4
clock/div/8
clock/div/16
clock/mult/2))
(define lfo (unit/low-gen))
(-> lfo (table :freq (hz 1) :amp 0.2 :offset 0.5))
; VOICE 1
(define voice1/sequence (unit/stages (table :size 10)))
(define voice1/gen (unit/gen))
(define voice1/gen-mix (unit/mix (table :size 3)))
(define voice1/slope (unit/slope))
(define voice1/gate (unit/gate))
(define voice1/filter (unit/filter))
(-> voice1/sequence
(table :clock (<- clock) :glide-time (ms 100))
(list
; phrase 1
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb4") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb4") :mode mode/all :pulses 2 :glide mode/on)
; phrase 2
(table :freq (hz "Eb2") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb2") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb2") :mode mode/all :pulses 1 :glide mode/off)))
(-> voice1/gen
(table
:freq (<- voice1/sequence :freq)
:pulse-width (<- lfo :sine)))
(-> voice1/gen-mix
(list
(table :in (<- voice1/gen :saw))
(table :in (<- voice1/gen :sub-pulse))))
(-> voice1/slope
(table :trigger (<- voice1/sequence :gate)
:rise (ms 10)
:ratio 0.0001
:fall (ms 2000)))
(-> voice1/gate
(table :in (<- voice1/gen-mix)
:control (<- voice1/slope)))
(-> voice1/filter
(table :in (<- voice1/gate)
:res 1
:cutoff (hz 1000)))
; VOICE 2
(define voice2/euclid (unit/euclid))
(define voice2/filter (unit/filter))
(define voice2/gate (unit/gate))
(define voice2/gen (unit/gen))
(define voice2/gen-mix (unit/mix (table :size 4)))
(define voice2/gen2 (unit/gen))
(define voice2/overload (unit/overload))
(define voice2/sequence (unit/stages (table :size 5)))
(define voice2/slope (unit/slope))
(define voice2/transpose (unit/transpose))
(-> voice2/euclid
(table :span 27
:fill 2
:clock (<- clock)))
(-> voice2/sequence
(table :clock (<- voice2/euclid))
(list
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb2") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Bb2") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)
(table :freq (hz "Eb3") :mode mode/all :pulses 1 :glide mode/off)))
(-> voice2/transpose
(table :in (<- voice2/sequence :freq)
:semitones 7))
(-> voice2/gen
(table :freq (<- voice2/sequence :freq)))
(-> voice2/gen2
(table :freq (<- voice2/transpose)))
(-> voice2/gen-mix
(list
(table :in (<- voice2/gen2 :saw) :level (db 12))
(table :in (<- voice2/gen :pulse))
(table :in (<- voice2/gen :cluster) :level (db 12))
(table :in (<- voice2/gen :sub-pulse))))
(-> voice2/filter
(table :in (<- voice2/gen-mix)
:cutoff (hz "C3")))
(-> voice2/overload
(table :in (<- voice2/filter :lp)
:gain 1000))
(-> voice2/slope
(table :trigger (<- voice2/sequence :gate)
:rise (ms 500)
:ratio 0.001
:fall (ms 20000)))
(-> voice2/gate
(table :in (<- voice2/overload)
:cutoff-high (hz 2000)
:cutoff-low (hz 1000)
:control (<- voice2/slope)))
; KICK
(define kick/gate (unit/gate))
(define kick/gen (unit/gen))
(define kick/slope (unit/slope))
(define kick/stretch/mult (unit/mult))
(define kick/stretch/slope (unit/slope))
(-> kick/stretch/slope
(table :ratio 0.001
:rise (ms 1)
:fall (ms 50)
:trigger (<- clock/div/2)))
(-> kick/stretch/mult
(table :x (<- kick/stretch/slope)
:y (hz 400)))
(-> kick/gen
(table :freq (hz "Eb1")
:freq-mod (<- kick/stretch/mult)))
(-> kick/slope
(table :trigger (<- clock/div/2)
:rise (ms 10)
:ratio 0.001
:fall (ms 1000)))
(-> kick/gate
(table :in (<- kick/gen :sine)
:control (<- kick/slope)))
; ANOTHER
(define another/euclid (unit/euclid))
(define another/filter (unit/filter))
(define another/gate (unit/gate))
(define another/gen (unit/gen))
(define another/slope (unit/slope))
(-> another/euclid
(table :span 8
:fill 5
:clock (<- clock)))
(-> another/gen :freq (hz "Eb4"))
(-> another/filter
(table :in (<- another/gen :saw)
:cutoff (hz "Bb4")
:res 10))
(-> another/slope
(table :trigger (<- another/euclid)
:rise (ms 10)
:ratio 0.001
:fall (ms 1000)))
(-> another/gate
(table :in (<- another/filter :bp)
:control (<- another/slope)))
; CLICK
(define click/gate (unit/gate))
(define click/gen (unit/gen))
(define click/slope (unit/slope))
(-> click/gen :freq (hz "Eb6"))
(-> click/slope
(table :trigger (<- clock/mult/2)
:rise (ms 1)
:ratio 0.001
:fall (ms 5)))
(-> click/gate
(table :in (<- click/gen :triangle)
:control (<- click/slope)))
; POST-PROCESSING
(define compressed-mix (unit/panmix (table :size 6)))
(define final-mix (unit/panmix))
(define gainA (unit/mult))
(define gainB (unit/mult))
(define left/compress (unit/dynamics))
(define reverb (unit/reverb))
(define right/compress (unit/dynamics))
(-> reverb (table :a (<- voice1/filter :lp)
:b (<- voice1/filter :lp)
:decay 0.99
:mix 0.5
:size 0.3
:cutoff-pre (hz 800)
:cutoff-post (hz 1300)))
(let
((compression
(table :above 0.01
:threshold (db -12)
:relax (ms 200)))
(left (<- reverb :a))
(right (<- reverb :b)))
(-> left/compress
(table-merge compression
(table :in left
:control (<- kick/gate))))
(-> right/compress
(table-merge compression
(table :in right
:control (<- kick/gate)))))
(-> compressed-mix
(list
(table :in (<- click/gate) :level (db -6) :pan 0)
(table :in (<- another/gate) :level (db -12) :pan 0)
(table :in (<- voice2/gate) :level (db -12) :pan 0)
(table :in (<- left/compress) :pan -1 :level (db 12))
(table :in (<- right/compress) :pan 1 :level (db 12))))
(-> final-mix
(table :master (db -10))
(list
(table :in (<- kick/gate) :level 1)
(table :in (<- compressed-mix :a) :pan -1)
(table :in (<- compressed-mix :b) :pan 1)))
(define gain-a (unit/mult))
(define gain-b (unit/mult))
(-> gain-a (table :x (<- final-mix :a) :y (db -6)))
(-> gain-b (table :x (<- final-mix :b) :y (db -6)))
(emit (<- gain-a) (<- gain-b))
(load "percussion.lisp")
; Timing and patterns
(define clock (unit/clock))
(define clock-div-2 (unit/clock-div))
(define euclid-1 (unit/euclid))
(define euclid-2 (unit/euclid))
(define euclid-3 (unit/euclid))
(define euclid-4 (unit/euclid))
(define snare-xor (unit/xor))
(define hat-xor (unit/xor))
(define hat-accents (unit/switch))
(define hat-rise (unit/mult))
(define hat-fall (unit/mult))
(-> clock (table :tempo (hz 11) :shuffle 0.05))
(-> clock-div-2 (table :in (<- clock) :div 2))
(-> euclid-1 (table :span 8 :fill 1 :clock (<- clock-div-2)))
(-> euclid-2 (table :span 10 :fill 1 :clock (<- clock-div-2)))
(-> euclid-3 (table :span 10 :fill 8 :clock (<- clock-div-2)))
(-> euclid-4 (table :span 4 :fill 2 :clock (<- euclid-3)))
(-> snare-xor (table :x (<- euclid-1) :y (<- euclid-2)))
(-> hat-xor (table :x (<- euclid-1) :y (<- euclid-3)))
(-> hat-accents
(table :trigger (<- euclid-4))
(list 1 2 4 1))
(-> hat-rise (table :x (ms 3) :y (<- hat-accents)))
(-> hat-fall (table :x (ms 100) :y (<- hat-accents)))
; Voices
(define snare (make-snare))
(define kick (make-kick))
(define hat (make-hat))
(define hat-2 (make-hat))
((snare :patcher)
(table :low-freq (hz "C#3")
:high-freq (hz "C4")
:rise (ms 1)
:fall (ms 200)
:cutoff-high (hz 12000)
:cutoff-low (hz 8000)
:trigger (<- snare-xor)))
((kick :patcher)
(table :freq (hz "C1")
:tone-fall (ms 800)
:trigger (<- euclid-2)))
((hat :patcher)
(table :rise (<- hat-rise)
:fall (<- hat-fall)
:cutoff-high (hz 5000)
:cutoff-low (hz 4000)
:trigger (<- hat-xor)))
((hat-2 :patcher)
(table :rise (ms 10)
:fall (ms 150)
:cutoff-high (hz 900)
:cutoff-low (hz 800)
:trigger (<- clock)))
; Mixing and post-processing
(define mix (unit/mix))
(-> mix
(table :mode mode/average)
(list
(table :in (kick :output) :level (db -6))
(table :in (snare :output))
(table :in (hat :output) :level (db -24))
(table :in (hat-2 :output) :level (db -36))))
(define overload (unit/overload))
(define filter-bank (unit/filter-bank))
(-> overload (table :in (<- mix) :gain 3))
(-> filter-bank
(table :in (<- overload))
(list (table :cutoff (hz 300))
(table :cutoff (hz 1000) :res 10)
(table :cutoff (hz 9000))))
(define gain (unit/mult))
(-> gain (table :x (<- filter-bank) :y (db -6)))
(emit (<- gain))
; Harmonic ratios of the delay line to create the metalic overtones.
(define delay-harmonic-ratios (list 0.0625 0.125 0.25 0.5 0.75))
(define num-delay-harmonics (len delay-harmonic-ratios))
; Independant sources for different random numbers
(define source (unit/gen))
(define source2 (unit/gen))
(define source3 (unit/gen))
(define source4 (unit/gen))
(define source5 (unit/gen))
; Set range of this source to drive the selection of harmonic ratios
(-> source5
(table :offset num-delay-harmonics
:amp num-delay-harmonics))
; Latches for freezing outputs of the unit/gens
(define latch (unit/latch))
(define latch2 (unit/latch))
(define latch3 (unit/latch))
(define latch4 (unit/latch))
(define latch5 (unit/latch))
; Predeclare slope. We'll use its "eoc" output to feedback a trigger signal at the end of each note to cause new random
; values to be locked into the latches and be outputted. Round and round we go.
(define slope (unit/slope))
(-> latch (table :in (<- source :noise) :trigger (<- slope :eoc)))
(-> latch2 (table :in (<- source2 :noise) :trigger (<- slope :eoc)))
(-> latch3 (table :in (<- source3 :noise) :trigger (<- slope :eoc)))
(-> latch4 (table :in (<- source4 :noise) :trigger (<- slope :eoc)))
(-> latch5 (table :in (<- source5 :noise) :trigger (<- slope :eoc)))
; Value ranges for parameters
(define rise (unit/mult))
(define fall (unit/mult))
(define rise-max (unit/max))
(define fall-max (unit/max))
(define cutoff (unit/mult))
(define delay-time (unit/mult))
(define left-compress (unit/dynamics))
(define right-compress (unit/dynamics))
(-> rise (table :x (ms 1000) :y (<- latch)))
(-> rise-max (table :x (<- rise) :y (ms 10)))
(-> fall (table :x (ms 6000) :y (<- latch2)))
(-> fall-max (table :x (<- fall) :y (ms 1000)))
(-> cutoff (table :x (hz 4000) :y (<- latch3)))
(define quantize (unit/quantize))
(define gate (unit/gate))
(define mix (unit/mix (table :size 2)))
(define delay-harmonics (unit/mux (table :size 5)))
(define delay-samples (unit/div))
(define intervals
(list (theory/interval :perfect 1)
(theory/interval :minor 3)
(theory/interval :perfect 5)
(theory/interval :minor 7)
(theory/interval :minor 9)))
(-> quantize
(table :in (<- latch4)
:tonic (hz "C2")
:intervals intervals))
(-> source (table :freq (<- quantize)))
(-> delay-harmonics (table :select (<- latch5)) delay-harmonic-ratios)
(-> delay-samples (table :x 1.0 :y (<- quantize)))
(-> delay-time (table :x (<- delay-samples) :y (<- delay-harmonics)))
; Slope will cycle and keep emitting "eoc" triggers which are triggering the
; latches. This is why the patch keeps going on forever.
(-> slope
(table :rise (<- rise-max)
:fall (<- fall-max)
:cycle mode/on
:trigger 1))
(-> mix
(list (table :in (<- source :saw))
(table :in (<- source :sub-pulse) :level (db -3))))
(-> gate
(table :in (<- mix)
:control (<- slope)
:res 5
:cutoff-high (<- cutoff)))
; Generate metalic harmonics using Karplus-Strong.
(define delay (unit/delay))
(define delay-filter (unit/filter))
(-> delay
(table :in (<- gate)
:fb-gain 0.8
:fb-return (<- delay-filter :lp)
:time (<- delay-time)))
(-> delay-filter
(table :in (<- delay :fb-send)
:cutoff (hz 2000)))
; Reverb and compression
(define reverb (unit/reverb))
(-> reverb
(table :a (<- delay)
:b (<- delay)
:mix 0.9
:decay 0.8
:size 0.8
:shift-semitones 0
:cutoff-pre (hz 500)
:cutoff-post (hz 400)))
(let
((compress (table :above 0.1
:threshold (db -6)
:relax (ms 300)))
(left (<- reverb :a))
(right (<- reverb :b)))
(-> left-compress
compress
(table :in left
:control left))
(-> right-compress
compress
(table :in right
:control right)))
(emit (<- left-compress) (<- right-compress))
; Snare drum
; Inputs:
; :low-freq - Low frequency (fundamental) of the drum
; :high-freq - High frequency of the drum. Creates dissonance with low-freq
; :fall - Gate decay time
; :cutoff-high - Upper-bound cutoff frequency of the noise gate
; :cutoff-low - Lower-bound cutoff frequency of the noise gate
; :trigger - Trigger
(define (make-snare)
(let ((gen-low (unit/gen))
(gen-high (unit/gen))
(mix (unit/mix))
(env (unit/slope))
(gate (unit/gate)))
(define (patcher inputs)
(-> gen-low
(table :freq (inputs :low-freq (hz "F#3"))
:sync (inputs :trigger)))
(-> gen-high
(table :freq (inputs :high-freq (hz "F4"))
:sync (inputs :trigger)))
(-> mix
(table :mode mode/average)
(list (table :in (<- gen-low :triangle))
(table :in (<- gen-low :noise) :level (db -6))
(table :in (<- gen-high :triangle))))
(-> env
(table :trigger (inputs :trigger)
:ratio 0.0001
:rise (ms 1)
:fall (inputs :fall (ms 400))))
(-> gate
(table :in (<- mix)
:cutoff-high (inputs :cutoff-high)
:cutoff-low (inputs :cutoff-low)
:control (<- env))))
(table :patcher patcher :output (<- gate))))
; Kick drum
; Inputs:
; :freq - Fundamental frequency of the drum
; :tone-fall - Gate decay time
; :trigger - Trigger
(define (make-kick)
(let ((gen (unit/gen))
(mix (unit/mix))
(stretch-env (unit/slope))
(stretch-amount (unit/adjust))
(tone-env (unit/slope))
(noise-env (unit/slope))
(tone-gate (unit/gate))
(noise-gate (unit/gate))
(overload (unit/overload)))
(define (patcher inputs)
(-> stretch-env
(table :trigger (inputs :trigger)
:rise (inputs :stretch-rise (ms 1))
:fall (inputs :stretch-fall (ms 30))))
(-> stretch-amount
(table :in (<- stretch-env)
:mult (inputs :stretch-amount (hz 300))))
(-> gen
(table :freq (inputs :freq (hz "C1"))
:freq-mod (<- stretch-amount)
:sync (inputs :trigger)))
(-> tone-env
(table :trigger (inputs :trigger)
:ratio 0.001
:rise (inputs :tone-rise (ms 1))
:fall (inputs :tone-fall (ms 500))))
(-> noise-env
(table :trigger (inputs :trigger)
:ratio 0.0001
:rise (inputs :noise-rise (ms 1))
:fall (inputs :noise-fall (ms 20))))
(-> tone-gate
(table :in (<- gen :sine)
:cutoff-high (inputs :tone-cutoff-high (hz 500))
:cutoff-low (inputs :tone-cutoff-low)
:control (<- tone-env)))
(-> noise-gate
(table :in (<- gen :noise)
:cutoff-high (inputs :noise-cutoff-high (hz 1000))
:cutoff-low (inputs :noise-cutoff-low)
:control (<- noise-env)))
(-> mix
(table :mode mode/average)
(list (table :in (<- tone-gate))
(table :in (<- noise-gate))))
(-> overload (table :in (<- mix) :gain 5)))
(table :patcher patcher :output (<- overload))))
; High-hat or cymbal
; Input:
; :rise - Gate attack time
; :fall - Gate decay time
; :cutoff-high - Upper-bound cutoff frequency of the noise gate
; :cutoff-low - Lower-bound cutoff frequency of the noise gate
; :trigger - Trigger
(define (make-hat)
(let ((gen (unit/gen))
(mix (unit/mix))
(env (unit/slope))
(gate (unit/gate))
(overload (unit/overload)))
(define (patcher inputs)
(-> env
(table :trigger (inputs :trigger)
:ratio 0.001
:rise (inputs :rise (ms 1))
:fall (inputs :fall (ms 100))))
(-> gate
(table :in (<- gen :noise)
:cutoff-high (inputs :cutoff-high (hz 5000))
:cutoff-low (inputs :cutoff-low (hz 4000))
:control (<- env)))
(-> overload (table :in (<- gate) :gain 10)))
(table :patcher patcher :output (<- overload))))
; Rythm
(define clock (unit/clock))
(define euclid (unit/euclid))
(-> clock (table :tempo (hz 0.8)))
(-> euclid
(table :span 7
:fill 3
:clock (<- clock)))
; Pitches
(define switch-1 (unit/switch (table :size 3)))
(define switch-2 (unit/switch (table :size 3)))
(define switch-3 (unit/switch (table :size 3)))
(define gen (unit/gen))
(define gen-2 (unit/gen))
(define gen-3 (unit/gen))
(define gen-mix (unit/mix))
; Pre-declare our note slope so it's eoc can be used to trigger movement of the
; higher pitch.
(define note-slope (unit/slope))
(-> switch-1 (theory/chord (hz "C3") :major) (table :trigger (<- euclid)))
(-> switch-2 (theory/chord (hz "F2") :major) (table :trigger (<- euclid)))
(-> switch-3 (theory/chord (hz "A3") :minor) (table :trigger (<- note-slope :eoc)))
(-> gen (table :freq (<- switch-1)))
(-> gen-2 (table :freq (<- switch-2)))
(-> gen-3 (table :freq (<- switch-3)))
(-> gen-mix
(list (table :in (<- gen :saw))
(table :in (<- gen-2 :pulse))
(table :in (<- gen-3 :saw))))
; Voice
(define gate (unit/gate))
(define filter (unit/filter))
(define resist-slope (unit/slope))
(define note-slope-max (unit/mult))
(define note-slope-min (unit/max))
(define reverb (unit/reverb))
(-> resist-slope
(table :rise (ms 1)
:fall (ms 5000)
:ratio 0.1
:trigger (<- euclid)))
(-> note-slope-max
(table :x (ms 800)
:y (<- resist-slope :mirror)))
(-> note-slope-min
(table :x (ms 60)
:y (<- note-slope-max)))
(-> note-slope
(table :trigger (<- euclid)
:cycle (<- resist-slope)
:rise (ms 1)
:fall (<- note-slope-min)))
(-> gate
(table :in (<- gen-mix)
:cutoff-high (hz 5000)
:cutoff-low (hz 3000)
:control (<- note-slope)))
(-> filter
(table :in (<- gate)
:cutoff (hz 5000)))
(-> reverb
(table :a (<- filter :lp)
:b (<- filter :lp)
:mix 0.8
:size 0.5
:decay 0.4
:cutoff-pre (hz 1000)
:cutoff-post (hz 100)))
(define gain-a (unit/mult))
(define gain-b (unit/mult))
(-> gain-a
(table :x (<- reverb :a)
:y (db -6)))
(-> gain-b
(table :x (<- reverb :b)
:y (db -6)))
(emit (<- gain-a) (<- gain-b))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment