Instructions for mixedUpMelodies

(produced at 21:45 UTC on 2024-01-30)

This task is part of project02 which is due at 23:00 EST on 2024-02-06.

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 mixedUpMelodies.py
(which is provided among the starter files)

This task is based on 18th-century dice-based music composition, such as Motzart's "Musicalisches Würfenspiel." which involves rolling dice to randomly determine different segments of music to fit together.

Your goal in this task is to write functions that use the wavesynth library to create short melodic segments: intros, refrains, and endings. These functions will be combined with each other to create a mixed-up melody.

Melodic Segments

The focus of this task is on modularity, so we want to write functions which will add audio to the current track while being able to be mixed together with other functions to make a song. There are many possible approaches to this, but for this task, we will stick with something simple: all of our melodies will make sure that they return to the original pitch and volume settings by the end of the function. They don't necessarily have to include a note that uses that pitch, but by returning to it, the next melody function will be able to use that same starting pitch to inform the notes that it adds, and all of the segments will be using a common baseline. Likewise, by maintaining a steady volume, when multiple segments are used we won't wind up slowly becoming much too quiet or loud. However, you should not just use setPitch or setVolume to fix the pitch or volume in any of these functions: they need to be able to return to the starting pitch/volume no matter what those values are to start with. To achieve this, balance out calls to climbUp/climbDown and louder/quieter within the function, OR use currentPitch/currentVolume to measure the pitch/volume at the start of the function so you can return to those values.

