< Back

Music Synthesis

Sound is simply a vibration of the air molecules around you. Pleasing sounds have some nice structure to the vibrations. These are continuous structures, but our computers are inherently digitial, discrete beings. To play music on a computer, we generate a series of samples of the continuous wave. For this assignment you will create a program that can read a textual music notation file and synthesize a digital representation of a simple stringed instrument playing the music. The program will use the Karplus-Strong string synthesis algorithm to generate the samples.


Setup

Create a directory assignment9 under assignments in your cs170 directory. All code for the assignment should be stored in this directory.

cd ~/cs170/assignments
mkdir assignment9
cd assignment9

Details

Create a program that creates a wave file of the music in a text file specified through the command line. The program should use the Karplus-Strong algorithm (described below) to generate the sound samples. The following is an example of a music file that contains four ascending notes played one beat apart:

120 4
-1 1.0
0 1.0
1 1.0
2 1.0

The first line of the music file is the header that specifies information about the rest of the file. The header line consists of two space separated integers. The first integer is the number of beats per minute to play the rest of the file and the second integer is the total number of beats of the music in the file. All subsequent lines of the music file specify notes to be played. A note line consists of an integer and a real number separated with a space. The integer is a note to be played. The real number specifies the number of beats to wait until playing the next note. The note 0 is concert A, or 440Hz. A positive note with value n is n steps higher in pitch than concert A. A negative note with value -n is n steps lower in pitch than concert A.

Note that the relationship between the difference in pitch of two notes and frequency is not linear. The frequency of any note can be computed from the number of steps it is from concert A using the following equation:

440 * 2n / 12

Where 440 is the frequency, in Hertz, of concert A, n is the number of steps that a note is away from concert A, and 12 is the number of steps in an octave.

The Karplus-Strong algorithm heuristically generates samples that model a simple stringed instrument, such as a harp, piano, or guitar. The algorithm begins with a linked list of randomly generated floating point numbers between -1 and 1. The length of the linked list determines the pitch of the string. To produce a sample of a particular note, you simply remove the first node of the linked list. The data of this removed node is the current sample to be produced. In order to maintain the same pitch of the note as more samples are produced, the length of the list must remain the same. To accomplish this, a new value must be added to the end of the linked list. This new value is the simple arithmetic mean of the produced sample and the new value at the head of the list, multiplied by a decay value (a value between 0 and 1). A good decay value is 0.996.

To generate the samples for a single note, first compute the length of the Karplus-Strong linked list by dividing the number of samples per second by the frequency of the note to play. A good sample rate to use 44,100 Hertz, or 44,100 samples per second. The number of times that a sample is generated is determined by the duration of the note as specified in the music file. You will have to convert the number of beats to a number of samples by using the sample rate and the number of beats per second of the music file.

The file sound.py contains a class called Sound that can be used to create audio files. Samples generated with the Karplus-Strong algorithm can be added to a sound with the add_sample method. Once all of the samples have been added, the samples can be written to a wave file using the write method.

Once you've tested your program on simple examples like the one above, you can test your program on the file test_song_1.


Submission

You are required to submit a tar file to http://inquire.roanoke.edu/. On inquire, there is a link for Assignment 9. You can create a tar file by issuing the following commands:

cd ~/cs170/assignments
tar czvf assignment9.tgz assignment9/

"Hacker" Prompt

  1. Chords: Music files can specify that multiple notes be played at once by specifying that the wait until the next note is 0 beats. The following is an example of a music file that plays a C major chord for four beats:

    120 4
    -2 0.0
    -5 0.0
    -9 4.0

    In order to play multiple notes simultaneously, you will need a linked list for each of the notes. Each should be initialized to the length that corresponds to the note's frequency. Then, sum the result of the samples generated from all of the linked lists Note that the sum may be outside of the range of -1 to 1. If this occurs, just clamp the value into the appropriate range. That is, if the sum is greater than 1, set the sum to 1, or if it is less than -1, set the sum to -1.

    Once you've tested your program on simple examples like the one above, you can test your program on the file test_song_2.

  2. Compose or Transpose: Write your own song in or transpose an existing song to the text music file format. Be prepared to play your composition in class.

  3. Visualize: If you are terribly disappointed that this assignment does not have any graphics, you can add some. Create a program that displays the waveform of the sample array that corresponds to a music file that is generated with your program. Each sample can be represented as a point in two dimensions where the sample value is the y value and the depth in the linked list is the x value. Note both the x and y values will have to be scaled so that they fit the window dimensions. Create a window that is wide but not tall. The sample points can then be drawn to the window by either drawing a small oval for each, or drawing lines connecting neighboring samples.