Numerical Representation of Pitch


A number of years ago, I started working on a Python library for music theory and composition called Sebastian and one of the first implementation decisions I needed to make was how to represent pitch. Assuming one allows for double-flats and double-sharps, there are 35 note names. What I was looking for was a way to represent these 35 note names in a way that was consistent with the relationships between them.

I ended up deciding to use the set of integers with D as 0 and each successor being a 5th higher. So A would be +1, E +2, G -1, Eb -5, F# +4 and so on.

This turns out to work quite nicely. Given one note, you can find the tone above/below by adding/subtracting 2 and the semitone (different letter) above/below by subtracting/adding 5. To augment/diminish (same letter) you can add/subtract 7.

You can determine if two notes are enharmonic by testing

(abs(val1 - val2) % 12) == 0

You generate the textual note name from this integer with:

modifiers = ((val + 3) - ((val + 3) % 7)) / 7 if modifiers == 0: m_name = "" elif modifiers == 1: m_name = "#" elif modifiers > 1: m_name = "x" * (modifiers - 1) else: # m < 0 m_name = "b" * -modifiers return "DAEBFCG"[val % 7] + m_name

and the reverse with

letter = name[0] base = "FCGDAEB".find(letter) - 3 if base == -4: raise ValueError mod = name[1:] if mod == "": m = 0 elif mod == "#": m = 1 elif mod == "x" * len(mod): m = len(mod) + 1 elif mod == "b" * len(mod): m = -len(mod) else: raise ValueError return base + m * 7

While it's true that moving the origin to F would eliminate some of those -3s and +3s, new ones would need to be introduced, so there's no really clear winner between an origin at D versus an origin at F.

Scales are easy to generate. The pattern for a major scale is [0, 2, 4, -1, 1, 3, 5] and so you can generate the scale for a particular tonic with something like

[tonic + i for i in [0, 2, 4, -1, 1, 3, 5]]

Another advantage of the system is it can be extended to 19-et and other tuning systems. I haven't given much thought to whether it's useful for tunings without a constant frequency ratio for the 5th, though.

I also haven't yet investigated how this system is inferior to Hewlett's base-40 system.

UPDATE: Okay, I've finally grokked the functional difference between Hewlett's system and mine. Mine can incorporate an infinite number of note names (triple flats, quadruple sharps, you name it) but it cannot express intervals of an octave or more. Hewlett's base-40 system can handle intervals of octaves or above but cannot, without change, handle more than the 35 note names of 12-tone chromatic music. My system (and others like it) require two numbers to handle more than an octave. Hewlett traded off infinite note-naming capability for the ability to include octave in a single number.

The original post was in the categories: python music_theory sebastian but I'm still in the process of migrating categories over.

The original post had 6 comments I'm in the process of migrating over.