Have you ever heard a piece of music and known exactly when it was played or who played it? Some pieces take on the identity of their creators. Assuming this is true, would it be possible to automatically know an artist or time period given a piece of music? That is to say, is it possible to define a base structure that is unique to a certain set of musical pieces but not to others?
Let's start with the basics of what music is. Glossing over basics like notes and time, most complete pieces adhere to one or more scales. A scale is something we can define loosely as a finite set of musical notes, even though the real definition is somewhat more complicated.
Let's say a note is this:
data Note = A | A# | …
Each note in a song must be present in its composite scales. If not, the note is "off key". Ever listen to someone sing and get a jarring sensation when they're off? I don't know about the biological mechanism behind it, but I can say with confidence that it happens when the note being sung or played is not in the proper scale.
So knowing that, lets say a scale is this:
type Scale = [Note]
Given a set of notes and scales, we can see if the two coincide.
But what if, given a set of notes and the fact that they are a song that fits a scale(s), can we derive the scales?
We'll need a structure to define our "set of notes". Is there a better name for that? Of course, a song!
data Song = [Note]
Uh oh. It looks like our definition of a scale and our definition of a song are actually the same underlying data structure. Is this true? Could a scale and a song be the same thing?
On the surface… maybe. Who's to say that playing a string of notes isn't actually a song? If your baby cousin say down and banged out some keys on a piano, it might not be a song worth listening to, but who's to say it isn't a song to him?
But still, few people would characterize a scale as a song. There's something just… different about the latter.
Since our model needs to be precise, "something" does not cut it.
An artist said once, paint with light and shadow. Could this be true for music as well? Music needs both sound and space. So maybe a given space in a song could be either a sound or a rest? That sounds about right, so lets roll with it.
data Song = [Either Rest Note]
And of course we must define Rest (this time as a sum data structure):
data Rest = Rest1 | Rest2| …
There we go.
Note how our definition of a song has nothing to do with a scale anymore. This means that we are saying a song can be as off pitch as we like. Artistic freedom!
But seriously, there is no reason to assume that every "song" will fit into a scale. Only the ones that we can attach an algebraic identity to. This is key not only to understand this exercise, but also to get why some music sounds good and some does not ;-)
So now let's come up with a function to see if a song contains a scale:
isScaleInSong :: Scale -> Song -> Bool isScaleInSong _ sg = false isScaleInSong sc _ = false isScaleInSong sc sg
Since a song (that is on key) must only contain notes in a scale, to derive the scale we simply filter out the repeats and sequence them:
songToScale :: Song -> Scale songToScale song = sort . nub $ rights song
Lets put this to the test. I need to pass this function an actual song and see if it works.
I'm going to use the Rebel's Theme from Star Wars because its
1. Recognizable 2. One of my favorites
let RebelTheme = [A, A, D, F, FSharp, G, Fsharp, ...] songToScale RebelTheme
After doing this I was able to see the list of notes used to compose one of the most memorable songs of our generation. Its true, when you listen to them in order you can hear the essence of the actual song.
In doing this I found myself asking another question. Given a scale, can one compose a song? Assuming a song is a progression of notes within a finite set, wouldn’t the composition of a song be a type of unfold? More on this in the next post.