Instructions for musicalMeasures

(produced at 11:32 a.m. UTC on 2024-09-16)

This task is part of project03 which is due at 23:00 EDT on 2024-09-24.

You have the option to work with a partner on this task if you wish. Working with a partner requires more work to coordinate schedules, but if you work together and make sure that you are both understanding the code you write, you will make progress faster and learn more.

You can download the starter code for this task using this link.

You can submit this task using this link.

Put all of your work for this task into the file musicalMeasures.py
(which is provided among the starter files)

For this problem set, you have a choice: you may complete this task OR the treeParts task, but you do not need to complete both. treeParts is graphics-oriented and works with turtle graphics, while musicalMeasures (this task) is based on audio and music instead, using the wavesynth library.

This task will help you practice the material on custom functions and how to use several functions together to achieve a complicated result. For this task, you will work with the wavesynth.py audio library.

Melodies, Harmonies, Rhythms, and Phrases

For this task, you will be writing code to create a song that involves repetition which has notes and beats layered over each other. You are free to decide what specific melody, harmony, and rhythm you want to use, but there are some restrictions about which functions you must write and how they should interact. (Note: the audio can be quite loud, so you may want to turn down your sound first until you can find the right volume).


Click here to download test_song.wav

You will need to write three base functions that work together to produce the song:

  1. melody which creates a melody using addNote
  2. rhythm which creates a drum line using addBeat
  3. harmony which creates a harmony using chord (a provided function).

