Instructions for mixedUpMelodies

(produced at 02:27 a.m. UTC on 2024-09-10)

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

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. 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 the original pitch, but they must return to it, allowing us to mix multiple melodies together without interference.

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