Solving a Pitch Label Problem

Converting scientific pitch notation to piano key number and vice versa

One difficulty that developers may encounter when integrating audio, sound, and/or music into an application is what I call the Pitch Label Problems. These problems arise from the fact that there are many different systems used for labeling pitch and that converting a pitch’s label in one system to its label in another is a process that can be quite difficult for humans to do and even more difficult for humans to translate into code.

There is Helmholtz pitch notation, in which each note, from A through G in both upper and lower case, is labeled using the sub- and super-prime symbols ( ͵ and ′) to denote which octave they are part of.

Helmholtz Pitch Notation

There is scientific pitch notation, which makes use of the traditional upper case note names (A to G), which are followed by numbers showing which octave they are part of.

Scientific Pitch Notation

There are the solfège systems, of which fixed do and movable do are the most popular, in which seven syllables (do, re, mi, fa, sol, la, and ti) are used to label certain pitches.

Fixed Do
Movable Do System

There is the hertz(Hz) approach, in which every pitch is labeled using a number that corresponds to its frequency in hertz.

Hertz Approach

There is also the piano key number approach, in which all 88 keys of the standard piano keyboard (white and black) are assigned a number, starting with 1 and ending with 88.

Piano Key Number Approach

These systems are further complicated by the accepted practice in Western music of using completely different letter names in combination with the sharp symbol (#) and the flat symbol (b) to represent the exact same note. This is referred to as enharmonic equivalency. For example, G#4 and Ab4 are the exact same note, but we use a different letter and sharp/flat to refer to it depending on some rather complicated rules having to do with harmonic context which I won’t explain right now.

Enharmonic Equivalents on the Black Notes

And while all of these systems are the most common approaches for pitch labeling, there are many more, especially when you include non-Western methods of pitch labeling (Hindustani, Carnatic, Arabic musical traditions, Indonesian gamelan, etc.).

The Carnatic System
The Indonesian System

The fact that there are so many different ways to label the exact same sounds means that it can be quite difficult to write code that pertains to music. What might be considered a simple musical conversion for a child who has just started learning music, such as converting C4 in scientific pitch notation to “do” in fixed do solfège, can be a relatively difficult challenge process to represent in code. This process is further complicated by the fact that many of the notes in scientific pitch notation have two different names (e.g. G#4 is the exact same note as Ab4, but we use a different name depending on the context).

I refer to this complicated set of challenges having to do with converting one pitch labeling system into another as the Pitch Label Problems or P.L.P.. I’ve written some JavaScript code to help me solve one of these problems: the conversion of scientific pitch notation into piano key number and vice versa. This code functions as a sort of calculator that quickly tells you what the piano key number equivalent (1 through 88) is of a note in scientific pitch notation (A0 through C8). This code can also perform the same process in reverse. Here is the code:

const fullRange = ["A0", "A#0", "B0", "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", "C8"]function keyToNote(key){
return fullRange[key - 1]
}
function noteToKey(note){
if(note.includes('b')){
const shiftedNote = note.replace('b', '')
return fullRange.indexOf(shiftedNote)
} else {
return fullRange.indexOf(note) + 1
}
}

Let’s go through this code section by section starting with the array that we assign to a constant:

const fullRange = ["A0", "A#0", "B0", "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", "C8"]

fullRange is a constant that we are assigning to an array. The array contains every single note on the standard piano keyboard in scientific pitch notation, with one caveat. The caveat is that we have not used any of the note names with flat symbols (b), only the natural note names and the note names with sharp symbols (#). This is because the note names with flat symbols and the note names with sharp symbols are the exact same piano key number, but they have different names in scientific pitch notation. This is not a relationship that we would normally be able to represent using an array. For example, “A#0” is the exact same note as “Bb0”. Both of these notes are the exact same key on the piano, so they have the exact same piano key number, 2. After defining this array, we have created a function:

function keyToNote(key){
return fullRange[key - 1]
}

This function, keyToNote(key), takes in an argument of a piano key number and converts it into equivalent its scientific pitch notation label. Let’s use the first piano key number as an example. The first piano key number is 1. 1 is equivalent to A0 in scientific pitch notation. so, we will be using 1 as the key parameter here. return fullRange[key-1] would become return fullRange[1–1], which would become return fullRange[0]. return fullRange[0] would return whatever item is at the 0 index of the fullRange array that we have defined. That item is A0. The reason why we need to subtract 1 is because the piano key numbers start at 1 but the index numbers of fullRange start at 0. So, the piano key number will always be 1 number greater than the index of its corresponding note in scientific pitch notation. After the keyToNote(key) function, we have created another function:

function noteToKey(note){
if(note.includes('b')){
const shiftedNote = note.replace('b', '')
return fullRange.indexOf(shiftedNote)
} else {
return fullRange.indexOf(note) + 1
}
}

This function, noteToKey(note), takes in an argument of a scientific pitch notation label and converts it into its equivalent piano key number. Let’s use a scientific pitch notation label with a flat symbol(b) as an example. We can use Bb0. Bb0 (which is the same note as A#0 in our fullRange array) has an equivalent piano key number of 2. The second line of our code if(note.includes(‘b’)){ accounts for any scientific pitch notation label with a flat symbol(b), such as our example of Bb0. We then define a variable shiftedNote and assign it to note.replace(‘b’, ‘’). This removes the flat symbol from the note, which transforms our example of Bb0 into B0. The next line, return fullRange.indexOf(shiftedNote), provides us with the index of shiftedNote in the fullRange array. What is the index of B0, our shiftedNote? It is 2, which is the piano key number that we are looking for. Let’s look at the final section of our code:

} else {
return fullRange.indexOf(note) + 1
}

This section of our code accounts for any scientific pitch notation label without a flat symbol(b). For this section, we wouldn’t be able to use our example of Bb0, because it has a flat symbol. So, let’s use the scientific pitch notation label of A0 as our example. A0 has an equivalent piano key number of 1. return fullRange.indexOf(note) + 1 would first return the index of A0 in our fullRange array. This index would be 0. Is this the correct equivalent piano key number? No, the correct piano key number is 1. This is why we need +1 in our code. If we take the index of 0 and add 1 to it, we get 1, which is the correct piano key number.

Writing this code has made me think about how complicated pitch labeling is in music. There are so many different systems and each system has many different variations, exceptions, and problems. I began to think that the world might be a better place if everyone used one standardized system so humans (and computers) wouldn’t have to constantly run the computations necessary to convert one pitch labeling system into another. This led me to thinking about all of the systems that lack standardization. Some countries use metric and some use imperial. Some countries use the Cyrillic alphabet, some use the Latin alphabet, some use Chinese characters, and so on. How much more efficient could we as a species be if we standardized everything? But then I started to think about what I value more: efficiency or variety? For me, the answer is obviously variety (which is the spice of life, after all). I would much rather live in a world with thousands of different systems, each with its own pros and cons, each with its own lessons to teach us about the human experience. With this perspective in mind, perhaps I should re-consider my naming. The Pitch Label Problems become the Pitch Label Presents. Countless presents from the universe that give us innumerable ways to experience music.

Software engineering student at Flatiron School in New York City

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store