My Latest Project
Tonight I decided to implement a second markov chain to track the timings of the recited song and use those along with the notes to create real songs. The results this time weren't too bad at all. (I've attached a sample of the song to this post)
Give it a listen. I think you'll be somewhat surprised that that's a completely computer generated song.
How'd You Do That?!
There's a fairly simple computer science technique known as a "Markov Chain". Don't let the whole reference to computer science fool you, it's really not tough to grasp. Basically I created a table of numbers that answers the following question: When note X was played what percentage of the time were the other notes played next? So just imagine a table with all of the notes from a to g# laid out on top (these are the notes that we last played) and vertical axis is all of the same notes but this axis represents the probability that that particular note was played next.
Here's a sample of what my program generates:
a a# b c c# d d# e f f# g g#
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 6, 0, 1, 0, 0, 0, 0, 2, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 2, 0, 3, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
You'll have to just imagine that same list of notes listed along the left hand edge of that table since it's too hard for me to put it there myself in this editor. :)
Here's the timings table (1, 1/2, 1/4, 1/8, 1/16 notes):
1 2 4 8 16
[0, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 3, 5, 0],
[0, 2, 4, 11, 0],
[0, 0, 0, 0, 0]
But that's it, that's the magic that drives the whole process. As you can see, I'm actually not storing percentages but instead just the count of the number of times a note led to a different note. It works out to be the same thing in the end.
Grok'd
So to summarize, my program was able to generate the music because I fed it a sample musical score and it figured out what percentage of the time a c note led to another note. Here's a step by step run through:
- Give program a note and a timing.
- When I give it a second note/timing it notes in it's table that the first note led to the 2nd note one time. It also notes that the first timing led to this 2nd timing one time. (note I don't attempt to relate notes/timings, it's not important surprisingly).
- Enter a third note.
- The program then notes in its table that the 2nd note led to the 3rd note one time.
- Continue ad inifinitum
So that's how we set the system up. Next this is how we get the program to come up with its own song:
- Choose some random note/timing to start.
- Ask the computer to suggest what a good note/timing would be to follow those.
- print out the note/timing (in case it's a work of genius ;)
- play each note using the python library I'm using, pysynth.
I know that's pretty general and a pretty quick overview but I'll be giving a more in depth explanation at Portland Code Camp.
Here's a link to my git repo with all of my Python code: http://github.com/jcbozonier/MarkovMusic/tree/master
That's all for now!