You must write three functions for this part of the task: melodyIntro, melodyRefrain, and melodyEnding. In each function, you must:

  1. Set the pitch and volume back to their starting values by the end, as just discussed.
  2. Call addNote and/or addBeat in at least two places (it's okay if these are called indirectly within a custom function, but there must be at least two separate places that such function calls appear in your code).
  3. Call at least two of the pitch- or volume-changing functions somewhere (again it's fine if this happens in a custom function that's called from within the melody function).

Beyond those requirements, melodyRefrain has two extra requirements: you must use some kind of custom function within melodyRefrain, and that function must add at least one note or beat to the composition using addNote or addBeat. Furthermore, in either melodyRefrain or the custom function used within it, you must use rewind somewhere.

Of course, these requirements are pretty open-ended, and it's up to you to decide what kind of melodies you want to create. You can reference the cheeryMelody.py and drumsMelody.py starter files (and associated test files) for examples of how to fulfil these goals, but of course, your own code has to be different from the starter files.

Note: none of these three required functions may have any parameters, although your custom function(s) can have whatever parameters they like.

Mixed Melody

To complete this task, you have to define a mixedMelody function which has no parameters and which mixes together some of the melody segments you created with one or more of the provided melody segments from the cheeryMelody.py and drumsMelody.py files.

These melody function examples provide a demonstration of what your melody functions could sound like, although the exact pitches, volumes, and instruments used are up to you.

Specifically:

You must call at least one Intro, at least two Refrain, and at least one Ending function, and you must call at least two different Refrain functions. You may of course call other functions, and if you want you can get creative with the use of functions like rewind so that the segments overlap instead of just playing in sequence.

This mixedMelody example demonstrates what the melody could sound like by mixing together some of the provided segments with some novel segments.

Extra Requirements

As usual, there are a few rules you must follow throughout:

  1. Each function you define must include a docstring.
  2. You should not waste fruit and you should not waste boxes. "Wasting fruit" means calling a fruitful function but ignoring the result. "Wasting boxes" means storing the result of a non-fruitful function (which will always be None) in a variable (a.k.a., box).
  3. You should not define any functions inside of other functions (this isn't a useful thing to do anyhow).

Examples

Demonstration of melodyIntro, melodyRefrain, and melodyEnding

These examples illustrate how the different melody part functions might sound (the specifics are up to you!). Note that we print the pitch and volume before and after each to show that they are the same. The last example demonstrates how things sound when multiple functions are called one after the other.

In []:
print("Starting pitch is:", round(currentPitch(), 2)) print("Starting volume is:", str(round(100 * currentVolume())) + '%') melodyIntro() printTrack() playTrack() print("Ending pitch is:", round(currentPitch(), 2)) print("Ending volume is:", str(round(100 * currentVolume())) + '%')
Prints
Starting pitch is: 261.63 Starting volume is: 60% a 0.5s keyboard note at C4 (60% vol) and a 0.25s rest at 0.75s a 0.5s keyboard note at C4 (60% vol) at 0.75s a 0.5s keyboard note at G4 (27% vol) at 1.25s a 0.25s rest at 1.5s a 0.5s keyboard note at C4 (60% vol) at 1.5s a 0.5s keyboard note at E4 (27% vol) Ending pitch is: 261.63 Ending volume is: 60%
Audio In []:
# Set up a higher pitch and quieter volume to start with setPitch(G4) setVolume(0.4) print("Starting pitch is:", round(currentPitch(), 2)) print("Starting volume is:", str(round(100 * currentVolume())) + '%') melodyRefrain() printTrack() playTrack() print("Ending pitch is:", round(currentPitch(), 2)) print("Ending volume is:", str(round(100 * currentVolume())) + '%')
Prints
Starting pitch is: 392.01 Starting volume is: 40% at 0s a 0.5s keyboard note at F4 (40% vol) at 0s a 0.5s keyboard note at A4 (18% vol) at 0.5s a 0.25s rest at 0.75s a 0.5s keyboard note at Eb4 (40% vol) at 0.75s a 0.5s keyboard note at Bb4 (18% vol) at 1.25s a 0.25s rest at 1.5s a 0.5s keyboard note at G4 (40% vol) at 1.5s a 0.5s keyboard note at Bb4 (18% vol) Ending pitch is: 392.01 Ending volume is: 40%
Audio In []:
print("Starting pitch is:", round(currentPitch(), 2)) print("Starting volume is:", str(round(100 * currentVolume())) + '%') melodyEnding() printTrack() playTrack() print("Ending pitch is:", round(currentPitch(), 2)) print("Ending volume is:", str(round(100 * currentVolume())) + '%')
Prints
Starting pitch is: 261.63 Starting volume is: 60% at 0s a 0.5s keyboard note at C4 (60% vol) at 0s a 0.5s keyboard note at G4 (27% vol) at 0.5s a 0.25s rest at 0.75s a 0.5s keyboard note at C4 (60% vol) at 0.75s a 0.5s keyboard note at Eb4 (27% vol) at 1.25s a 0.25s rest at 1.5s a 0.5s keyboard note at C4 (60% vol) at 1.5s a 0.5s keyboard note at E4 (27% vol) Ending pitch is: 261.63 Ending volume is: 60%
Audio In []:
print("Starting pitch is:", round(currentPitch(), 2)) print("Starting volume is:", str(round(100 * currentVolume())) + '%') melodyIntro() melodyRefrain() melodyEnding() printTrack() playTrack() print("Ending pitch is:", round(currentPitch(), 2)) print("Ending volume is:", str(round(100 * currentVolume())) + '%')
Prints
Starting pitch is: 261.63 Starting volume is: 60% a 0.5s keyboard note at C4 (60% vol) and a 0.25s rest at 0.75s a 0.5s keyboard note at C4 (60% vol) at 0.75s a 0.5s keyboard note at G4 (27% vol) at 1.25s a 0.25s rest at 1.5s a 0.5s keyboard note at C4 (60% vol) at 1.5s a 0.5s keyboard note at E4 (27% vol) at 2s a 0.5s keyboard note at Bb3 (60% vol) at 2s a 0.5s keyboard note at D4 (27% vol) at 2.5s a 0.25s rest at 2.75s a 0.5s keyboard note at Ab3 (60% vol) at 2.75s a 0.5s keyboard note at Eb4 (27% vol) at 3.25s a 0.25s rest at 3.5s a 0.5s keyboard note at C4 (60% vol) at 3.5s a 0.5s keyboard note at Eb4 (27% vol) at 4s a 0.5s keyboard note at C4 (60% vol) at 4s a 0.5s keyboard note at G4 (27% vol) at 4.5s a 0.25s rest at 4.75s a 0.5s keyboard note at C4 (60% vol) at 4.75s a 0.5s keyboard note at Eb4 (27% vol) at 5.25s a 0.25s rest at 5.5s a 0.5s keyboard note at C4 (60% vol) at 5.5s a 0.5s keyboard note at E4 (27% vol) Ending pitch is: 261.63 Ending volume is: 60%
Audio

Demonstration of the mixedMelody function

This example shows what mixedMelody could sound like. Note from the printed messages that the pitch and volume do not change from beginning to end, even though they do change during the melody.

In []:
print("Starting pitch is:", round(currentPitch(), 2)) print("Starting volume is:", str(round(100 * currentVolume())) + '%') mixedMelody() printTrack() playTrack() print("Ending pitch is:", round(currentPitch(), 2)) print("Ending volume is:", str(round(100 * currentVolume())) + '%')
Prints
Starting pitch is: 261.63 Starting volume is: 60% a 0.25s keyboard note at C4 (27% vol) and a 0.25s rest and a 0.25s keyboard note at C4 (27% vol) and a 0.25s rest and a 0.25s keyboard note at C4 (40% vol) and a 0.25s keyboard note at D4 (60% vol) at 1.5s a 0.5s keyboard note at C4 (60% vol) at 1.5s a 0.5s keyboard note at E4 (18% vol) at 2s a 0.5s keyboard note at Bb3 (60% vol) at 2s a 0.5s keyboard note at D4 (27% vol) at 2.5s a 0.25s rest at 2.75s a 0.5s keyboard note at Ab3 (60% vol) at 2.75s a 0.5s keyboard note at Eb4 (27% vol) at 3.25s a 0.25s rest at 3.5s a 0.5s keyboard note at C4 (60% vol) at 3.5s a 0.5s keyboard note at Eb4 (27% vol) at 4s a 0.25s keyboard note at C4 (60% vol) at 4s a 0.125s snare beat (18% vol) at 4.25s a 0.25s keyboard note at A3 (60% vol) at 4.25s a 0.125s snare beat (18% vol) at 4.5s a 0.25s keyboard note at F3 (60% vol) at 4.5s a 0.125s snare beat (18% vol) at 4.75s a 0.25s keyboard note at C4 (60% vol) at 4.75s a 0.125s snare beat (18% vol) at 5s a 0.25s keyboard note at C4 (60% vol) and a 0.25s keyboard note at E4 (60% vol) and a 0.25s keyboard note at G4 (60% vol) and a 0.25s keyboard note at E4 (60% vol) and a 0.25s keyboard note at C4 (60% vol) and a 0.25s keyboard note at E4 (60% vol) at 6.5s a 0.5s keyboard note at D4 (60% vol) at 6.5s a 0.5s keyboard note at A4 (18% vol) at 7s a 0.5s keyboard note at C4 (60% vol) at 7s a 0.5s keyboard note at G4 (27% vol) at 7.5s a 0.25s rest at 7.75s a 0.5s keyboard note at C4 (60% vol) at 7.75s a 0.5s keyboard note at Eb4 (27% vol) at 8.25s a 0.25s rest at 8.5s a 0.5s keyboard note at C4 (60% vol) at 8.5s a 0.5s keyboard note at E4 (27% vol) Ending pitch is: 261.63 Ending volume is: 60%
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 melodyIntro returns to original pitch and volume (test 1/1)
We will check the current pitch and volume values before and after melodyIntro is called. Both pitch and volume must return to their original values.
 
unknown melodyIntro returns to original pitch and volume (test 1/2)
We will check the current pitch and volume values before and after melodyIntro is called. Both pitch and volume must return to their original values.
 
unknown melodyIntro returns to original pitch and volume (test 2/2)
We will check the current pitch and volume values before and after melodyIntro is called. Both pitch and volume must return to their original values.
 
unknown melodyRefrain returns to original pitch and volume (test 1/1)
We will check the current pitch and volume values before and after melodyRefrain is called. Both pitch and volume must return to their original values.
 
unknown melodyRefrain returns to original pitch and volume (test 1/2)
We will check the current pitch and volume values before and after melodyRefrain is called. Both pitch and volume must return to their original values.
 
unknown melodyRefrain returns to original pitch and volume (test 2/2)
We will check the current pitch and volume values before and after melodyRefrain is called. Both pitch and volume must return to their original values.
 
unknown melodyEnding returns to original pitch and volume (test 1/1)
We will check the current pitch and volume values before and after melodyEnding is called. Both pitch and volume must return to their original values.
 
unknown melodyEnding returns to original pitch and volume (test 1/2)
We will check the current pitch and volume values before and after melodyEnding is called. Both pitch and volume must return to their original values.
 
unknown melodyEnding returns to original pitch and volume (test 2/2)
We will check the current pitch and volume values before and after melodyEnding is called. Both pitch and volume must return to their original values.
 
unknown Define melodyIntro with 0 parameters
Use def to define melodyIntro with 0 parameters
 
unknown Use at least two different pitch- or volume-changing functions from the synth module.
Within the definition of melodyIntro with 0 parameters, use at least two different pitch- or volume-changing functions from the following list: climbUp, climbDown, halfStepUp, halfStepDown, quieter, louder
 
unknown Call addNote or addBeat
Within the definition of melodyIntro with 0 parameters, call addBeat or addNote in at least 2 places.
 
unknown Define melodyRefrain with 0 parameters
Use def to define melodyRefrain with 0 parameters
 
unknown Use at least two different pitch- or volume-changing functions from the synth module.
Within the definition of melodyRefrain with 0 parameters, use at least two different pitch- or volume-changing functions from the following list: climbUp, climbDown, halfStepUp, halfStepDown, quieter, louder
 
unknown Call addNote or addBeat
Within the definition of melodyRefrain with 0 parameters, call addBeat or addNote in at least 2 places.
 
unknown Define melodyRefrain with 0 parameters
Use def to define melodyRefrain with 0 parameters
 
unknown Call at least one custom function.
Within the definition of melodyRefrain with 0 parameters, your code must call a custom function, and that function must add at least one beat or note.
 
unknown Call addNote or addBeat
Within the call to a custom function within the definition of melodyRefrain with 0 parameters, call addBeat or addNote in at least one place.
 
unknown Use rewind
Within the definition of melodyRefrain with 0 parameters, either melodyRefrain or a custom function that it calls must use rewind in at least one place.
 
unknown Define melodyEnding with 0 parameters
Use def to define melodyEnding with 0 parameters
 
unknown Use at least two different pitch- or volume-changing functions from the synth module.
Within the definition of melodyEnding with 0 parameters, use at least two different pitch- or volume-changing functions from the following list: climbUp, climbDown, halfStepUp, halfStepDown, quieter, louder
 
unknown Call addNote or addBeat
Within the definition of melodyEnding with 0 parameters, call addBeat or addNote in at least 2 places.
 
unknown Define mixedMelody with 0 parameters
Use def to define mixedMelody with 0 parameters
 
unknown Use at least one intro function.
Within the definition of mixedMelody with 0 parameters, use at least one of melodyIntro, cheeryIntro, or drumsIntro.
 
unknown Use at least two different refrain functions.
Within the definition of mixedMelody with 0 parameters, use at least two of melodyRefrain, cheeryRefrain, or drumsRefrain.
 
unknown Use at least one ending function.
Within the definition of mixedMelody with 0 parameters, use at least one of melodyEnding, cheeryEnding, or drumsEnding.