Listen to my MISPELling
expremigen - a lesson in MISPEL
Expremigen is an expressive midi generation library written in python by shimpe. It’s an exceptional tool to create musical compositions which can be rendered into MIDI and played out to an audio device.
In this post, we’re going to cover how to setup your OSX-based computer to play a midi file and then dive into using the python library, expremigen and it’s MIDI Specification Language (MISPEL) to generate some midi compositions.
Setting up your computer to play MIDI
I think one of the easiest ways to set up your computer to play midi files is to use brew. If you’re not familiar with brew, check it out. It’s a must for the missing applications and resources essential to making your Mac far more useful.
The tool we want to install is called fluidsynth. And the easiest way to install is is with brew:
brew install fluidsynth
After you install it, you’ll need to add a Soundfont. Check out Christian Collins soundfont download page.
Download this soundfont and install it in a directory like /usr/local/share/fluidsynth
. Then, after you install it, create an alias to reference
the file and take a parameter to play the midi file passed to the alias as an argument. For example, I use the following:
alias mplay='function __mplay() { \
fluidsynth -i /usr/local/share/fluidsynth/GeneralUser\ GS\ v1.471.sf2 $1; unset -f __mplay; \
}; __mplay'
Now you can easily play any midi file by using the alias - mplay eg.midi
.
Okay, now that we’re all set to play midi files, let’s dive into MISPEL and the expremigen python library.
Before we can use it, we need to install it. But before we can even install it, we need to install the dependencies. A few notes to save you some time from pulling out all of your hair. Keep in mind, this library uses python 3.6.X. so if you don’t have it, you’ll want to once more turn to brew.
Next, it’s advised to use virtualenv for your installation. Since we’re using python 3.x and not 2.X, we need to use the pyvenv tool to create our virtualenv. Moreover, since you want to use the python 3.6.X version of python that you’ve installed with brew, you need to make certain that you call the correct pyvenv. Most likely, your path will reference the Apple version of python 3, which IS NOT 3.6.
Make sure you use the absolute path as below:
/usr/local/Cellar/python3/3.6.3/bin/pyvenv env
You may receive a warning telling you that pyvenv is deprecated. If you want to be proper, you can use the following to generate your virtualenv:
/usr/local/Cellar/python3/3.6.3/bin/python3.6 -m venv env
Note, the last argument to either command above, env is the name of your virtualenv. You can name it whatever you like.
To activate the virtual environment, be sure to source it:
source env/bin/activate
Now that we have an activated virtual python environment, we’re ready to install the dependencies and the main expremigen library.
pip3 install MIDIUtil
pip3 install textX
pip3 install vectortween
And lastly, clone expremigen, cd into the cloned directory, and install the expremigen library using the standard python setup.py install
Verify that you’ve properly installed the dependencies as well as the library itself by importing it into python in the virtual environment.
python
>>> from expremigen.io.pat2midi import Pat2Midi
>>> from expremigen.mispel.mispel import Mispel
>>>
If you don’t get an output similar to the above, go back and make sure you’ve followed the instructions from the beginning.
MISPEL a DSL for MIDI-Generation
Now that we’re all set, let’s take a look at some of the examples in the library example directory. The first example to look at
to give you a sense for MISPEL is example_readme.py
:
from expremigen.io.pat2midi import Pat2Midi
from expremigen.mispel.mispel import Mispel
outputfile = "output/example_readme.mid"
def make_midi():
m = Mispel()
m.parse(r"""
with track 0 channel 0:
c4_16\vol{p}\tempo{120} e g c5 b4 g f d c_4 r\vol{ff}\tempo{60}
with track 1 channel 1:
<c3_4\vol[mp] e3 g> <b2\vol[f] d3 g> <c3_2\vol[mf] e g c4>
""")
p2m = Pat2Midi(m.get_no_of_tracks())
m.add_to_pattern2midi(p2m)
p2m.write(outputfile)
if __name__ == "__main__":
make_midi()
Let’s look at the main function here, make_midi()
. There are two main things to be aware of here.
First, we have the familiar python constructions and library-specific calls. But within the standard python code, we have
the embedded MISPEL DSL between the multi-line string wrapped with starting and ending triple-quotations ("""
).
So, what’s going on here?
- First, we create a Mispel object,
m
, and next, we pass our MISPEL code to theparse
function. - We then create a Pattern-to-Midi object
Pat2Midi
, passing out MISPEL tracks as a parameter. - Next, we call the
add_to_pattern2midi
on our Mispel object, passing it our Pattern-to-Midi object. - Lastly, we call
write
on our Pattern-to-Midi object, passing it a filename where we want our midi output written.
The skeleton is virtually the same regardless of how we wish to write our MISPEL DSL within the quotes. The real magic of what we ultimately here occurs in the MISPEL DSL.
Let’s take a closer look here. We start off by specifying a track and midi channel. Then, within the track/channel specification, we write a grammar that specifies notes, rhythms, and even sound dynamics in musical notation nonetheless.
Dissecting the track 0, channel 0 MISPEL tells us the following:
"""
c4_16\vol{p}\tempo{120} e g c5 b4 g f d c_4 r\vol{ff}\tempo{60}
"""
We play a 16th note with a C note having a command, indicated by the backslash followed by a literal - vol
the value of the command is encapsulated
with curly brackets - {p}
. Additional commands may follow. Here we speficy a tempo as well. next we specify additional notes. Keep in mind that
subsequent notes will inherit the rhythmic value of the last specified note. So we end up with a progression of 16th notes, starting with the c
,
e
, g
, c5
, b4
, g
, f
, and d
. The next note, c_4
specifies a quarter note, and the r
following it inherits its subsequent rhythmic value,
resulting in a quarter-note rest. We also add two more commands to the last note (the rest) - a vol
command with the value ff
specifying fortissimo and temp with a value
of 60. The cool thing here is that the phrase will start off with volume dynamics of p
and end with volume dynamics of ff
– effectivly creating a crescendo.
Similarly, The tempo will decelerate from 120 beats per second to 60 beats by the time we finish the phrase.
While there’s not really a documentation describing the grammar in great detail, the repo README.md
does detail a bit further some
other options that exist in the MISPEL grammar.
Now that we know how to generate a MISPEL grammar, we can use this with our algorithmic compositional strategies to make real music!
Before we do that, get familiar with the MISPEL DSL and generate some cool dynamic audio content. Next up, we’ll begin to look at using MISPEL programmatically to genenerate music.
** Note. Here’s a bonus tip! If you want to be able to convert your midi files into mp3 and/or wave files. Do the following:
- install fluidsynth but specifiy the option –with-libsndfile.
brew install --with-libsndfile fluidsynth
- use brew to install lame (mp3) and libsndfile
brew install libsndfile lame
- generate wave files with
fuildsynth
-fluidsynth -F output.wav /usr/local/share/fluidsynth/GeneralUser\ GS\ v1.471.sf2
- generate an mp3 file with
lame
-lame output.wav
Here’s the MISPEL midi file above converted to mp3: example_readme