/JSB2

Computer-generated music using simple Python code

Primary LanguagePython

JSB2

What is it?

This code is a simple example of how you can auto-compose songs using Python and generate the audio for those songs using FluidSynth.

What's required?

Getting started

  1. Download MIDIUtil from here. From within the downloaded folder, run in a terminal: python setup.py install.
  2. Download and install FluidSynth. Follow instructions for your OS here.
  3. Download the JSB2 code. From within the downloaded folder, run in a terminal: python run_JSB2.py. You just made your first computer-generated song! You'll hear it playing.

What's happening under the hood?

Python code randomly generates notes (within the constraints of some musical structure) that get translated to a midi file. The Python code also generates a file that assigns instrument samples to different channels in the midi file (we'll call this the channel mapping script). The midi file and the channel mapping script are used by FluidSynth to generate an audio file.

How can you interact with the code?

You can:

  • Generate a random song using default parameters.
  • Generate a random song using user-defined parameters like tempo and song structure.
  • Play the song.
  • Save a .raw file of the song (which can be converted to .wav automatically. See 'Generating .wav files').

You can do all of the above by (un)commenting lines in the very short run_JSB2.py file.

How can you modify the code to generate different songs?

The code has lots of comments and has an object-oriented structure, which makes it easy to modify and expand.

Some things you can do to start playing with it:

  • Download a .sf2 audio sample file from the web (there are lots of free resources). Put it in the samples folder and replace the filename in the get_melody_sample function in JSB2.py with the new filename.
  • Remove some of the chords in the chords list in the music_theory class.
  • Replace the logic in the for loop of the set_bass function in JSB2.py with your own.

This code is really only meant to serve as an example of how easy it is to auto-generate songs. You could work within the (rather loose) structure I used, or create your own. The hope is that by knowing how these tools (MIDIUtil and FluidSynth) work together, people can start thinking about the algorithms behind auto-generated music and easily implement their ideas in Python.

Files

  • The samples folder contains .sf2 audio samples.
  • The output_files folder is where all generated files (.mid, .txt, .raw) are saved.
  • JSB2.py has the class implementations.
  • run_JSB2.py is used to interact with the classes and functions.

More stuff

Generating .wav files

Using SoX, you can convert the .raw files generated by FluidSynth into .wav files. Just brew install sox and uncomment the call to convert_raw_to_wav() in run_JSB2. Make sure you call the write_raw_audio() function before the convert_raw_to_wav() function.

How does MIDIUtil generate midi files from Python code?

MIDIUtil writes notes to a midi file like this: midi_obj.addNote(channel_num,note_pitch,time,note_duration,note_volume). That's it; you can just use Python code to generate those variables. Notes with the same channel_num will be played using the same instrument sample. Notes with the same time will be played at the same time in the song.

What's the algorithm used in JSB2 to generate songs?

It's pretty simple:

  • At the start of every bar of music, randomly pick a chord from the set of possible chords.
  • Play a bass note that corresponds to that chord at the start of every bar.
  • Play a rhythm chord at the start of every bar made up of notes from the chord for that bar.
  • At every timestep in the song, randomly play one, none, or some combination of a bass drum, a rim shot, and a high hat.
  • At every timestep in the song, randomly pick the next note higher, the next note lower, or the same note as the previous melody note. Limit the selection of notes to those on the Pentatonic scale. Also, randomly play no note sometimes.
  • With the default settings, four bars makes up a part (verse or chorus) of the song. The order in which these parts are played is specified (default is ['verse', 'verse', 'chorus', 'chorus','verse','verse','chorus','chorus','verse','verse','chorus','chorus']). The same one bar of drums is repeated throughout the song.
  • Notes, chords, keys, and tempo are all randomly picked as the program runs, so every song is different.

You can listen to some songs it made here.

Heads up!

JSB2.py makes use of the subprocess Python module. For your own peace of mind, check out the lines of code that use that module.