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