//
you're reading...
Uncategorized

Encoding Sound using Overtone and Clojure

What’s Overtone?
Overtone is an open source audio environment designed to explore new musical ideas from synthesis and sampling to instrument building, live-coding and collaborative jamming. Overtone uses the powerful SuperCollider (SC) audio engine. SC is an advanced development environment and programming language for sound synthesis. Overtone is a ‘third party’ client for SC that does not provide an interface to SuperCollider’s programming language, instead Overtone communicates directly with the SC audio server and provides a robust Clojure programmable interface facilitating user expressions to manipulate sound.


Running Overtone together with Emacs

On your terminal, type the following:

$ lein new tutorial

This will create you a new project directory structure skeleton within which to place your musical overtone code

Pull in Dependencies

Overtone relies on a number of external dependencies which must be available on your system. Luckily this doesn’t mean lots of manual downloading as lein will handle all this for you. All you need to do is to tell lein that your project depends on Overtone, and lein will figure out the rest. When you created the tutorial project, lein created a file called tutorial/project.clj. This is the file you use to tell lein about the specifics of your project. In this case we only care about telling lein that Overtone is a dependency. This is as simple as adding [overtone “0.9.1”] to the list of dependencies. Therefore, open up tutorial/project.clj and edit it to add the overtone dependency, and should look as follows:

(defproject tutorial “1.0”
:dependencies [ [org.clojure/clojure “1.6.0”] [overtone “0.9.1”] ])

Now, to pull in the dependencies, you just need to run lein deps from within the project directory:

$ cd tutorial
$ lein deps

Now, cd into a directory containing a lein project which references overtone as a dependency.

Fire up nrepl: lein repl

Look for the line nREPL server started on port 55803. Note that the actual port number may be quite different, remember yours.

Fire up Emacs

Connect Emacs to nrepl: M-x nrepl or M-x cider (in newer versions of Emacs Live)

At the Host: prompt, type localhost

When the prompt Port: appears, enter the nREPL port number, from above.

Fire up Overtone and play sounds:

user> (use ‘overtone.live)
user> (demo (sin-osc))

Metronome and Sequencing Sounds in Overtone

[Refs: https://github.com/overtone/overtone/wiki/Metronome-and-sequencing%5D

Here’s an example of how to set up a beat with a simple metronome and timed sounds.

Once you define a metronome in Overtone (one-twenty-bpm in the example below), it will start counting beats.

;Fire up overtone
(use 'overtone.live)

; setup a sound for our metronome to use
(def kick (sample (freesound-path 2086)))

; setup a tempo for our metronome to use
(def one-twenty-bpm (metronome 120))

; this function will play our sound at whatever tempo we've set our metronome to
(defn looper [nome sound]
    (let [beat (nome)]
        (at (nome beat) (sound))
        (apply-at (nome (inc beat)) looper nome sound [])))

; turn on the metronome
(looper one-twenty-bpm kick)

;Playing a Melody

(def subject [[:d4 2] [:a4 2] [:f4 2] [:d4 2] [:c#4 2] [:d4 1] [:e4 1] [:f4 2.5] [:g4 0.5] [:f4 0.5] [:e4 0.5] [:d4 1]])

(defn play-one
  [metronome beat instrument [pitch dur]]
  (let [end (+ beat dur)]
    (if pitch
      (let [id (at (metronome beat) (instrument (note pitch)))]
        (at (metronome end) (ctl id :gate 0))))
    end))

We take the metronome, the target beat, and the instrument as arguments. In the final argument, we destructure the note vector into pitch and duration. Then we calculate the beat when the note needs to stop by adding the duration to the start beat. In order to encode rests with a pitch of nil, we only go into the playing code, if the pitch is not nil. After that we play the note and stop it as shown above. Finally, we return to beat when this note ends, so that we know the timing of the next note. Finally, we can now define the play function that goes through the melody, calls play-one for each note and uses apply-at to schedule a recursive execution of itself at for the next note.

(defn play
  ([metronome inst score]
     (play metronome (metronome) inst score))
  ([metronome beat instrument score]
     (let [cur-note (first score)]
       (when cur-note
         (let [next-beat (play-one metronome beat instrument cur-note)]
           (apply-at (metronome next-beat) play metronome next-beat instrument
             (next score) []))))))

The recursive call has to get the beat, on which it should play its first note, but for a convenient API, we make that argument optional and ask the metronome for the next beat, so that it starts playing at once, when called. We cannot use the next beat from the metronome at each recursive call, as we need to be able to handle fractional beats for eighth or sixteenth notes.We have reached our goal and can play the subject of “Kunst der Fuge”:

(use 'overtone.inst.sampled-piano)

(play (metronome 120) sampled-piano subject)

; play it repeatedly for an infinitely long time.

(def subject-inf (lazy-seq (concat subject subject-inf)))

(play (metronome 120) sampled-piano subject-inf)

;Or we can shuffle it up a bit....
(def mixup (lazy-seq (concat (shuffle subject) mixup ))
(play (metronome 180) sampled-piano mixup)

; but the above does not repeatedly shuffle - so here is solution

(def g (apply concat (repeatedly #(shuffle subject))))
(play (metronome 120) sampled-piano g)

(def t (repeatedly #(subject (rand-int 12))))
(take 10 t)
;=>([:d4 2] [:f4 0.5] [:f4 2.5] [:f4 0.5] [:f4 0.5] [:f4 2] [:f4 2.5] [:e4 1] [:a4 2] [:f4 2.5])
(play (metronome 120) sampled-piano t)

Putting Together Melody, Chords, and Rhythm: A Twelve Bar Blues in Overtone

;;FREDS-BLUES.CLJ;;  by Fred Annexstein fannexstein@gmail.com

;These libs should be loaded
;(use 'overtone.live)
;(use 'overtone.inst.sampled-piano)

;RHYTHM SOUNDS

(definst kick [freq 120 dur 0.3 width 0.5]
  (let [freq-env (* freq (env-gen (perc 0 (* 0.99 dur))))
        env (env-gen (perc 0.01 dur) 1 1 0 1 FREE)
        sqr (* (env-gen (perc 0 0.01)) (pulse (* 2 freq) width))
        src (sin-osc freq-env)
        drum (+ sqr (* env src))]
    (compander drum drum 0.2 1 0.1 0.01 0.01)))

(definst c-hat [amp 0.8 t 0.04]
  (let [env (env-gen (perc 0.001 t) 1 1 0 1 FREE)
        noise (white-noise)
        sqr (* (env-gen (perc 0.01 0.04)) (pulse 880 0.2))
        filt (bpf (+ sqr noise) 9000 0.5)]
    (* amp env filt)))

;PLAY

(defn play-one-note
  [metronome beat instrument [pitch dur]]
  (let [end (+ beat dur)]
    (if pitch
      (let [id (at (metronome beat) (instrument (note pitch)))]
        (at (metronome end) (ctl id :gate 0))))
    end))

(defn play-melody
  ([metronome inst score]
     (play-melody metronome (metronome) inst score))
  ([metronome beat instrument score]
     (let [cur-note (first score)]
       (when cur-note
         (let [next-beat (play-one-note metronome beat instrument cur-note)]
           (apply-at (metronome next-beat) play-melody metronome next-beat instrument
             (next score) []))))))

; MELODY

(def twelvebar
[
[:E4 1/3] [:F4 1/3] [:F#4 1/3]
[:G4 1/3] [:C4 1/3] [:G4 1/3]
[:C4 1/3][:G4 1/3][:C4 1/3]
[:F#4 1/3][:C4 1/3][:F#4 1/3]
[:F4 1/3][:C4 1/3][:E4 1/3]
[:C4 9/3]

[:E4 1/3] [:F4 1/3] [:F#4 1/3]
[:G4 1/3] [:C4 1/3] [:G4 1/3]
[:C4 1/3][:G4 1/3][:C4 1/3]
[:F#4 1/3][:C4 1/3][:F#4 1/3]
[:F4 1/3][:C4 1/3][:E4 1/3]
[:C4 9/3]

[:A4 1/3] [:A#4 1/3] [:B4 1/3]
[:C5 1/3] [:F4 1/3] [:C5 1/3]
[:F4 1/3][:C5 1/3][:F4 1/3]
[:B4 1/3][:F4 1/3][:B4 1/3]
[:A#4 1/3][:F4 1/3][:A4 1/3]
[:F4 9/3]

[:E4 1/3] [:F4 1/3] [:F#4 1/3]
[:G4 1/3] [:C4 1/3] [:G4 1/3]
[:C4 1/3][:G4 1/3][:C4 1/3]
[:F#4 1/3][:C4 1/3][:F#4 1/3]
[:F4 1/3][:C4 1/3][:E4 1/3]
[:C4 9/3]

[:B2 1/3] [:C3 1/3] [:C#3 1/3]
[:D3 1/3] [:G2 1/3] [:D3 1/3]
[:G2 1/3] [:D3 1/3] [:G2 1/3]
[:C#3 1/3][:G2 1/3] [:C#3 1/3]
[:C3 1/3] [:G2 1/3] [:B2 1/3]
[:G3 9/3]

[:E4 1/3] [:F4 1/3] [:F#4 1/3]
[:G4 1/3] [:C4 1/3] [:G4 1/3]
[:C4 1/3][:G4 1/3][:C4 1/3]
[:F#4 1/3][:C4 1/3][:F#4 1/3]
[:F4 1/3][:C4 1/3][:E4 1/3]
[:C4 9/3]
]
)

(defn play-chord [a-chord]
  (doseq [note a-chord] (sampled-piano note)))

(defn chord-progression-beat [m beat-num]
  (at (m (+ 1 beat-num)) (play-chord (chord :C4 :major)))
  (at (m (+ 3 beat-num)) (play-chord (chord :C4 :minor)))
  (at (m (+ 5 beat-num)) (play-chord (chord :C4 :major)))
  (at (m (+ 9 beat-num)) (play-chord (chord :C4 :major)))
  (at (m (+ 11 beat-num)) (play-chord (chord :C4 :minor)))
  (at (m (+ 13 beat-num)) (play-chord (chord :C4 :major)))
  (at (m (+ 17 beat-num)) (play-chord (chord :F3 :major)))
  (at (m (+ 19 beat-num)) (play-chord (chord :F3 :minor)))
  (at (m (+ 21 beat-num)) (play-chord (chord :F3 :major)))
  (at (m (+ 25 beat-num)) (play-chord (chord :C4 :major)))
  (at (m (+ 27 beat-num)) (play-chord (chord :C4 :minor)))
  (at (m (+ 29 beat-num)) (play-chord (chord :C4 :major)))
  (at (m (+ 33 beat-num)) (play-chord (chord :G3 :major)))
  (at (m (+ 35 beat-num)) (play-chord (chord :G3 :minor)))
  (at (m (+ 37 beat-num)) (play-chord (chord :G3 :major)))
  (at (m (+ 41 beat-num)) (play-chord (chord :C4 :major)))
  (at (m (+ 43 beat-num)) (play-chord (chord :C4 :minor)))
  (at (m (+ 45 beat-num)) (play-chord (chord :C4 :major))) 

)
;TEMPO
(def metro (metronome 70))

(defn drum-player [beat]
  (at (metro beat) (c-hat))
  (at (metro (+ 0.33 beat)) (kick))
  (at (metro (+ 0.66 beat)) (c-hat))
  (apply-at (metro (inc beat)) drum-player (inc beat) []))

(drum-player (metro))
(play-melody metro sampled-piano twelvebar)
(chord-progression-beat metro (metro))

A Drum & Bass Pattern in Overtone

(ns overtone.examples.compositions.funk
    "This example creates a simple drum and bass pattern, based off of
    the James Brown classic 'Licking Stick', with Bootsy Collins on bass,
    and John Jab'o Starks on drums"
    (:use [overtone.live]))

; model a plucked string, we'll use this for our bass
(definst string [note 60 amp 1.0 dur 0.5 decay 30 coef 0.3 gate 1]
  (let [freq (midicps note)
        noize (* 0.8 (white-noise))
        dly   (/ 1.0 freq)
        plk   (pluck noize gate dly dly decay coef)
        dist  (distort plk)
        filt  (rlpf dist (* 12 freq) 0.6)
        clp   (clip2 filt 0.8)
        reverb (free-verb clp 0.4 0.8 0.2)]
    (* amp (env-gen (perc 0.0001 dur) :action 0) reverb)))

; define a simple drumkit using freesound samples
(def snare (sample (freesound-path 26903)))
(def kick (sample (freesound-path 2086)))
(def close-hihat (sample (freesound-path 802)))
(def open-hihat (sample (freesound-path 26657)))

(defn subdivide
    "subdivide two time intervals by 4, and return the time interval
    at position. this is a close-hihateap hack to sclose-hihatedule 16th notes without
    defining the whole pattern with the metronome firing every 16th note."
    [a b position]
    (+ a (* position (/ (- b a) 4) )))

(defn drums [nome]
    (let [beat (nome)]
        ; hi-hat pattern
        (at (nome beat) (close-hihat))
        (at (nome (+ 1 beat)) (open-hihat))
        (at (nome (+ 2 beat)) (close-hihat))
        (at (nome (+ 3 beat)) (close-hihat))
        (at (nome (+ 4 beat)) (close-hihat))
        (at (nome (+ 5 beat)) (open-hihat))
        (at (nome (+ 6 beat)) (close-hihat))
        (at (nome (+ 7 beat)) (close-hihat))

        ; snare pattern
        (at (nome (+ 2 beat)) (snare))
        (at (subdivide (nome (+ 2 beat)) (nome (+ 4 beat)) 3) (snare))
        (at (subdivide (nome (+ 4 beat)) (nome (+ 6 beat)) 1) (snare))
        (at (nome (+ 6 beat)) (snare))
        (at (subdivide (nome (+ 6 beat)) (nome (+ 8 beat)) 3) (snare))

        ; kick drum pattern
        (at (nome beat) (kick))
        (at (nome (+ 5 beat)) (kick))
        (at (nome (+ 7 beat)) (kick))
        (apply-by (nome (+ 8 beat)) drums nome [])))

(defn bass [nome]
    (let [beat (nome)]
    (at (nome beat) (string 51))
    (at (subdivide (nome beat) (nome (+ 2 beat)) 1) (string 51))
    (at (subdivide (nome beat) (nome (+ 2 beat)) 3) (string 51))
    (at (subdivide (nome (+ beat 1)) (nome (+ 3 beat)) 1) (string 51))
    (at (subdivide (nome (+ beat 1)) (nome (+ 3 beat)) 3) (string 51))
    (at (nome (+ 4 beat)) (string 51))
    (at (subdivide (nome (+ 4 beat)) (nome (+ 6 beat)) 1) (string 49))
    (at (nome (+ 5 beat)) (string 46))
    (at (nome (+ 6 beat)) (string 51))
    (at (subdivide (nome (+ 6 beat)) (nome (+ 8 beat)) 1) (string 49))
    (at (nome (+ 7 beat)) (string 46))
    (at (nome (+ 8 beat)) (string 51))
    (at (nome (+ 12 beat)) (string 51))
    (at (subdivide (nome (+ 12 beat)) (nome (+ 14 beat)) 1) (string 51))
    (apply-by (nome (+ 16 beat)) bass nome [])))

(defn section [nome]
    (drums nome)
    (bass nome))

;; define a metronome that will fire every eighth note
;; at 100 bpm

(def met (metronome (* 100 2)))
;; to play the beat, just run
;; (section met)
;; (stop)

Advertisement

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: