The purpose of this lab is to:
As requested in the prelab, please use headphones while working on this lab.
Download the file mozart.tar into your cs150 folder and unpack it. Do NOT save it in your lab09 folder!
# save the file mozart.tar into ~/cs150 % In a terminal window navigate to your cs150 folder and tye tar xvf mozart.tar % ls
You should now have the directories Mfiles and Tfiles, each containing a slew of .wav files.
Now create a folder called lab09 inside your cs150 folder. This is where you'll put all the files you create for this lab. You should save the following files into your lab09 folder. If you use the chromium browser you can right-click on each of the links and select "Save link as ..." from the popup box that appears. Other browsers have the same capability, perhaps with different terminology.
Do NOT move the Tfiles or Mfiles folders, or their contents. We do not want you submitting a bajillion .wav files when you run handin. The lab machines will break. More than usual.
Now let's check that you have what it takes to play sound files. Plug in your headphones, and use the file browser to navigate your way to the lab09 directory. If you've untarred the files properly, you should have some music files (with the .wav extension) in the Mfiles and Tfiles directory within your cs150 directory. Right-click on one of these files and open it with Audacity.
If you don't hear anything, then your sound may be either muted or turned down. In a terminal window type
This will start a program that adjusts volume. With the cursor in the mixer window, use the F6 key (at the top of the keyboard) to bring up the soundcard information. With the arrow keys move the gray line down to
1 HDA Intel PCH
Select this line wtih the Enter key. This will bring up a graphical display of 7 volume controls, labeled "Master", "Headphones", "Speaker", "PCM", and so forth. If the control is turned on it should have "OO" at the bottom (meaning left and right chanels are both On); if it is off it will have "MM" at the bottom (meaning both chanels are Muted). You can use the left and right arrow keys to move to each control; the "M" key will toggle between "OO" and "MM" for this control. You need to be sure that the Master, Headphone, and PCM controls are all in the "OO" position. When the controls are on you can change their levels with the up and down arrow keys, though they are probably already set to the maximum volvue and that is okay. You can use the ESC key to exit from the alsamixer application.
First, let's talk about music representation in .wav files. Each music note is just a sine wave. This wave is defined by its frequency (pitch), its amplitude (volume), and its length (duration). Middle C (the center key on a piano) has frequency around 523, and a safe volume is an amplitude under 1. We can define all notes relative to this one: to go up a semitone, you just multiply your frequency by the 12th root of two (1.05946).
For example, C# (C sharp) has the value 523*(2**(1/12))=554, and B has the value 523/(2**(1/12))=493. There are 12 semitones in an octave (count 'em up on a piano if you like), so to go up an octave, you double your frequency (e.g. high C has the value 1046).
You can refer back to the prelab for all the details. For now all you really need to know is that at second t, the y-value of the sound wave is amplitude*sin( 2*PI*frequency*t ).
Here is a table listing the frequencies of the middle octave from A to A.
Since we're going to be creating music using sound waves, it seems like a good idea to have a Soundwave class that will represent a sampled sound wave. You should create this class in the file soundwave.py (note that the file name is lowercase, the class name is capitalized) using the following guidelines.
amp*math.sin(2*math.pi*freq*t/samplerate)where the value of freq is
Observe that the note A440 is 3 semitones below C, and indeed if halftones has a value of -3, freq evaluates to 440. Once we've computed the frequency of the note, we're just applying our earlier formula for the sound wave at time t, except that we divide t by samplerate because we're taking samplerate samples for each second.
note = soundwave.Soundwave(6,3,.5)to get an F-sharp with length 3 seconds at volume 0.5,
note = soundwave.Soundwave(2,1)to generate a D with length 1 second at volume 1.0, or
note = soundwave.Soundwave()to generate an empty soundwave object.
Add a function called play to your soundwave class. This function should take no parameters (except for self). The function play should simply pass samples to the audio.play() function.
You should now be able to run the provided file middlec.py. When you run this program, you should hear a single note (C) for approximately 2 seconds. If it works, great, continue onward! Otherwise you'll need to track down some bugs.
snippet = soundwave.Soundwave("imonaboat.wav")
and have this set the samples appropriately. To suppose this, we'll need to do some type checking on the parameters. In particular, if the type of the first parameter passed to the constructor is a string (str), we want to use audio.read_file function on that string to generate our samples list. Otherwise, we want to do what we've been doing.
To check whether halftones is a string representing a .wav file rather than an integer representing halftones from middle C, you can use the function isinstance(halftones,str). As you might expect, this returns True if halftones has type str and returns False otherwise. To put this all together, one part of your constructor will say
if isinstance(halftones, str):
self.samples = audio.read_file(halftones)
To test whether this is working, try running the provided file fromfile.py. You might want to also double-check that the previous programs still work now that you've monkeyed with Soundwave's constructor. If all is good, congratulations, you're now ready to move on to the next part!
A scale is a sequence of notes, defined by the intervals between them. For example, the major scale is defined by the 7 intervals (and hence 8 notes) (2,2,1,2,2,2,1), that is, there are 2 semitones between the first and second notes, and 2 between the second and third notes, but a single semitone between the third and fourth notes, and so on. The C major scale is the major scale starting at C and is thus the sequence of notes starting at around frequency 523 and ending around 1046, that is, the notes (C, D, E, F, G, A, B, C). The D major scale is the major scale starting at D: the sequence of notes (D, E, F#, G, A, B, C#, D). The A major scale is the sequence of notes of (A, B, C#, D, E, F#, G#, A).
There are many other interesting scales, such as the minor scale, defined by the intervals (2,1,2,2,1,2,2), and the blues scale, defined by the intervals (3,2,1,1,3,2) (the scale only contains 7 notes).
For this part of the lab, you should write a program scale.py that will play a scale specified by two inputs from the user: the tonic note as a semitone offset from middle C, and a choice between major, minor, and blues scales. An A scale will have offset 3, a C scale will have offset 0, and so forth.
For example, if variable s holds the initial offset, the major scale consists of semitones
s, s+2, s+4, s+5, s+7, s+9, s+11, and s+12
You should be able to see how those tones come from the major scale intervals [2, 2, 1, 2, 2, 2, 1].
Requirements for your program:
Now let's talk about this Minuet and Trio business. What is a Minuet and Trio? It is musical piece that is often the third movement of a sonata in Classical (i.e, Mozart and Haydn) style.. Both the Minuet and Trio follow a specific rhythm and form, and they are usually combined by first playing the Minuet, then playing the Trio, then the Minuet once more. You can listen to a very nice Minuet and Trio here.
You'll be generating a Minuet and Trio based on a random algorithm developed by Wolfgang Amadeus Mozart himself. Your Minuet will contain 16 measures (musical snippets), as will your Trio. For each of the 16 measures in the Minuet, you will randomly generate a number between 0 and 10 (inclusive); use each such number to pick a specific music snippet from the following table (there are 176 total minuet snippets). For example, if I generate the 16 random numbers (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5) for the Minuet, then I will select the snippets (32, 95, 113, 45, 154, 133, 169, 123, 102, 20, 26, 56, 73, 160, 1, 151). Here is such a randomly generated Minuet and Trio. For the Trio, you do the same thing except your random number is between 0 and 5, inclusive.
In this part of the lab, you will write a program mozart.py that generates such a random Minuet and Trio (that is, it generates a Minuet followed by a Trio followed by your Minuet a second time). There are three main steps to this program, which will be discussed in more detail below.
Requirements and suggestions for your program:
PLEASE READ: When you do your handin, double check that you haven't somehow moved the Mfiles or Tfiles into your lab08 directory.
Check through your files and make sure you have your name at the top in comments. Also, if you followed the Honor Code in this assignment, add a README file to your lab 09 folder with the text:
I affirm that I have adhered to the Honor Code in this assignment.
You now just need to electronically handin all your files.
% cd # changes to your home directory % cd cs150 # goes to your cs150 folder % handin # starts the handin program # class is 150 # assignment is 9 # file/directory is lab09 % lshand # should show that you've handed in something
You can also specify the options to handin from the command line
% cd ~/cs150 # goes to your cs150 folder % handin -c 150 -a 9 lab09
soundwave.py scale.py mozart.py README.txt (for the Honor Pledge)