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))
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)
python

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


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))
python

And here is the output.

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!