LSTM Neural Network that tries to write piano melodies similar to Bach's
Switch branches/tags
Nothing to show
Clone or download
Latest commit 0fb8230 Nov 5, 2018
Permalink
Failed to load latest commit information.
.gitignore Initial commit Jul 17, 2016
LICENSE Initial commit Jul 17, 2016
README.md Update README.md Nov 5, 2018
chorales.lisp Initial Commit Jul 17, 2016
musicnetwork.py Initial Commit Jul 17, 2016
parse midi.py Initial Commit Jul 17, 2016
parsemusic.py Initial Commit Jul 17, 2016

README.md

This is a super old project! I did this when I was first learning about neural networks; please don't judge me too hard based on what you find in this repo ;)

Bach_AI

LSTM Neural Network (python 2.7) that writes piano melodies similar to Bach's.

Here's an example: https://www.noteflight.com/scores/view/c89c26b9f26aaab8aa3aff178b09c762e8722d44

Dependencies

It all runs on python 2.7

You'll need pybrainv

pip install pybrain

and midiutil

http://www.emergentmusics.org/midiutil

What the different files do

Chorales.lisp, parsemusic.py, and musicnetwork.py all need to be in the same directory.

Chorales.lisp is the song data

parsemusic.py turns Chorales.lisp into a dataset

musicnetwork.py uses that dataset to write melodies, it is the neural network.

parse midi.py is what turns the output of the neural network into a MID file.

How to use

With everything set up in the same directory, it will be fairly easy. Simply run musicnetwork.py and it will print the dataset it's using, followed by the songs it produces at various epochs. The network will train on the dataset for one epoch, and then print a song. It does this forever, so you can just let it run for a while and then turn the latest song into a MID file. To do this, you will need to copy and paste. musicnetwork.py will output something like this:

[[5, 2, 1, 1, 0], [7, 8, 1, 1, 0], [27, 4, 0, 2, 0], [26, 11, 0, 2, 0], [19, 3, 0, 1, 0], [16, 4, 0, 1, 0], [16, 1, 1, 1, 0], [15, 3, 1, 1, 0], [13, 2, 2, 1, 0], [14, 4, 2, 1, 0], [11, 2, 2, 0, 0], [7, 3, 2, 0, 0], [5, 5, 1, 0, 0], [8, 4, 1, 0, 0], [5, 5, 0, 1, 0], [6, 6, 0, 1, 0], [6, 0, 3, 1, 0], [10, 6, 3, 1, 0], [11, 2, 2, 1, 0], [14, 5, 2, 1, 0], [-3, 3, 2, 0, 0], [-2, 1, 2, 0, 0], [9, 2, 2, 0, 0], [2, -1, 2, 0, 0], [9, 3, 1, 0, 0], [4, 1, 1, 0, 0], [2, 3, 0, 0, 0], [-4, -3, 0, 0, 0], [-1, 10, 0, 0, 0], [-8, 0, 0, 0, 0], [-2, 1, 1, 0, 0], [-12, 1, 1, 0, 0], [4, 3, 2, 0, 0], [-5, 9, 2, 0, 0], [3, 0, 3, 0, 0], [-1, 4, 3, 0, 0], [0, 0, 2, 0, 0], [-2, 6, 2, 0, 0], [-3, 2, 1, 0, 0], [-8, 0, 1, 0, 0], [-4, 6, 0, 0, 0], [-7, 1, 0, 0, 0], [-4, 4, 1, 0, 0], [2, 3, 1, 0, 0], [1, 0, 3, 0, 0], [12, 1, 3, 0, 0], [6, -1, 4, 0, 0], [14, 4, 4, 0, 0], [7, -1, 5, 0, 0], [19, 1, 5, 0, 0], [7, -1, 3, 0, 0], [13, 5, 3, 0, 0], [5, -2, 2, 0, 0], [10, 6, 2, 0, 0], [0, 2, 2, 0, 0], [9, -1, 2, 0, 0], [-2, 3, 1, 0, 0], [10, 5, 1, 0, 0], [1, 7, 1, 0, 0], [14, 3, 1, 0, 0], [-8, 0, 2, 0, 0], [12, 6, 2, 0, 0], [-1, -1, 0, 0, 0], [14, 6, 0, 0, 0], [-1, -2, 3, 0, 0], [17, 7, 3, 0, 0], [-3, 0, 1, 0, 0], [3, 8, 1, 0, 0], [-8, 10, 0, 0, 0], [1, 9, 0, 0, 0], [2, 3, 0, 0, 0], [-1, 4, 0, 0, 0], [0, 10, 0, 0, 0], [1, 6, 0, 0, 0], [3, 2, 1, 0, 0], [3, 4, 1, 0, 0], [5, 5, 0, 0, 0], [3, 1, 0, 0, 0], [-3, 2, 1, 0, 0], [8, 1, 1, 0, 0], [-5, 3, 1, 0, 0], [6, 2, 1, 0, 0], [-4, 3, 1, 0, 0], [5, 4, 1, 0, 0], [-2, 0, 2, 0, 0], [4, 0, 2, 0, 0], [0, 1, 1, 0, 0], [9, 3, 1, 0, 0], [5, -1, 3, 0, 0], [13, 1, 3, 0, 0], [4, 0, 2, 0, 0], [10, 0, 2, 0, 0], [5, 0, 2, 0, 0], [12, 3, 2, 0, 0], [3, 3, 3, 0, 0], [6, 8, 3, 0, 0], [15, 6, 1, 0, 0], [10, 6, 1, 0, 0], [18, 7, 0, 0, 0], [13, 9, 0, 0, 0]]

