Monday, February 18, 2019

Music Theory for Programmers


For this post I wanted to do something a little different. Although my profession is software engineering, I would also call myself an amateur musician. Maybe even a singer/songwriter. I play the guitar, keyboards and a handful of other instruments and also like to write and record music.

For a while now I've been thinking about how much writing code and writing music were similar. And maybe that's why I like doing both things so much. Just like programming I can get lost for hours making a song sound just right. So I decided to enumerate the ways that writing music and writing code are similar. No knowledge of musical notation or theory is required to enjoy this post!

Music Theory for Programmers

You might think that writing code and writing music have nothing in common, but they actually share a lot of similarities. Besides both being creative endeavors that build something from pure thought, the underlying processes are also very similar. For example both are made up of loops and modules, both have varying input and output, and both compile down to binary.

As a programmer I assume you already know a lot about programming. So let me talk a little about how music works. As a human being who listens to music you probably already know a great deal about music whether you realize it or not.
  • Songs are made up of sections such as verse, chorus and bridge
  • Those sections are usually repeated multiple times
  • Songs have a key that dictate which notes are played
  • Songs have an underlying structure or motif
Let's delve into some of the similarities between music and code.

Loops

There are lots of loops in code; we have for loops, while loops, recursive loops. Loops are everywhere in our code. They allow us to iterate over an array or do something over and over until a certain condition exists, or even find the factorial of a number.

Music has a lot of loops too. The drum beat, the bass line, verses and choruses. Without loops music would just be a long string of notes without structure, and pretty dang hard to follow and listen to. The human mind craves patterns. If the listener can't discern any patterns she will write the music off as noise.

Here's what a loop looks like in music notation, called a repeat sign. Here the second note is repeated.


Modules

Code is made up of modules within modules within modules. Programs contain classes, classes contain methods, methods contain code blocks. Modularity is the cornerstone of programming. It's what makes it possible for us to read and understand code and keeps our code DRY (don't repeat yourself).

Music contain modules too. A song contains sections, those sections contain measures, those measures contain notes. Without modules written music would be hard to read too. Imagine pages and pages of musical notes with no delineation. You would get lost pretty quickly.


Which is equivalent to something like this minimized code.


Input/Output

Just as code modules can accept parameters as input to produce different output, so can music. Think of the verse of your favorite song; there probably isn't just one. There are usually at least two or three different verses. But the verses sound pretty much the same, just the words are different. The verse module takes words as an input and applies the structure of the verse's melody to it to produce different output.

Here's the structure of a song represented as if it were a set of code modules.

intro()
verse(A)
$chorus()
verse(B)
$chorus()
bridge()
verse(C)
$chorus()
outro()

Here's an example of a module with varying input. There are two lines of lyrics both set to the same melody.



Development Lifecycle

In code we have a development lifecycle. First we come up with an idea for an application. Then we write some specifications. Next we do the development by writing our code. Finally we debug and refactor our code until it's ready to be released into the wild.

Creating music isn't much different. First you come up with an idea for a song, play around with some chords until it sounds good and then write it down. Next you fire up your DAW and start recording the instruments and vocals then mix and apply effects. Then you find every thing that doesn't sound right and refactoring it until it does sound right. Finally after you have everything sounding right you release it into the wild.

Design Patterns

In programming we have design patterns that describe general, reusable solutions to a commonly occurring problems. There are also common reusable patterns in music that help us build songs. They are known as chord progressions. Chord progressions are a series of chords that are played in a specific order. Certain chord progressions sound very good to the human ear.

Probably one of the most common is the four chord progression I-V-vi-IV. There are countless popular songs using it. The numbers 1, 5, 6, and 4 are chord numbers in a key. In music theory there are seven primary chords in each key, each of which has a number associated with it. In the key of C, I-V-vi-IV translates to the chords C-G-Am-F. The reason numbers are used is so that you can easily move to a different key and have the exact same progression, just higher or lower in pitch.

Check out this mash up of songs all with that same I-V-vi-IV chord progression to see just how pervasive it is:
https://www.youtube.com/watch?v=oOlDewpCfZQ

Software Tools

In programming we have IDEs (integrated development environments) to help us write code. In music we have DAWs (digital audio workstations) to help us record and mix songs. Both make our lives so much easier. Writing code in notepad sucks. And having to record an entire song perfectly  is nearly impossible, at least for me. A DAW allows you to record sounds, add effects to them, cut and paste them and manipulate them in all sorts of ways.

Asynchronous

Plenty of languages support asynchronous coding so we can have multiple things going on at once without blocking. Music is massively asynchronous. You have a number of instruments or vocals all executing at the same time. Here's what playing a section of music might look like in C#.

async Task PlayVerseAsync(string lyrics)
{
    var tasks = new Task[] {
        PlayVocalsAsync(lyrics),
        PlayDrumsAsync(),
        PlayBassAsync(),
        PlayPianoAsync()
    };
    await Task.WhenAll(tasks);
}

Compilers

Music and code both compile down to binary. Your code compiles down to machine executable codes. Music compiles down to digital audio files such as WAV and MP3.

Input Devices

They both use keyboards ;)

Complex Notation

They both have strange and complex notation. If a musician were to look at some source code they would probably have no idea what it means.

function reduce(a: int[], reducer: (int, int)=>int): void {
  let sum: int = 0;
  for (let i = 0; i < a.length; i++) {
sum += reducer(sum, a[i]);
}
return sum;
}

On the other hand if a programmer were to look at some sheet music they would be equally confused. Here's particularly perplexing piece of music.

Bugs

Music and code can both be very frustrating to work on. Sometimes there's a bug in your code and you can't figure it out. Sometimes there's a bug in your song and you can't work it out either. But when you finally do figure it out you feel that rush of greatness!

Conclusion

I hope I have convinced you that writing music and writing code share some similarities. I enjoy doing both. Each gives me the same feelings of starting a project, doing some creative things and getting a sense of accomplishment at the end. Both are a creative process that requires deep concentration and thought. I guess that is the main similarity between the two is the creative process. But as I've shown above it doesn't stop there.

No comments:

Post a Comment