Pitches

This module introduces the concept of musical pitches.

In the western art music tradition, musical notes or pitches are represented by letters of the alphabet. We use the letters A through G, and then begin with A again. In Python, we can use a list to represent these letters in order:

pitch_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

If we want to access a particular letter, we can specify its position within the list using brackets. (Remember, we always count from zero in Python). For example:

pitch_list[2]
> 'c'

Let’s write a simple function that allows us to move through our list of pitch letter names:

def move_note():
 pitch_list = ["a", "b", "c", "d", "e", "f", "g"]
 index = 2
 while index >= 0:
  print('current note:',pitch_list[index])
  direction = input('+ or -: ')
  if direction == '+':
   index = index + 1
  if direction == '-':
   index = index - 1

First, we define our list within the function. Then we set a starting point of index number two, which corresponds to the note ‘c.’ Next, we want our function to keep running while we move up or down in the list, so we need to use a loop. I’ve chosen a while loop that remains active as long as the index value is at least zero–the minimum index value in any list.

Within this loop, we first print the current note, then ask for user input using the input() function. Depending on what the user enters, it will change the index value. If they type ‘+’, we go up one note; if they type ‘-‘, we go down one note.

Let’s give this a try. First, call the function, then type + or – (and hit enter) to move up and down the list:

move_note()

> current note: c
> + or -: +
> current note: d
> + or -: -
> current note: c
> + or -: -
> current note: b
> + or -: 

At first, it works just as expected. But once we try to go below ‘a’ or above ‘g’, the function will either shut down or we’ll see an error message that says “list index out of range.” In other words, our program doesn’t understand that we need to be able to loop back to either: the beginning of our list if we go above the last index value (6); or, the end of our list if we go below the first index value (0).

Luckily, we just have to make a couple of tweaks. Here is our new and improved function:

def move_note():
 pitch_list = ["a", "b", "c", "d", "e", "f", "g"]
 index = 2
 while index >= 0:
  print('current note:',pitch_list[index % 7])
  direction = input('+ or -: ')
  if direction == '+':
   index = index + 1
  if direction == '-':
   index = index - 1
   if index == -1:
    index = 6

You’ll notice that we’ve just made a couple of changes, each of which addresses one of our two special cases. The first change is using “index % 7” instead of just “index” as the index value for our list. This modulo operator means that as our index variable increases past 6, we will always divide that value by 7 to get the relevant index for the list.

The second change is the addition of an extra if statement nested within the second directional if statement. This if statement identifies if our index value ever drops below 0, and simply bumps it back up to 6. In other words, it loops it back to the “end” of the list.

If you try running the function again, you’ll now see that it works as expected–we can go up or down any number of times and the program continues to function.

Extensions

  1. Each span between notes represented by the same letter (for example, A to A) is known as an octave. How could you keep track of and display the current octave for the user?
  2. How would you integrate accidentals (sharps and flats) into a program like this?