What does your commit sound like?

348cb82a — fix typo in controller before_action

The product team at carwow is home to more than a handful of musicians, so you’ll often overhear conversations on guitars, synths and occasionally recorders. One such conversation on music and programming reminded me of my old guitar tab parsing experiment written many years ago, one that made use of an awesome gem called micromidi.

Returning to the idea of using a programming language I enjoy (Ruby) with another hobby I enjoy (songwriting) led me to think about what else I could do with this gem, something useful perhaps, helpful for others in my team and the dev community at large…

Unfortunately I was very quickly hooked on doing something much less useful but definitely just as fun—what does a commit sound like?


Before I dive into exactly how I achieved that, let me introduce how micromidi and GarageBand work together.

How to play a synth with Ruby

The basic setup is:

  1. Open a MIDI channel on your machine
  2. Set up GarageBand to play an instrument when notes are sent to the channel
  3. Write and run the Ruby code to send notes to the channel

On a Macbook you will need to open the Audio MIDI Setup program, then go to Window -> Show MIDI Studio. You should see a dark grey panel like the lefthand side of the screenshot below.

Double click on the IAC Driver item to open the panel on the right and then make sure that the Device is online checkbox is ticked before clicking Apply. You will now have a MIDI channel open.

To set up GarageBand, open the program and create a new Project, selecting Keyboard Collection as the base. This will give you a wide range of instruments to choose from once we have the notes playing. Once it’s open select any instrument track, then go to GarageBand -> Preferences -> Audio/MIDI and make sure you can see the MIDI input detected like in the screenshot below.

Micromidi provides a neat DSL to let you send notes to a MIDI output, allowing you to send a named note (or an array of notes) as well as the duration. Here’s an example:

require "midi" # gem install micromidi
output = UniMIDI::Output.open(:first) 
MIDI.using(output) do  
play "F4", 0.5
end

The second line in the above code will simply return the first MIDI output detected, in our case the channel opened in step 1. Then the DSL provides a using method that accepts this output channel, and any calls inside the block will make use of that channel.

If you run the above ruby code you should hopefully hear something like this following clip:

Since this is just Ruby you get access to all the features of a normal programming language, such as loops in the below example.

require "midi"
o = UniMIDI::Output.open(:first)
MIDI.using(o) do
4.times do |oct|
octave oct + 2
play "C", 0.25
play "D", 0.25
play "E", 0.25
play "G", 0.25
end
play "C6", 0.25
4.times do |oct|
octave 5 - oct
play "G", 0.25
play "E", 0.25
play "D", 0.25
play "C", 0.25 unless oct == 3
end
end

Now for the fun part.

How to turn any commit SHA into a melody

A standard short form git commit message takes the form of 8 hexadecimal characters, 79759e3b. An even number means we could easily transform this into a series of notes to be played in sequence, similar to an arpeggio.

This led me to the simple algorithm to create a 8-note sequence for each 8-character commit SHA:

  1. Take the first character of the SHA and map its position in the list of 16 hexadecimal characters onto the list of the 12 notes in the chromatic scale, starting at C. This gives us the root note for the scale the notes will come from, such as F#.
  2. Take the second character, and use its position in the list of 16 hexadecimal characters to pick from a set of scales, in this case just major and minor scales. This combined with the root note gives us a key, such as F# Major.
  3. These scales are 8 notes long and defined as steps away from the root note along a chromatic scale, so the Major scale would be [0,2,4,5,7,9,11,12].
  4. The next step is to map the position of each note in the commit SHA to an equivalent position in the list of 16 hexadecimal characters and then half it, giving us a highest possible position as 8. We then reverse the list to try and ensure we don’t start on the root note most of the time. For example the commit above gives us the following list: [5, 1, 7, 4, 2, 3, 4, 3].
  5. The next step is to take this list of 8 numbers and treat each item as an index in the scale, mapping over the list to pull out the number at that index in the scale. In this commit’s case, this gave us: [9, 2, 12, 7, 4, 5, 7, 5].
  6. Finally, we map over that list of steps and transpose the root note (F#) by that number of steps along the chromatic scale to give you a new note in each position, finally giving a list of notes such as [“Eb5”, “G#4”, “F#5”, “C#5”, “Bb4”, “B4”, “C#5”, “B4”]

This is the final code for the above:

The evidence

Running this code logs a line with the outcome of the algorithm and then uses micromodi to send the notes to GarageBand.

$ ruby musical_commit.rb ~/path/to/repo_a
bb5f3455: key of A4 major : ["C#5", "C#5", "C#5", "B4", "A5", "C#5", "F#5", "F#5"]
$ ruby musical_commit ~/path/to/repo_b
79759e3b: key of F#4 major : ["Eb5", "G#4", "F#5", "C#5", "Bb4", "B4", "C#5", "B4"]

The reality is that the chance of the algorithm producing anything vaguely listenable depends very much on the variation in the 8 characters in the commit, so the outputs did vary wildly. There was some success however — one of our latest commits for an internal tool produced a haunting folk-like melody:

Extending the algorithm slightly then playing the same pattern through different instruments helped produce bass notes and a drum track for another repo:

All in all, the algorithm isn’t particular clever, and there is clearly much more that could be explored here — manipulating MIDI inputs from GarageBand as one example, or using the features of a commit SHA to change the timings of the notes being played across multiple tracks.

Hopefully this will inspire some further explorations into the intersection of music and programming — what do your commits sound like?

Elsewhere

Of course Ruby is not the only language that can help you create music, so here are some other useful libraries I am aware of in other languages — feel free to post any others in the comments.