Additionally, you will create phrase which will call melody, rhythm, and harmony and will use rewind at least twice to overlap them (you may not use rewind in your melody, rhythm, or harmony functions. Finally, you will write a song function which calls phrase multiple times (possibly in addition to doing other stuff).

The chord, melody, rhythm, harmony, and phrase functions must each return the current pitch to whatever pitch it was when they started, so that they are easier to use together without having to keep track of what changes each one makes. The melody and harmony functions must each call a pitch-changing function such as climbUp, however, so you cannot just leave the pitch completely unchanged. However, there is no specific sequence of notes that you must create.

You are also free to modify the provided chord function, as long as you still call addNote at least twice and it still restores the original pitch when it's done. You are free to decide what arguments each function should use, and even how many arguments they should have. However, you must write one additional function called main which has zero arguments. Your main must call song, and we will use main to test your code.

One final constraint: your main function must not crash and must be able to complete within about 5 seconds. Because wavesynth takes longer the more audio it produces, we recommend sticking with shorter note durations when submitting (using variables and arguments for these would make this easy).

We've provided examples for the following functions:

Once more, you are encouraged to come up with your own song here, these examples are just to illustrate one way to satisfy the requirements and fit things together.

wavesynth.py Usage

Remember to consult the wavesynth quick-reference section for examples of the functions available and what they do, as well as a quick summary of some music concepts if you're struggling to figure out how to achieve what you want.

Testing

We have provided a file named test_musicalMeasures.py which can be used to check some of the constraints specified above, but you should rely on Potluck for thorough testing. We recommend that you test each function as you build it, because the lessons you learn from debugging your earlier functions will help you improve the later functions.

Notes

  • As usual, you must include a non-empty docstring for each function you write.
  • Also as usual, you should not waste fruit or waste boxes, and you shouldn't define functions inside other functions, but these are all extra goals.
  • You are allowed to define and call extra functions if you wish, as long as these don't invalidate the rubric rules for which functions must call which other functions.
  • The longer a song is, the longer it will take Python to process it when it's asked to play or save the song. Using shorter duration values during testing can help alleviate this problem. Especially when testing song, expect to wait a few seconds (maybe as many as 10-20) for the audio to play. When you submit to Potluck, your main function must be able to complete within about 5 seconds.

Examples

melody example

This example shows one way that melody could work. Your melody can use completely different notes, but like this one, it should put the pitch back where it started by the end.

In []:
setPitch(D4) print("Starting at pitch D4...") melody(0.2, 2) print("...final pitch is:", currentPitchName()) printTrack() playTrack()
Prints
Starting at pitch D4... ...final pitch is: D4 a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at F4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at F4 (60% vol) and a 0.2s keyboard note at D4 (60% vol)
Audio

rhythm example

This example shows one way that rhythm could work. Your rhythm can use completely different beats.

In []:
rhythm(0.2) printTrack() playTrack()
Prints
a 0.2s snare beat (8% vol) and a 0.2s snare beat (8% vol) and a 0.2s snare beat (8% vol) and a 0.2s snare beat (8% vol) and a 0.6s rest and a 0.2s snare beat (8% vol)
Audio

harmony example

This example shows one way that harmony could work. Your harmony can use completely different notes, but it must call chord at least twice, and like melody, it must return to the starting pitch when done.

In []:
setPitch(D4) print("Starting at pitch D4...") harmony(0.2, 1) print("...final pitch is:", currentPitchName()) printTrack() playTrack()
Prints
Starting at pitch D4... ...final pitch is: D4 at 0s a 0.2s keyboard note at D4 (18% vol) at 0s a 0.2s keyboard note at Gb4 (18% vol) at 0s a 0.2s keyboard note at A4 (18% vol) at 0.2s a 0.2s keyboard note at E4 (18% vol) at 0.2s a 0.2s keyboard note at Ab4 (18% vol) at 0.2s a 0.2s keyboard note at B4 (18% vol)
Audio

phrase example

This example shows one way that phrase could work. In this case we call melody, then rewind to the beginning, then call rhythm, rewind again, and finally call harmony so that all three stack up on top of each other. Because each function individually returns to the starting pitch, it's easy for phrase to do the same.

In []:
setPitch(D4) print("Starting at pitch D4...") phrase(0.2, 2, 1) print("...final pitch is:", currentPitchName()) printTrack() playTrack()
Prints
Starting at pitch D4... ...final pitch is: D4 a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at D4 (60% vol) and a 0.2s keyboard note at F4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at F4 (60% vol) at 1.4s a 0.2s keyboard note at D4 (60% vol) at 0s a 0.2s snare beat (8% vol) at 0.2s a 0.2s snare beat (8% vol) at 0.4s a 0.2s snare beat (8% vol) at 0.6s a 0.2s snare beat (8% vol) at 1.4s a 0.2s snare beat (8% vol) and a -1.6s rest at 0s a 0.8s keyboard note at C3 (18% vol) at 0s a 0.8s keyboard note at E3 (18% vol) at 0s a 0.8s keyboard note at G3 (18% vol) at 0.8s a 0.8s keyboard note at D3 (18% vol) at 0.8s a 0.8s keyboard note at Gb3 (18% vol) at 0.8s a 0.8s keyboard note at A3 (18% vol)
Audio

song example

This example shows the full song, which calls phrase multiple times.

In []:
setPitch(A4) print("Starting at pitch D4...") song(0.2) print("...final pitch is:", currentPitchName()) printTrack() playTrack()
Prints
Starting at pitch D4... ...final pitch is: A4 a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at C5 (60% vol) and a 0.2s keyboard note at E5 (60% vol) and a 0.2s keyboard note at C5 (60% vol) at 1.4s a 0.2s keyboard note at A4 (60% vol) at 0s a 0.2s snare beat (8% vol) at 0.2s a 0.2s snare beat (8% vol) at 0.4s a 0.2s snare beat (8% vol) at 0.6s a 0.2s snare beat (8% vol) at 1.4s a 0.2s snare beat (8% vol) and a -1.6s rest at 0s a 0.8s keyboard note at G3 (18% vol) at 0s a 0.8s keyboard note at B3 (18% vol) at 0s a 0.8s keyboard note at D4 (18% vol) at 0.8s a 0.8s keyboard note at A3 (18% vol) at 0.8s a 0.8s keyboard note at Db4 (18% vol) at 0.8s a 0.8s keyboard note at E4 (18% vol) and a 0.2s keyboard note at B4 (60% vol) and a 0.2s keyboard note at B4 (60% vol) and a 0.2s keyboard note at B4 (60% vol) and a 0.2s keyboard note at B4 (60% vol) and a 0.2s keyboard note at G4 (60% vol) and a 0.2s keyboard note at B4 (60% vol) and a 0.2s keyboard note at G4 (60% vol) at 3s a 0.2s keyboard note at E4 (60% vol) at 1.6s a 0.2s snare beat (8% vol) at 1.8s a 0.2s snare beat (8% vol) at 2s a 0.2s snare beat (8% vol) at 2.2s a 0.2s snare beat (8% vol) at 3s a 0.2s snare beat (8% vol) and a -1.6s rest at 1.6s a 0.8s keyboard note at A3 (18% vol) at 1.6s a 0.8s keyboard note at Db4 (18% vol) at 1.6s a 0.8s keyboard note at E4 (18% vol) at 2.4s a 0.8s keyboard note at G3 (18% vol) at 2.4s a 0.8s keyboard note at B3 (18% vol) at 2.4s a 0.8s keyboard note at D4 (18% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at A4 (60% vol) and a 0.2s keyboard note at C5 (60% vol) and a 0.2s keyboard note at E5 (60% vol) and a 0.2s keyboard note at C5 (60% vol) at 4.6s a 0.2s keyboard note at A4 (60% vol) at 3.2s a 0.2s snare beat (8% vol) at 3.4s a 0.2s snare beat (8% vol) at 3.6s a 0.2s snare beat (8% vol) at 3.8s a 0.2s snare beat (8% vol) at 4.6s a 0.2s snare beat (8% vol) and a -1.6s rest at 3.2s a 0.8s keyboard note at G3 (18% vol) at 3.2s a 0.8s keyboard note at B3 (18% vol) at 3.2s a 0.8s keyboard note at D4 (18% vol) at 4s a 0.8s keyboard note at A3 (18% vol) at 4s a 0.8s keyboard note at Db4 (18% vol) at 4s a 0.8s keyboard note at E4 (18% vol) and a 0.2s keyboard note at E5 (60% vol) and a 0.2s keyboard note at D5 (60% vol) and a 0.2s keyboard note at C5 (60% vol) and a 0.2s keyboard note at B4 (60% vol) at 5.6s a 0.8s keyboard note at A4 (60% vol) at 4.8s a 1s keyboard note at G3 (18% vol) at 4.8s a 1s keyboard note at B3 (18% vol) at 4.8s a 1s keyboard note at D4 (18% vol)
Audio

Rubric

Group goals:
 
unknown All functions are documented
Each function you define must include a non-empty documentation string as the very first thing in the function.
 
unknown Do not define functions inside of other functions
None of your function definitions may be placed inside of other function definitions.
 
unknown Do not ignore the results of any fruitful function calls
According to the "Don't waste fruit" principle, every place you call a fruitful function (built-in or custom) you must store the result in a variable, or that function call must be part of a larger expression that uses its return value.
 
unknown Do not create any variables that you never make use of
According to the "Don't waste boxes" principle, every time you create a variable (using = or by defining a parameter for a function) you must also later use that variable as part of another expression. If you need to create a variable that you won't use, it must have the name _, but you should only do this if absolutely necessary.
 
unknown main must not crash
Your main function must run without crashing.
 
unknown main song parts must each set the current pitch back to what it started at when done.
We will call your main function without any arguments, starting at several different pitches. We will measure how the current pitch changes, including where it is at the start and end of each inner function call. We will check to make sure that the pitch at the end of each phrase, melody, rhythm, harmony, and chord call is the same as the pitch before that function call started.
 
unknown Define chord
Use def to define chord
 
unknown Call addNote
Within the definition of chord, call addNote in at least 2 places.
 
unknown Define melody
Use def to define melody
 
unknown Call addNote
Within the definition of melody, call addNote in at least 2 places.
 
unknown Call a pitch-changing function
Within the definition of melody, call climbUp, climbDown, halfStepUp, halfStepDown, leapUp, leapDownwavesynth.climbUp, wavesynth.climbDown, wavesynth.halfStepUp, wavesynth.halfStepDown, wavesynth.leapUp, or wavesynth.leapDown in at least one place.
 
unknown Do not call rewind
Within the definition of melody, do not call rewind or wavesynth.rewind.
 
unknown Define rhythm
Use def to define rhythm
 
unknown Call addBeat
Within the definition of rhythm, call addBeat in at least 2 places.
 
unknown Do not call rewind
Within the definition of rhythm, do not call rewind or wavesynth.rewind.
 
unknown Define harmony
Use def to define harmony
 
unknown Call chord
Within the definition of harmony, call chord in at least 2 places.
 
unknown Call a pitch-changing function
Within the definition of harmony, call climbUp, climbDown, halfStepUp, halfStepDown, leapUp, leapDownwavesynth.climbUp, wavesynth.climbDown, wavesynth.halfStepUp, wavesynth.halfStepDown, wavesynth.leapUp, or wavesynth.leapDown in at least one place.
 
unknown Do not call rewind
Within the definition of harmony, do not call rewind or wavesynth.rewind.
 
unknown Define phrase
Use def to define phrase
 
unknown Call melody
Within the definition of phrase, call melody in at least one place.
 
unknown Call rhythm
Within the definition of phrase, call rhythm in at least one place.
 
unknown Call harmony
Within the definition of phrase, call harmony in at least one place.
 
unknown Call rewind
Within the definition of phrase, call rewind or wavesynth.rewind in at least 2 places.
 
unknown Define song
Use def to define song
 
unknown Call phrase
Within the definition of song, call phrase in at least 2 places.
 
unknown Define main with 0 parameters
Use def to define main with 0 parameters
 
unknown Call song
Within the definition of main with 0 parameters, call song in at least one place.