Skip to content

TonalContext

A TonalContext provides a context against which to evaluate the position and behaviour of notes “in” a key or mode. It exposes the following public fields:

tonic: NamedTuple # with fields letter: str, accidental: int, chroma: int
mode: int

Since tonic is a named tuple, its fields are accessed with ordinary attribute syntax: context.tonic.letter, context.tonic.chroma.

TonalContext(chroma: int, mode: int)

You can create a TonalContext directly via the class constructor, from the pitch chroma of its tonic degree, and a “mode number” using the following table:

Lydian0
Ionian1
Mixolydian2
Dorian3
Aeolian4
Phrygian5
Locrian6
context = TonalContext(2, 1) # D major
p = SPN.to_pitch("F4")
p.snap_to(context) # F#4
TonalContext.from_strings(tonic: str, mode: str) -> TonalContext

The more intuitive way to initialise a TonalContext. Takes the name of the tonic pitch class and the name of the mode as strings. Can be “major” or “minor”, or a traditional modal name like “dorian” or “ionian”. Case-insensitive. Raises a ValueError if either string is invalid.

context = TonalContext.from_strings("G", "minor")
p = SPN.to_pitch("B4")
p.snap_to(context) # Bb4

Most of TonalContext’s methods are usually more conveniently accessed from the Pitch vectors they act on rather than the class itself, but are available nonetheless. TonalContext.degree_chroma is only available as a method directly on a TonalContext instance, however.

TonalContext.degree_number(p: Pitch) -> int

Returns the scale degree (0-indexed, such that the tonic is 0) of the passed in Pitch vector in the current TonalContext.

context = TonalContext.from_strings("C", "major")
p = SPN.to_pitch("C4")
context.degree_number(p) # 0
p = SPN.to_pitch("D4")
context.degree_number(p) # 1
p = SPN.to_pitch("D#4")
context.degree_number(p) # still 1 (just an altered variant)
TonalContext.degree_alteration(p: Pitch) -> int

Returns the scale degree alteration represented by a Pitch in the current TonalContext, e.g. C# is a raised note in the key of C major.

  • 0 represents a diatonic degree.
  • +1 and -1 represent raised and lowered degrees respectively.
  • +2 and -2 represent degrees too sharp or too flat to belong in a given TonalContext.
context = TonalContext.from_strings("G", "minor")
p = SPN.to_pitch("Bb4")
context.degree_alteration(p) # 0, Bb is diatonic in G minor
p = SPN.to_pitch("B4")
context.degree_alteration(p) # 1, B is raised in G minor
p = SPN.to_pitch("Bbb4")
context.degree_alteration(p) # -2, Bbb is too flat for this context
TonalContext.degree_chroma(degree: int, alteration: int = 0) -> int

Produces the chroma (signed distance from C measured in perfect 5ths) of the variant of the passed-in scale degree (0-indexed so the tonic is 0) that matches the specified alteration (diatonic if unspecified) with respect to the TonalContext.

context = TonalContext.from_strings("G", "minor")
context.degree_chroma(0) # 1, the chroma of G
context.degree_chroma(1) # 3, the chroma of A
context.degree_chroma(2) # -2, the chroma of Bb
context.degree_chroma(3) # 0, the chroma of C
context.degree_chroma(3, 1) # 7, the chroma of C#
TonalContext.snap_diatonic(p: Pitch) -> Pitch

Snaps the passed-in Pitch vector to the diatonic position for that letter-name in the current TonalContext. Returns the result as a new Pitch:

context = TonalContext.from_strings("C", "major")
p = SPN.to_pitch("F#4")
p = context.snap_diatonic(p) # p now points to F4