Generating Random Music
A while ago, I wrote a tutorial on how to get the NBC/NXC running on Linux in order to program an Mindstorm NXT brick. In the tutorial, I posted an example script that turns the robot into a dancer and plays some music. The only problem is that the music was just set of random frequencies and thus was unbearable to listen to. So I though, is there a way to make it less random without the need to make it play the same thing over and over again?
Experimenting with this idea lead me to write the libmidi library. MIDI files are a collection of notes, so it seemed as the best format to use. It allowed me to just generate random notes and tell the MIDI player to play them in some order. The library also includes an example called randommusic, but just does the same thing as the dancing robot. It just plays 128 random notes. This is what it sounds like:
I am no expert on music theory, but from what I understand most songs contain only notes in one scale. And the idea also works the other way, playing notes in a scale can result in a song. The song won’t be a masterpiece, but it will be bearable. Since I am too lazy to pre-program every possible scale, I decided that I will only limit notes to ones found in an existing song instead of a scale.
After analyzing Piano Sonata No.1, that I grabbed from Kunst der Fuge some time ago, I get the following result:
It sounds much better than before, but it still sounds like it is all over the place. To fix this, I applied one more change to how the next note is picked by looking at one more piece of information when analyzing the song; the note that was played previously. That is if note B never follows note A in the existing song, then it should never do so in the random music. Here is the result:
That was a big improvement! I think that is where I will stop working on this. But more tweaks could be done in the future:
- Add random rhythm
- Analyze multiple songs
Of course, the code still needs to be ported to NXT to make a much more improved dancer robot.
The script that I wrote to do this can be downloaded here and is released under the GPL3 license. To use it, you need to have libmidi and ROOT installed. This is how it works:
- Analyze the song
./analyze input.mid output.root
- Generate a random tune.
- The first argument is the track of the orignal song to analyze, and should be set as track1, track2 and so on. Also you can set it to song, which uses all tracks.
- The second argument is the ROOT file with the analyzed song created in step 1
- The third argument is the output MIDI where the result will be saved
- The fourth argument is optional. Specifying it will ignore any previous note conditional probability.
./generate track input.root output.mid [unconditional]