Simply copy and paste that single line into "parse midi.py" so it's equal to the variable "songdata", like so:

songdata = [[5, 2, 1, 1, 0], [7, 8, 1, 1, 0], [27, 4, 0, 2, 0], [26, 11, 0, 2, 0], [19, 3, 0, 1, 0], [16, 4, 0, 1, 0], [16, 1, 1, 1, 0], [15, 3, 1, 1, 0], [13, 2, 2, 1, 0], [14, 4, 2, 1, 0], [11, 2, 2, 0, 0], [7, 3, 2, 0, 0], [5, 5, 1, 0, 0], [8, 4, 1, 0, 0], [5, 5, 0, 1, 0], [6, 6, 0, 1, 0], [6, 0, 3, 1, 0], [10, 6, 3, 1, 0], [11, 2, 2, 1, 0], [14, 5, 2, 1, 0], [-3, 3, 2, 0, 0], [-2, 1, 2, 0, 0], [9, 2, 2, 0, 0], [2, -1, 2, 0, 0], [9, 3, 1, 0, 0], [4, 1, 1, 0, 0], [2, 3, 0, 0, 0], [-4, -3, 0, 0, 0], [-1, 10, 0, 0, 0], [-8, 0, 0, 0, 0], [-2, 1, 1, 0, 0], [-12, 1, 1, 0, 0], [4, 3, 2, 0, 0], [-5, 9, 2, 0, 0], [3, 0, 3, 0, 0], [-1, 4, 3, 0, 0], [0, 0, 2, 0, 0], [-2, 6, 2, 0, 0], [-3, 2, 1, 0, 0], [-8, 0, 1, 0, 0], [-4, 6, 0, 0, 0], [-7, 1, 0, 0, 0], [-4, 4, 1, 0, 0], [2, 3, 1, 0, 0], [1, 0, 3, 0, 0], [12, 1, 3, 0, 0], [6, -1, 4, 0, 0], [14, 4, 4, 0, 0], [7, -1, 5, 0, 0], [19, 1, 5, 0, 0], [7, -1, 3, 0, 0], [13, 5, 3, 0, 0], [5, -2, 2, 0, 0], [10, 6, 2, 0, 0], [0, 2, 2, 0, 0], [9, -1, 2, 0, 0], [-2, 3, 1, 0, 0], [10, 5, 1, 0, 0], [1, 7, 1, 0, 0], [14, 3, 1, 0, 0], [-8, 0, 2, 0, 0], [12, 6, 2, 0, 0], [-1, -1, 0, 0, 0], [14, 6, 0, 0, 0], [-1, -2, 3, 0, 0], [17, 7, 3, 0, 0], [-3, 0, 1, 0, 0], [3, 8, 1, 0, 0], [-8, 10, 0, 0, 0], [1, 9, 0, 0, 0], [2, 3, 0, 0, 0], [-1, 4, 0, 0, 0], [0, 10, 0, 0, 0], [1, 6, 0, 0, 0], [3, 2, 1, 0, 0], [3, 4, 1, 0, 0], [5, 5, 0, 0, 0], [3, 1, 0, 0, 0], [-3, 2, 1, 0, 0], [8, 1, 1, 0, 0], [-5, 3, 1, 0, 0], [6, 2, 1, 0, 0], [-4, 3, 1, 0, 0], [5, 4, 1, 0, 0], [-2, 0, 2, 0, 0], [4, 0, 2, 0, 0], [0, 1, 1, 0, 0], [9, 3, 1, 0, 0], [5, -1, 3, 0, 0], [13, 1, 3, 0, 0], [4, 0, 2, 0, 0], [10, 0, 2, 0, 0], [5, 0, 2, 0, 0], [12, 3, 2, 0, 0], [3, 3, 3, 0, 0], [6, 8, 3, 0, 0], [15, 6, 1, 0, 0], [10, 6, 1, 0, 0], [18, 7, 0, 0, 0], [13, 9, 0, 0, 0]]

After this, just run "parse midi.py" and it will output "song.mid", which contains the melody. Sometimes these files aren't playable as is. To turn this into an actual playable MIDI file, I uploaded it to https://onlinesequencer.net/ (through the "import midi" function), and then exported it as a playable midi file which I then downloaded.

How it works

I trained my neural network on a dataset of hundreds of melodies by Bach. It looks at each melody 2 notes at a time (that is, the dataset it trains on has an sample of two notes, and then the expected output is the next two notes). It has 30 LSTM layers of 30 neurons each. To generate a song, it first starts with two random notes, then it runs these through the network to get the next two 'expected' notes. It repeats this process and feeds the network the 'expected notes' while appending everything to a list of notes (each list contains ~100 notes), which is then turned into a MID file with "parse midi.py".