Instructions for recursiveScales

(produced at 10:49 a.m. UTC on 2024-04-15)

This task is part of project10 which is due at 23:00 EDT on 2024-04-23.

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 recursiveScales.py
(you will create this file from scratch)

This task and the recursiveCircles task are very similar. This task is based on audio using the wavesynth library, while the recursive circles task is based on turtle graphics instead. You may choose to do either task, but you do not need to do both.

In this task, you will create a file named recursiveScales.py and write functions scale, unevenScale, and rungsListMelody within it, the first two of which which are similar to the functions with the same names from the earlier "scales" task. However, for this task, you are not allowed to use any loops, and must use recursion instead.

If you didn't do the scale task before, you should review that material before starting this task, and you may need to familiarize yourself with the wavesynth library. It may be easier to do the recursiveCircles task instead of this one in that case.

Part A: scale

This function works like the scale function from the earlier task of the same name, and takes equivalent parameters:

  • scaleDuration determines the duration of the entire scale.
  • notesUp determines the number of notes in the scale.

It should behave exactly like scale from the earlier task: it must add a number of notes to the current track, each one step above the last. climbUp must be used to increase the pitch. The number of notes added is determined by the second parameter, and the duration of each note is the same, so the total scale duration is split evenly between the notes. For example, if there are 4 notes and the total duration is 1 second, each note will be 1/4 second long.

Whereas in the previous task this problem was solved using a loop, in this task, you may not use any loops and you must use recursion. As an extra goal, you should only include a single call to addNote and you should only include a single recursive call.

Hint: Each recursive function call frame needs to add just one note.

These scale examples demonstrate what it should print and what the results should sound like.

Part B: unevenScale

This function works exactly like unevenScale from the non-recursive scale task, taking equivalent parameters:

  • notesUp determines the number of notes in the scale.
  • startLength determines the length of the first note in the scale, and every odd-numbered note after that.
  • otherLength determines the length of the even-numbered notes in the scale (every other note starting from the second one).

As before, notes are added stepping up one step at a time using climbUp, but now every other note has a different duration.

Just like in the previous function, you may not use any loops and you must use recursion. Also as above, as extra goals, you should use addNote in only one place, and you should also only include a single recursive call.

These unevenScale examples demonstrate what the printed output and audio should be.

Part C: rungsListMelody

This function is a new function: given a total duration and a list of rung values, it must add notes to the current track which follow the pattern of climbing up and/or down that is provided. Specifically, it will add one note at the current pitch, even if the rungs list is empty. If the rungs list is not empty, it will contain positive and negative integers, and subsequent notes should be added climbing up or down that many rungs in pitch. Note that it must use the climbUp function, which can accept an argument to specify how many steps to take, and negative values will cause it to climb down, so you can simply pass the numbers from the rungs list directly to the climbUp function. As a concrete example, if the rungs list is [3, -2, 1] then the notes added would be:

  • One note at the starting pitch.
  • One note 3 rungs above the starting pitch.
  • One note one rung above the starting pitch (i.e., two rungs below the pitch of the note before).
  • One note two rungs above the starting pitch (i.e., one rung above the previous note).

Just like turtle keeps track of the current drawing position, wavesynth keeps track of the "current pitch" which is what climbUp changes and what addNote uses to determine the pitch of the note it creates.

As with the other functions in this task, you may not use loops and you must use recursion. Also as before, as extra goals, you should call addNote in only one place and you should include only one recursive call.

Hint: The total number of notes in the melody is always one more than the number of intervals in the rungs list, because the rungs represent pitch changes in between notes.

These rungsListMelody examples demonstrate what the printed output and audio should be.

Notes

Examples

scale examples

These examples demonstrate what the printed output and audio results of the scale function should be. Note that you must call saveTrack and then open the specified file with an audio player to hear the notes added, and if you call multiple functions that add notes without calling eraseTrack in between, the notes will all pile into the same track. You can also call playTrack to have Python play the sound directly, but you will need to use the package manager to install the simpleaudio package for that to work. Note that each example below uses setPitch before calling scale, since scale starts from whatever the current pitch happens to be.

In []:
setPitch(C4) scale(2, 8) printTrack()
Prints
a 0.25s keyboard note at C4 (60% vol) and a 0.25s keyboard note at D4 (60% vol) and a 0.25s keyboard note at E4 (60% vol) and a 0.25s keyboard note at F4 (60% vol) and a 0.25s keyboard note at G4 (60% vol) and a 0.25s keyboard note at A4 (60% vol) and a 0.25s keyboard note at B4 (60% vol) and a 0.25s keyboard note at C5 (60% vol)
Audio In []:
setPitch(C4) scale(1.2, 5) printTrack()
Prints
a 0.24s keyboard note at C4 (60% vol) and a 0.24s keyboard note at D4 (60% vol) and a 0.24s keyboard note at E4 (60% vol) and a 0.24s keyboard note at F4 (60% vol) and a 0.24s keyboard note at G4 (60% vol)
Audio In []:
setPitch(A3) scale(1.6, 4) printTrack()
Prints
a 0.4s keyboard note at A3 (60% vol) and a 0.4s keyboard note at B3 (60% vol) and a 0.4s keyboard note at C4 (60% vol) and a 0.4s keyboard note at D4 (60% vol)
Audio

unevenScale examples

These examples demonstrate what the printed output and audio results of unevenScale should be. Once again, setPitch is used beforehand to determine the starting pitch.

In []:
setPitch(C4) unevenScale(5, 0.3, 0.15) printTrack()
Prints
a 0.3s keyboard note at C4 (60% vol) and a 0.15s keyboard note at D4 (60% vol) and a 0.3s keyboard note at E4 (60% vol) and a 0.15s keyboard note at F4 (60% vol) and a 0.3s keyboard note at G4 (60% vol)
Audio In []:
setPitch(C4) unevenScale(6, 0.4, 0.3) printTrack()
Prints
a 0.4s keyboard note at C4 (60% vol) and a 0.3s keyboard note at D4 (60% vol) and a 0.4s keyboard note at E4 (60% vol) and a 0.3s keyboard note at F4 (60% vol) and a 0.4s keyboard note at G4 (60% vol) and a 0.3s keyboard note at A4 (60% vol)
Audio In []:
setPitch(A3) unevenScale(8, 0.2, 0.36) printTrack()
Prints
a 0.2s keyboard note at A3 (60% vol) and a 0.36s keyboard note at B3 (60% vol) and a 0.2s keyboard note at C4 (60% vol) and a 0.36s keyboard note at D4 (60% vol) and a 0.2s keyboard note at E4 (60% vol) and a 0.36s keyboard note at F4 (60% vol) and a 0.2s keyboard note at G4 (60% vol) and a 0.36s keyboard note at A4 (60% vol)
Audio

rungsListMelody examples

These examples demonstrate what the printed output and audio results of rungsListMelody should be. Note that even when the list of steps is empty, a single note is added to the track, taking up the full specified total duration.

