Skip to content

Pitch

Meantonal stores pitches as two-dimensional vectors. C₋₁ is defined to be (0,0)(0, 0) to conform to 0 representing the MIDI value for the same pitch.

  • The first component of a pitch’s vector represents increments in whole steps.
  • The second component represents increments in diatonic semitones (that is, from C to D♭, not from C to C♯).

Internally, the Pitch type is defined as a simple struct:

typedef struct {
int w;
int h;
} Pitch;

To help understand what this means, let’s see how we would represent the pitches of a C major scale from C₋₁ to C₀, given the familiar formula of WWHWWWH:

C₋₁D₋₁E₋₁F₋₁G₋₁A₋₁B₋₁C₀
(0,0)(0,0)(1,0)(1,0)(2,0)(2,0)(2,1)(2,1)(3,1)(3,1)(4,1)(4,1)(5,1)(5,1)(5,2)(5,2)

Or, arranged on the coordinate plane:

C0\sf{C}_0
F1\sf{F}_{-1}G1\sf{G}_{-1}A1\sf{A}_{-1}B1\sf{B}_{-1}
C1\sf{C}_{-1}D1\sf{D}_{-1}E1\sf{E}_{-1}

Pitches can therefore be thought of as lying on an infinite two-dimensional grid, of which an arbitrary portion is represented below as illustration.

D♭⁴₄E♭⁴₄F♭³₄G♭³₄A♭³₄B♭³₄C♭♭₅D♭♭₅E♭♭₅
C♭³₄D♭³₄E♭³₄F♭♭₄G♭♭₄A♭♭₄B♭♭₄C♭₅D♭₅
B♭³₃C♭♭₄D♭♭₄E♭♭₄F♭₄G♭₄A♭₄B♭₄C₅
A♭♭₃B♭♭₃C♭₄D♭₄E♭₄F₄G₄A₄B₄
G♭₃A♭₃B♭₃C₄D₄E₄F♯₄G♯₄A♯₄
F₃G₃A₃B₃C♯₄D♯₄E♯₄F♯♯₄G♯♯₄
E₃F♯₃G♯₃A♯₃B♯₃C♯♯₄D♯♯₄E♯♯₄F♯³₄
D♯₃E♯₃F♯♯₃G♯♯₃A♯♯₃B♯♯₃C♯³₄D♯³₄E♯³₄
C♯♯₃D♯♯₃E♯♯₃F♯³₃G♯³₃A♯³₃B♯³₃C♯⁴₄D♯⁴₄

In practice, Western music only generally uses accidentals up to double sharps and flats, but higher-order accidentals come for free as a result of Meantonal’s vector representation and can be useful for people working with alternative tuning systems, or in various algorithms for generating musical content that will eventually be enharmonically respelled for legibility.

Although the abstract vector space of whole steps and half steps shown above is theoretically infinite, Meantonal represents these coordinates with signed integers.

Just how much range is this, though? Do we cover as many octaves as MIDI at least?

To put things in perspective: (125,50)(-125,-50) and (125,50)(125, 50) represent C₋₂₆ and C₂₄ and would be well-represented by the Pitch type even if it were capped at 8-bit integers. That’s eome fifty octaves of range, or from roughly 240nHz to 264MHz.

Suffice to say: you’re not going to run out of pitches.

Scientific pitch notation (SPN) is a common system for representing pitches in text. It consists of essentially three components:

LetterAccidentalOctave
A5

Meantonal constructs a pitch vector with the following formula:

L+A(1,1)+O(5,2)L + A(1, -1) + O(5, 2)

Where LL represents the initial letter vector, selected from this table:

CDEFGAB
(0,0)(0,0)(1,0)(1,0)(2,0)(2,0)(2,1)(2,1)(3,1)(3,1)(4,1)(4,1)(5,1)(5,1)

AA represents the accidental, whose values are assigned as follows:

AccidentalA
etc.
♯♯2
1
0
-1
♭♭-2
etc.

OO represents the octave. Since we want (0,0)(0, 0) to represent C₋₁, the value of OO is greater than the octave component of a pitch’s SPN value by 1.

Putting it all together, the pitch vector for A♭5 would be:

(4,1)+(1)(1,1)+6(5,2)=(4,1)+(1,1)+(30,12)=(33,14)(4,1) + (-1)(1, -1) + 6(5, 2) = (4, 1) + (-1, 1) + (30, 12) = (33, 14)

Parsing ABC and LilyPond works much the same way.