Algorithmic Music Composition
For this toolbox exercise you will be creating a computer program that composes music! This type of programming is also known as “algorithmic music composition”. You may think that this idea is relatively new, but the history of algorithmic music composition actually goes back to Mozart! For a more recent discussion of algorithmic composition, check out “The Triumph of the Cyborg Composer”.
For this exercise you will create a computer program that improvises a blues solo! You will also be able to experiment with adding a backing track to your blues solo. Here is an example by one of the best (humans) in the biz:
Get Set
Before you can get started with this exercise, you will need to download (1) the Sonic Pi music synthesis program, and (2) a Python library that lets you control Sonic Pi from Python.
Install Sonic Pi
Download and install Sonic Pi.
Linux:
$ sudo add-apt-repository ppa:sonic-pi/ppa
$ sudo apt-get update
$ sudo apt-get install sonic-pi
Test Sonic Pi
Launch the Sonic Pi program. Click on the Search icon at the top of the Ubuntu tool bar.
Type “Sonic Pi” into the search dialog and click on the Sonic Pi icon.
Now, enter play 60 into the text area in the upper left pane (beneath the # Welcome to Sonic Pi
text), and press the “Run” button.
If you hear a tone, you are good to go. Proceed to the next section “Get Set with Python”.
If you do not hear a tone, verify that your volume is turned up.
If that doesn’t work, follow the instructions in
this Stack Overflow answer.
[These are the instructions that start with sudo lshw -c multimedia
, and end with jackd -R -d alsa
.]
Then test Sonic Pi again.
Get Set with Python
First, open up a terminal and execute the following command:
$ pip install python-sonic
Grab the starter code for this toolbox via the normal fork-and-clone method from https://github.com/sd2020spring/ToolBox-AlgorithmicMusic.
Synthesizing Your First Note
Open up the file blues_solo.py
in your editor. Take a minute to read
through the file and make sure you understand the basic steps that are
happening.
When you are comfortable with the given starter code, go ahead and run the Python script. Launch Sonic Pi, and then open a terminal and execute:
$ python blues_solo.py
You should hear a very short blues “solo” that consists of one very low note held for 1 beat. (By default we are playing at 45 beats per minute, so the duration in seconds is 1 1/3 seconds.)
Blues Licks
Okay, that wasn’t all that impressive, but on the other hand we actually synthesized a musical note using Python. That’s pretty cool! To make our blues solo more impressive, we need to randomly string together some blues licks. The basic idea will be to move up and down the blues scale according to these licks (or musical note patterns). Here is an example to get you started. We will create a list of licks. Each lick will contain a list of notes where each note is a list consisting of an interval (meaning the change in notes on the blues scale from the previous note) and a duration in beats. For example, the following line represents a blues lick that consists of four notes. Each note ascends the blues scale one note and lasts for half a beat:
licks = [[(1, 0.5), (1, 0.5), (1, 0.5), (1, 0.5)]]
Let’s modify our code to repeat this lick four times by changing blues_solo.py
in the following way:
curr_note = 0
play_note(BLUES_SCALE[curr_note], 1, BEATS_PER_MINUTE)
licks = [[(1, 0.5), (1, 0.5), (1, 0.5), (1, 0.5)]]
for _ in range(4):
lick = licks[0]
for note in lick:
curr_note += note[0]
play_note(BLUES_SCALE[curr_note], note[1], BEATS_PER_MINUTE)
Go ahead and try it! You will hear part of a blues scale!
Add Some Randomness
In order to make things more interesting, you shouldn’t always execute the
same lick over and over. First, add at least one more lick to the list (e.g.
you might want to replicate the example lick, but instead descend the blues
scale: [(-1, 0.5), (-1, 0.5), (-1, 0.5), (-1, 0.5)]
). One potentially
helpful guideline (that you should feel free to deviate from!) is to make sure
the duration of the sum of all notes in a lick adds up to 2 (this will keep
the solo “on the beat” and make it sound better when we add a backing track
later).
Once you have added a new lick, modify the line of code lick = licks[0]
to
choose the lick at random using the function random.choice
(note that the
function random.choice
has already been imported for you in the starter code
as choice
). Before running your code, you will want to make sure that the
variable curr_note
doesn’t get too high or too low. Make sure you create a
series of if statements to keep the variable from getting less than 0
or
greater than len(blues_scale) - 1
.
Once you have made these changes, you should make the number of licks larger (if you followed the code above this number will be at 4) so you can get a longer solo.
Tips to Make it Cooler
Make it swing:
alternate slightly longer and slightly shorter notes in your blues lick to
give it a swing feel (e.g.
[(1, 0.5 * 1.1), (1, 0.5 * 0.9), (1, 0.5 * 1.1), (1, 0.5 * 0.9)]
)
Avoid hammering the lowest or highest note: the code we added to avoid going
out of bounds of the list blues_scale
has the effect of sometimes hammering
the notes at the boundaries repeatedly. The solo may sound better if you
simply hold the note to the end of the lick if you reach the beginning or end
of the list blues_scale
.
Add a backing track: Sonic Pi can mix together various audio streams. In order to add a backing track to your solo, add this to the beginning of your program:
You will need to download the backing.wav file from the “files” section of the course Canvas page. Once downloaded, move the file to the “samples” directory of your toolbox-algorithmicMusic repo. You can choose to use any .wav file that you wish, but feel free to start with the one we supply using the code below.
BACKING_TRACK = os.path.join(SAMPLES_DIR, "backing.wav")
sample(BACKING_TRACK, amp=2)
sleep(2.25) # delay the solo to match up with backing track
The solo should stay on the beat of the backing track, but won’t really do a good job tracking chord changes.
Add some dynamics: in the basic version of the code, we always use the same volume. You may want to play around with adding licks with increasing or decreasing volume (known as crescendo and decrescendo respectively).
Move beyond simple intervals: in the basic version of the code, the lick is
always defined in terms of changes from the previous note. It may sound good
to start the lick from a specific note on the blues scale. For instance, you
may define a lick that starts on note 6 of the list blues_scale
. Notes 0, 6,
12, and 18 are special in that they are the root or (tonic note) of the blues
scale. It may sound cool for the lick to start on these notes.
Completing the Toolbox Exercise
To complete the toolbox exercise, you should complete all of the steps up to Make it Cooler, and then at least one of the extensions suggested in the Make it Cooler section. After you push your work to GitHub you should schedule a quick meeting to play your sweet tunes for a NINJA.