Skip to content

Instantly share code, notes, and snippets.

@tomasos
Created March 11, 2015 11:16
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomasos/17e2acd21a17d600ffc9 to your computer and use it in GitHub Desktop.
Save tomasos/17e2acd21a17d600ffc9 to your computer and use it in GitHub Desktop.
Overtone presentation
;; Tomas Osland
;; tomas.osland@knowit.no
;; @tomasosland
;; Welcome to this presentation about functional music. In this lightning talk we
;; will construct a drum machine and make som beats, play the piano, and experiment with synthesizers.
;; Start overtone.cid
(ns overtone.examples.timing.one-bar-sequencer
(:use [overtone.live]
[overtone.inst drum]
[overtone.inst.sampled-piano]))
;; Overtone is a library for creating synthesizers and composing music. The hard way.
;; The library is written in Clojure and uses the SuperCollider synthesis engine,
;; wich is written in Java. You can also use midi i/o for devices, such as the monome.
;; https://github.com/overtone/overtone/
;; http://overtone.github.io/
;; This defines the instruments.
(def instruments {:kick quick-kick
:snare noise-snare
:hit soft-hat})
(quick-kick)
(noise-snare)
(soft-hat)
;; And this is our drum machine sequence.
(def sequence {:kick [1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
:snare [0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0]
:hit [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0]})
;; Overtone provides a metronome, which is basically a ticker incrementing a count.
(def metro (metronome 130))
(metro)
;; And now to some logic. play-sequence is a function with a beat count and a instrument
;; for parameters. The function will go through the next 4 beats and play the given
;; instrument at a future time.
(defn play-sequence [beat instr]
(let [time (mod beat 4)
seq (vec (take 4 (drop (* 4 time) (sequence instr))))]
(if (= 1 (seq 0)) (at (metro (+ 0.00 beat)) ((instruments instr))))
(if (= 1 (seq 1)) (at (metro (+ 0.25 beat)) ((instruments instr))))
(if (= 1 (seq 2)) (at (metro (+ 0.50 beat)) ((instruments instr))))
(if (= 1 (seq 3)) (at (metro (+ 0.75 beat)) ((instruments instr))))))
(vec (take 4 (drop (* 4 0) (sequence :hit))))
(at (metro (+ 0.50 0)) ((instruments :kick)))
;; The player will iterate over the instruments and play the instruments sequence.
;; This function is recursive and will loop for ever.
(defn player [beat]
(doseq [instr (keys instruments)] (play-sequence beat instr))
(apply-at (metro (inc beat)) #'player (inc beat) []))
(player (metro))
;; Lets change the beat
(def sequence {:kick [1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0]
:snare [0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0]
:hit [0 0 1 0 0 0 1 0 1 0 1 0 0 1 1 1]})
;; And the tempo
(metro :bpm 90)
(metro :bpm 140)
(stop)
;; Overtone has two built in piano modules where one of them is based on piano
;; samples from Freesound.org.
(sampled-piano)
(sampled-piano 40 (+ 0.3 (rand 0.5)))
(for [i (range 110)] (at (+ (+ (now) i) (* i (rand 2) 20)) (sampled-piano i (+ (rand 0.6) 0.3))))
;; A chord is composed of three or more tones played simultaneous.
;; Overtone has already defined the chords for us,
;; but we must define how they are played.
(defn play-chord
[chord]
(doseq [note chord] (sampled-piano note (+ (rand 0.5) 0.3))))
(play-chord (chord :D3 :m7))
;; When we have defined how to play chords, we can use this to play
;; chord progressions.
(defn play-progression
[beat chords]
(let [next-beat (+ beat 3)]
(at (metro beat) (play-chord (first chords)))
(apply-by (metro next-beat) #'play-progression [next-beat (rest chords)])))
(play-progression (metro) [(chord :D3 :m7) (chord :A3 :m7)])
(play-progression (metro)
(cycle [(chord :C3 :m9) (chord :F3 :7) (chord :Bb3 :maj9) (chord :Eb3 :maj9) (chord :A3 :m7-5) (chord :D3 :7-9) (chord :G3 :minor7)]))
(stop)
;; To play a melody we will send in a list of notes wich we will cycle
;; through recursively and play at each beat of the metronome.
(defn play-melody
[beat notes]
(let [note (first notes)]
(when note
(at (metro beat) (sampled-piano note (+ (rand 0.6) 0.3))))
(let [next-time (+ beat 1)]
(apply-by (metro next-time) play-melody [next-time (rest notes)]))))
;; Overtone lets us specify which note in a scale to play. This gives us more
;; flexibility in changing scales and tonality.
(def deg [:ii :v :iii :vi :v])
(metro :bpm 180)
(play-melody (metro) (degrees->pitches deg :mixolydian :C4))
(play-progression (metro)
(cycle [(chord :C3 :m9) (chord :F3 :7) (chord :Bb3 :maj9) (chord :Eb3 :maj9) (chord :A3 :m7-5) (chord :D3 :7-9) (chord :G3 :minor7)]))
(play-melody (metro) (cycle (degrees->pitches deg :mixolydian :F4)))
;; Since Overtone is using the SuperCollider engine, we are able to define
;; our own synthesizers.
;; Lets make some noise.
(defsynth drone
[out-bus 0]
(out out-bus (pan2 (* 1.0 (sin-osc 30) (lf-pulse 30)))))
(drone)
(definst sawdrone []
(* 0.2
(+ (sin-osc 300) (saw 200) (saw 11) (sin-osc 30))))
(sawdrone)
(stop)
;; Check out https://github.com/overtone/overtone for code examples.
;; Check out http://meta-ex.com for some music examples.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment