Now everyone knows that you don’t follow V with ii, at least this is probably what your music teacher tried to tell you ;)  18thC Harmony lessons aside this point does question the validity of calling random chord changes a progression.

A russian mathematician named Andrey Markov came up with one neat solution which we’re going to pinch (he was actually interested in russian language usage, but hey whatever).  His work stated that you can construct a probability matrix that outlines the probability of any new state occurring based on a current state.

So let’s look at a very traditional picture (for simplicity’s sake) of Western Diatonic Harmony.  Remembering that in the major key our scale degree’s give us the following chords I-ii-iii-IV-V-vi-viio where roman uppercase are major chords, roman lowercase are minor chords and viio is a diminished chord.  When we add the circle of 5ths into the mix, we end up with a chord progression chart that in it’s simplest form looks something like this (I’ve taken a few liberties based on a few hundred years of usage).

So reading this diagram from left to right we can move from iii to vi.   Then from vi to either IV or ii.  From IV we can then move to either viio, ii, V or I.  From ii we can move to either viio or V.  From viio we can move to V or I.  From V we can move to either vi or I.  And from I we can move anywhere - however in the matrix to the right I have limited I’s movement to iii IV V and vi.  This is a pretty limited view of the harmonic world but we’ll stick with it for today.

Now for the cool part.  We can use random and assoc to trivially implement this markov matrix in impromptu (if you don’t know what assoc does go and quickly check your favorite scheme book).  For this first effort we’re going to assume the key of C major and I’m going to limit the example to the I, IV and V chords only.

;; markov chord progression I IV V
(define progression
(lambda (time chord)
(for-each (lambda (p)
(play-note time piano p 80 40000))
(pc:make-chord 60 73 3 chord))
(callback (+ time 40000) 'progression (+ time 44100)
(random (cdr (assoc chord '(((0 4 7) (5 9 0) (7 11 2))
((5 9 0) (7 11 2) (0 4 7))
((7 11 2) (0 4 7)))))))))

(progression (now) '(0 4 7))

Now that was pretty easy but our list of chords is a little unwieldy.  Fortunately pc-lib has a function that will help us out with that problem.  pc:diatonic is designed to return a chords pitch class given a key and a scale degree.  So if we use (pc:diatonic 0 ‘^ ‘iii) we are asking for iii in the key of c (0) major (‘^).  ‘^ is major and ‘- is minor.  Because impromptu symbols are lowercase only we use ‘i for I ‘v for V etc.  Because pc:diatonic is passed major or minor it is clever enough to know that ‘i means I and that ‘vii means viio in the major key.  In minor ‘i will be minor etc..  Let’s look at an example that implements our entire matrix.

;; markov chord progression I ii iii IV V vi vii
(define progression
(lambda (time degree)
(for-each (lambda (p)
(play-note time piano p 80 40000))
(pc:make-chord 48 77 5 (pc:diatonic 0 '^ degree)))
(callback (+ time 40000) 'progression (+ time 44100)
(random (cdr (assoc degree '((i iv v iii vi)
(ii v vii)
(iii vi)
(iv v ii vii i)
(v i vi)
(vii v i)
(vi ii))))))))

(progression (now) 'i)

Have a listen to my progression progression_one.mp3.  Let’s try playing this on a harpsichord.  But first we’re going to add a couple of performance changes (1) we’ll randomly add mordants and (2) make I and IV twice the duration of the other chords.

;; mordant
(define play-note-mord
(lambda (time inst pitch vol duration pc)
(play-note (- time 5000) inst pitch (- vol 10) 2500)
(play-note (- time 2500) inst (pc:relative pitch 1 pc) (- vol 10) 2500)
(play-note time inst pitch vol (- duration 5000))))

;; markov chord progression I ii iii IV V vi vii
(define progression
(lambda (time degree)
(let ((dur (if (member degree '(i iv)) 88200 44100)))
(for-each (lambda (p)
(if (and (> p 70) (> (random) .7))
(play-note-mord time piano p
(random 70 80)
(* .9 dur) '(0 2 4 5 7 9 11))
(play-note time harpsichord p (random 70 80) (* .9 dur))))
(pc:make-chord 40 78 4 (pc:diatonic 0 '^ degree)))
(callback (+ time (* .9 dur)) 'progression (+ time dur)
(random (cdr (assoc degree '((i iv v iii vi)
(ii v vii)
(iii vi)
(iv v ii vii i)
(v i vi)
(vii v i)
(vi ii)))))))))

(progression (now) 'i)

And here’s a recording of the harpsichord in action progression_two.mp3.  Not bad!

Ok so, as a final exercise let’s try to make a simple ditty for woodwind quintet.  We’re going to need 5 parts and we should try to have some simple part movement (i.e. not just block chords everywhere).  Now to do this, we’re going to cheat and use pc:relative to move from our chord tones on off beats, Arnold Schoenberg would be most unpleased!!  The other thing we’re going to have to do is assign the right instrument to the right part.  I’m playing my instruments on the same audiounit but using different midi-channels for each instrument.  We’ll also add an even longer duration option for I and IV.  Let’s take a look at how this might look.

;; Wind Quintet

(define flute 0)
(define oboe 1)
(define clarinet 2)
(define horn 3)
(define bassoon 4)

(define progression
(lambda (time degree)
(let ((dur (if (member degree '(i iv)) (random (list 88200 (* 2 88200))) 44100)))
(for-each (lambda (p inst)
(cond ((and (> (random) .7) (< dur 80000))
(play-note time sampler p (random 60 70) (* .3 dur) inst)
(play-note (+ time (* .5 dur)) sampler
(pc:relative p (random '(-1 1))
'(0 2 4 5 7 9 11))
(random 60 80)
(* .3 dur) inst))
(else (play-note time sampler p
(random 60 70)
(* .7 dur)
inst))))
(pc:make-chord 36 90 5 (pc:diatonic 0 '^ degree))
(list bassoon horn clarinet oboe flute))
(callback (+ time (* .8 dur)) 'progression (+ time dur)
(random (cdr (assoc degree '((i iv v iii vi)
(ii v vii)
(iii vi)
(iv v ii vii i)
(v i vi)
(vii v i)
(vi ii)))))))))

(progression (now) 'i)

Wind Quintet Number 1. By Impromptu progression_three.mp3  Bring back the beat I hear you say.  OK, onto Beat & Tempo.