Playing chords with Mido and Python

Playing something that actually sounds musical

Welcome back. This is part II of my python midi series. Part I can be found here.

Last time we set up our python program to successfully send a midi stream to our midi player.

Today we're going to loop a basic chord progression, and add some texture. Again, my midi player is Ableton Live, but this will work for anything that takes midi input.


Writing Chords -

We're going to start with some basic minor and major triads - the root, the third and the fifth. The major third is 2 whole steps up from the root - 4 steps - and the minor third is a whole and a half step up from the root - 3 steps.

First, our function setup -

1 2import mido 3from time import sleep 4 5def note(note,velocity = 64, time = 2): 6 return mido.Message('note_on',note=note,velocity = velocity, time=time) 7 8def note_off(note,velocity = 64, time=2): 9 return mido.Message('note_off',note=note,velocity = velocity, time=time) 10 11outport = mido.open_output('IAC Driver pioneer') 12 13def majorChord(root, duration): 14 outport.send(note(root)) 15 outport.send(note(root+4)) 16 outport.send(note(root+7)) 17 sleep(duration) 18 outport.send(note_off(root)) 19 outport.send(note_off(root+4)) 20 outport.send(note_off(root+7)) 21 22def minorChord(root ,duration): 23 outport.send(note(root)) 24 outport.send(note(root+3)) 25 outport.send(note(root+7)) 26 sleep(duration) 27 outport.send(note_off(root)) 28 outport.send(note_off(root+3)) 29 outport.send(note_off(root+7)) 30
python

The note method returns a mido.Message object that is sent to the port.

The majorChord and minorChord functions take in their root note, but also a duration argument. These functions play the chord, sleep for the duration, and then turn off the notes by triggering 'note_off' messages.

With this, we can loop a nice chord progression like so -

1C = 60 2G = 55 3A = 57 4F = 53 5 6while True: 7 majorChord(C,1) 8 majorChord(G,1) 9 minorChord(A,1) 10 majorChord(F,1) 11 majorChord(F,1) 12 majorChord(G,1) 13 majorChord(C,2) 14
python

Tada! we have a chord progression! It sounds a bit dull, though, so let's add some texture.

<iframe width="75%" height="265" src="https://clyp.it/2dtqyn41/widget" frameborder="0"></iframe>

Adding Texture -

We're going to make two changes to make this progression sound less robotic. First, in our note generation, we've added a velocity modification variable. With every note generated, the velocity is now anywhere, randomly, between 44 and 84. This changes the intensity of the note.

In addition, we've added a pause function, which inserts of sleep of anywhere between 0 and .05 seconds. We've added this pause between the individual notes on the chord, everyso slightly staggering the notes.

1 2def note(note,velocity = 64, time = 2): 3 velocity_modification = randint(-20,20) 4 return mido.Message('note_on',note=note,velocity = velocity + velocity_modification, time=time) 5 6def note_off(note,velocity = 64, time=2): 7 return mido.Message('note_off',note=note,velocity = velocity, time=time) 8 9def pause(): 10 sleep(randint(0,100) * .0005) 11 12def majorChord(root ,duration): 13 outport.send(note(root)) 14 pause() 15 outport.send(note(root+4)) 16 pause() 17 outport.send(note(root+7)) 18 pause() 19 sleep(duration) 20 outport.send(note_off(root)) 21 outport.send(note_off(root+4)) 22 outport.send(note_off(root+7)) 23 24def minorChord(root ,duration): 25 outport.send(note(root)) 26 pause() 27 outport.send(note(root+3)) 28 pause() 29 outport.send(note(root+7)) 30 sleep(duration) 31 outport.send(note_off(root)) 32 outport.send(note_off(root+4)) 33 outport.send(note_off(root+7)) 34
python

And here is the output.

<iframe width="75%" height="265" src="https://clyp.it/g54lv0zg/widget" frameborder="0"></iframe>

You can hear how much more organic it sounds. Each loop is unique in its velocity and stagger values.

Thanks for reading. Stay tuned for more python midi projects!