Instructions for scales

(produced at 12:10 p.m. UTC on 2024-02-27)

This task is part of project07 which is due at 23:00 EDT on 2024-03-15.

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

This project is very similar the circles task which uses turtle to generate images instead of wavesynth to generate audio. You only have to do one of the two (but you must do audioToolkit).

For this task, you will use for loops with the wavesynth.py library to create musical scales: sequences of notes with ascending pitches.

Tools

For this task, you will only need the addNote, halfStepUp, and climbUp functions from wavesynth.

For testing, you will also need to use at least one of printTrack, saveTrack, and/or playTrack, although we've supplied testing code for you. To use playTrack, you will have to install the simpleaudio module (in the Thonny "Tools" menu select "Manage Packages" and then search for simpleaudio and click "Install.")

If you are on Windows and you're unable to install simpleaudio, see the audioToolkit task instructions which include one possible fix. But note that simpleaudio is not required: you can always just open saved .wav files manually to hear what is being produced.

Overview

For this task, you will create a new Python file named scales.py. Your file should begin with this header, which you should fill out (note that as usual you must document each function you create):

"""
Authors:
Consulted:
Date:
Purpose: scales task: create runs of ascending notes.
"""

You will needs to import wavesynth by putting the following line at the beginning of your code:

from wavesynth import *

You will use functions from wavesynth.py to modify pitch values in order to construct sequences of notes with rising pitches. There are four parts to this task:

  • In Part A you will create a variable-length scale that uses climbUp.

  • In Part B you will create a variable-length scale using climbUp in which every other note is half as long as the others.

  • In Part C you will create a variable-length arpeggio, in which there are a different number of half-steps between subsequent notes, specified using a list of integers.

  • In Part D you will create your own custom pattern of notes by using one of the previous functions inside of a loop.

Testing

In this task, you will create multiple functions, and you should test each of them. We've included a test_scales.py testing file that you can run to test your functions (it will skip functions you haven't defined yet). We've also created a play_scales.py file that you can use to play your scales to hear them; in that file you should comment in additional tests as you go.

Part A: scale

The scale function accepts two parameters: the first controls the total duration of the scale, and the second controls the number of notes in the scale. It must add an ascending sequence of notes to the current track, starting at the current pitch, and increasing by one rung (using the climbUp function) with each note added. The provided duration for the whole scale must be evenly divided among the notes in the scale. So for example, if the scale duration is 1 second and there are 4 notes, each note's duration will be 0.25 seconds.

These scale examples demonstrate how it should work.

Part B: unevenScale

The unevenScale function must work like scale, but it has 3 parameters: a number of notes, a start duration, and an 'other' duration. Instead of creating notes that all have the same duration, every other note in the scale sequence uses the other duration value. The starting note of the scale always uses the start duration, which means that depending on the number of notes, the top note may use either that value or the other duration.

These unevenScale examples demonstrate how it should work.

Part C: arpeggio

For this last part, you'll create a more flexible function that creates ascending note sequences with variable pitch differences between the notes. The arpeggio function must accept 3 arguments: the first specifies the note duration, the second is a list of pitch differences (integers), and the third specifies the number of cycles, which indicates how many times the pattern of pitch differences should repeat.

arpeggio will add an ascending sequence of notes where the first note starts at the current pitch, the next note is a number of half-steps above that pitch specified by the first value from the list of pitch differences, the third note is a number of half-steps above that pitch specified by the second pitch-difference-list value, and so on. The steps in the pitch-differences list will be repeated as specified by the cycle count (which will always be a positive integer). The total number of notes will be one plus the cycle count times the length of the pitch-differences list.

As shown in the arpeggio examples, if the pitch differences are [3, 4, 5] and the cycle count is 2, the following notes will be added (specified in terms of half-steps above the starting pitch):

+0, +3, +7, +12, +15, +19, +24

Note that the total number of notes in this case is 1 + (2 * 3) = 7.

Notes:

  • There are multiple viable approaches to this problem, including two loops after each other, just one loop, or two loops inside each other.
  • You will use the halfStepUp function to change pitches; note that it accepts a parameter that determines the number of steps up to take, and that it will accept negative numbers to step down, so you can simply pass the pitch difference values directly to halfStepUp to change pitches.
  • Unlike the previous two parts, the first parameter to arpeggio directly determines the length of each note it adds, so you don't need to compute a note length based on a total duration.

Part D: scalesDesign

Now that you've created functions for several different kinds of note sequences, your final task is to create some more complicated pattern using these functions. This example demonstrates one such pattern that could be created, using a loop and the rewind function to create multiple overlapping scales. But there are no restrictions on the pattern that your function creates. The only requirements for your scalesDesign function are:

  1. It must have zero parameters, and when called, it must run without crashing, and complete within about 10 seconds.
  2. In the code for scalesDesign, you must use at least one loop, and in that loop, you must call at least one of the scale, unevenScale, or arpeggio functions.

Examples

scale examples

These examples show what should be printed and what audio should be produced when scale is called, followed by printTrack and playTrack. Note that the exact pitches used depend on the current pitch when the function is called.

In []:
setPitch(C4) scale(0.75, 3) printTrack() playTrack()
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)
Audio In []:
setPitch(B2) scale(0.64, 8) printTrack() playTrack()
Prints
a 0.08s keyboard note at B2 (60% vol) and a 0.08s keyboard note at C3 (60% vol) and a 0.08s keyboard note at D3 (60% vol) and a 0.08s keyboard note at E3 (60% vol) and a 0.08s keyboard note at F3 (60% vol) and a 0.08s keyboard note at G3 (60% vol) and a 0.08s keyboard note at A3 (60% vol) and a 0.08s keyboard note at B3 (60% vol)
Audio

unevenScale examples

These examples show what should be printed and what audio should be produced when unevenScale is called, followed by printTrack and playTrack. Note that the exact pitches used depend on the current pitch when the function is called.

In []:
setPitch(C4) unevenScale(3, 0.75, 0.25) printTrack() playTrack()
Prints
a 0.75s keyboard note at C4 (60% vol) and a 0.25s keyboard note at D4 (60% vol) and a 0.75s keyboard note at E4 (60% vol)
Audio In []:
setPitch(E2) unevenScale(8, 0.4, 0.5) printTrack() playTrack()
Prints
a 0.4s keyboard note at E2 (60% vol) and a 0.5s keyboard note at F2 (60% vol) and a 0.4s keyboard note at G2 (60% vol) and a 0.5s keyboard note at A2 (60% vol) and a 0.4s keyboard note at B2 (60% vol) and a 0.5s keyboard note at C3 (60% vol) and a 0.4s keyboard note at D3 (60% vol) and a 0.5s keyboard note at E3 (60% vol)
Audio