CyberSpy

Rantings from a guy with way too much free time

Listen to my MISPELling

2017-10-23 musings

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 the parse 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

comments powered by Disqus