In []:
setPitch(C4) rungsListMelody(0.5, []) printTrack()
Prints
a 0.5s keyboard note at C4 (60% vol)
Audio In []:
setPitch(C4) rungsListMelody(1, [3, -2, 1]) printTrack()
Prints
a 0.25s keyboard note at C4 (60% vol) and a 0.25s keyboard note at F4 (60% vol) and a 0.25s keyboard note at D4 (60% vol) and a 0.25s keyboard note at E4 (60% vol)
Audio In []:
setPitch(C4) rungsListMelody(2, [3, -2, 1, -2, 3, -2, 1]) printTrack()
Prints
a 0.25s keyboard note at C4 (60% vol) and a 0.25s keyboard note at F4 (60% vol) and a 0.25s keyboard note at D4 (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 F4 (60% vol) and a 0.25s keyboard note at D4 (60% vol) and a 0.25s keyboard note at E4 (60% vol)
Audio In []:
setPitch(C4) rungsListMelody(3, [2, 2, 1, 2, 2, 1, -3, 2, -3, 1]) printTrack()
Prints
a 0.273s keyboard note at C4 (60% vol) and a 0.273s keyboard note at E4 (60% vol) and a 0.273s keyboard note at G4 (60% vol) and a 0.273s keyboard note at A4 (60% vol) and a 0.273s keyboard note at C5 (60% vol) and a 0.273s keyboard note at E5 (60% vol) and a 0.273s keyboard note at F5 (60% vol) and a 0.273s keyboard note at C5 (60% vol) and a 0.273s keyboard note at E5 (60% vol) and a 0.273s keyboard note at B4 (60% vol) and a 0.273s keyboard note at C5 (60% vol)
Audio

Rubric

Group goals:
 
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 All functions are documented
Each function you define must include a non-empty documentation string as the very first thing in the function.
 
unknown scale must produce the correct note sequence
The notes added to the current track when scale is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown unevenScale must produce the correct note sequence
The notes added to the current track when unevenScale is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown rungsListMelody must produce the correct note sequence
The notes added to the current track when rungsListMelody is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown scale must produce the correct note sequence
The notes added to the current track when scale is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown unevenScale must produce the correct note sequence
The notes added to the current track when unevenScale is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown rungsListMelody must produce the correct note sequence
The notes added to the current track when rungsListMelody is called must match the solution notes in terms of timing, instruments, pitches, and volumes.
 
unknown Define scale with 2 parameters
Use def to define scale with 2 parameters
 
unknown Do not use any kind of loop
Within the definition of scale with 2 parameters, do not use any kind of loop.
 
unknown Use a conditional
Within the definition of scale with 2 parameters, use an if statement (possibly accompanied by an elif or else block) in at least one place.
 
unknown Call climbUp
Within the definition of scale with 2 parameters, call climbUp in at least one place.
 
unknown Call scale
Within the definition of scale with 2 parameters, call scale in at least one place.
 
unknown Define scale with 2 parameters
Use def to define scale with 2 parameters
 
unknown Call scale
Within the definition of scale with 2 parameters, call scale in exactly one place.
 
unknown Call addNote
Within the definition of scale with 2 parameters, call addNote in exactly one place.
 
unknown Define unevenScale with 3 parameters
Use def to define unevenScale with 3 parameters
 
unknown Do not use any kind of loop
Within the definition of unevenScale with 3 parameters, do not use any kind of loop.
 
unknown Use a conditional
Within the definition of unevenScale with 3 parameters, use an if statement (possibly accompanied by an elif or else block) in at least one place.
 
unknown Call climbUp
Within the definition of unevenScale with 3 parameters, call climbUp in at least one place.
 
unknown Call unevenScale
Within the definition of unevenScale with 3 parameters, call unevenScale in at least one place.
 
unknown Define unevenScale with 3 parameters
Use def to define unevenScale with 3 parameters
 
unknown Call unevenScale
Within the definition of unevenScale with 3 parameters, call unevenScale in exactly one place.
 
unknown Call addNote
Within the definition of unevenScale with 3 parameters, call addNote in exactly one place.
 
unknown Define rungsListMelody with 2 parameters
Use def to define rungsListMelody with 2 parameters
 
unknown Do not use any kind of loop
Within the definition of rungsListMelody with 2 parameters, do not use any kind of loop.
 
unknown Use a conditional
Within the definition of rungsListMelody with 2 parameters, use an if statement (possibly accompanied by an elif or else block) in at least one place.
 
unknown Call climbUp
Within the definition of rungsListMelody with 2 parameters, call climbUp in at least one place.
 
unknown Call rungsListMelody
Within the definition of rungsListMelody with 2 parameters, call rungsListMelody in at least one place.
 
unknown Define rungsListMelody with 2 parameters
Use def to define rungsListMelody with 2 parameters
 
unknown Call rungsListMelody
Within the definition of rungsListMelody with 2 parameters, call rungsListMelody in exactly one place.
 
unknown Call addNote
Within the definition of rungsListMelody with 2 parameters, call addNote in exactly one place.