In this post I’ll introduce my live coding music environment built on top on Overtone and Leipzig.

TL;DR

This is an example session we’ll be discussing here:

I’m using lots of samples from Major Lazer & DJ Snake - Lean On (feat. MØ) and a beat from Prodigy - Smack My B**ch Up.

Main theme

First things first. To recreate the Lean On main theme we’ll use Leipzig as in previous post. The notes are here:

And can be expressed as:

( def leanon-chords [[ -9 -2 0 2 4 ] [ -8 -1 -3 1 3 ] [ -7 0 2 4 ] [ -5 -1 2 4 5 6 ] [ -5 -1 2 3 4 ]]) ( def leanon ( let [[ ch1 ch2 ch3 ch4 ch5 ] leanon-chords ] ( ->> ( phrase ( concat ( take 9 ( cycle [ 1 /2 1 /4 ])) [ 1 /2 ] ( take 9 ( cycle [ 1 /2 1 /4 ])) [ 1 /2 ]) [ ch1 nil ch1 nil ch1 nil ch2 nil ch2 nil ch3 nil ch3 nil ch3 nil ch4 nil ch4 ch5 ]) ( wherever :pitch, :pitch ( comp scale/low scale/G scale/minor )) ( all :part :plucky ) ( all :amp 1 ))))

And I also created a simple “plucky” sound based on square wave with some reverb:

( definst plucky [ freq 440 dur 1 amp 1 cutoff 1500 fil-dur 0.1 ] ( let [ env ( env-gen ( asr 0 1 1 ) ( line :kr 1.0 0.0 dur ) :action FREE ) level ( + ( * 0.85 freq ) ( env-gen ( perc 0 fil-dur ) :level-scale cutoff ))] ( -> ( pulse freq ) ( lpf level ) ( free-verb :room 1 :wet 0.45 ) ( * env amp ))))

And to wire it up for Leipzig we need to implement live/play for :plucky

( def controls ( atom { :plucky { :amp 1.0 :cutoff 900 }})) ( defmethod live/play-note :plucky [{ hertz :pitch seconds :duration amp :amp }] ( when hertz ( let [ params { :freq hertz :dur seconds :volume ( or amp 1 )}] ( apply i/plucky ( to-args ( merge ( :plucky @ controls ) params ))))))

This controls atom lets us modify live the instrument amp and cutoff frequency.

So it sounds like this:

Sampler

What I’m doing a lot in this video is using a homemade sampler. I stolen some ideas from Sam Aaron’s Sonic Pi sample packs concept ;)

Basically, I have a directory when I put all the samples and use special meaning of samples file name to detect some properties of the sample. So for example, I have 120_8_smack_beat.wav which tells my sampler that this file is in 120 BPM, is 8 beats long and is named :smack-beat . Because Lean On is ~98 BPM I can compute a correct ratio to match Smack My B**ch Up beat with Lean On melody.

Original beat (120 BPM):

Scaled to 100 BPM with melody:

I can also play only first few beats of some sample by using it like this [0 :lean-chorus 2] , which means that on time 0 I only want first 2 beats of :lean-chorus sample. The beat lengths are of course computed from current BPM.

Song state

I found it really easy to manipulate current state of the song represented as a map of independent tracks:

{ :beat [{ :time 0 :drum :kick :amp 1 } ... ] :plucky [{ :pitch 39 , :time 0 , :duration 1 /2, :part :plucky, :amp 1 } ... ]}

This allows me to modify the current state by using this update-track function. It just takes a key with track name and a new value of this track. So I can have my plucky instrument playing while I’m modifying the beat and so on:

( update-track :beat ( times 2 l/lean-beat ))

It’s also very easy to remove some of the notes as I’m doing just before the chorus to remove last frame from beat and theme:

( def last-frame ( fn [ n ] ( >= ( :time n ) 12 ))) ( update-track :beat ( ->> ( times 2 l/lean-beat ) ( remove last-frame )) :plucky ( ->> ( times 2 l/leanon ) ( remove last-frame )) :sampler ( t/sampler [[ 0 :lean-verse-2 ] [ 0 :smack-beat 8 1.5 ] [ 8 :smack-beat 4 1.5 ]]))

In Leipzig I can just use live/jam to loop current state of the song. When I modify something it’ll we activated on next loop (same as :live-loop in Sonic Pi).

I you want to play around with this stuff, check out my disclojure repo on GitHub.