TonalVector

TonalVector()

A tuple of form (d_iatonic, c_hromatic, (o_ctave)), representing either a pitch or interval (or both). TonalVector implements tonal arithmetic with dunder methods, allowing use of standard operators (+, -, =, <, >).

TonalVector is the WSMN implementation of both Tone and Interval:

>>> isinstance(TonalVector((0, 0)), Tone)
True
>>> isinstance(TonalVector((0, 0)), Interval)
True

Attributes

Name Description
__slots__
tonal_system
pitch This TonalVector as a pitch (letter name, accidental, octave, …).
interval This TonalVector as an interval (quality, number, …).
d
c
o The octave designation, for a qualified vector (middle C is octave 0).
has_octave True if this TonalVector carries an octave designation.
fifths_position The position of this TonalVector on the circle (line) of fifths,

Methods

Name Description
__format__ Display form of the Tone, used by str.format and f-strings.
__new__ TonalVector is an immutable value: a tuple, compared by value.
from_string Creates and returns a TonalVector,
from_ly Creates and returns an octave-qualified TonalVector,
__repr__ >>> TonalVector((0,0))
__str__ Returns a string that includes the repr string,
__add__
__sub__
distance Returns the smallest difference between self and x, as an interval
nearest_instance Returns a Tonal Vector that has the same pitch class or interval type as x,
__abs__ Returns the distance, in half-steps, from self to the origin.
__int__ Returns the signed distance, in half-steps, from self to the origin.
__gt__ Returns True if self is higher (in pitch)
__lt__ Returns True if self is lower (in pitch)
transpose Returns a TonalVector transposed by x, in the given direction.
inversion Returns the inversion of self over x.
__eq__ Returns True if self and x are the same (d, c, [o]) values.
__hash__ Hashes as its tuple, so a TonalVector is a set member and a dict key by value.
__call__ Adds another TonalVector, or applies other to this one:
qualify_octave Returns a TonalVector with an octave designation set to octave.
conditional_qualify_octave Returns a TonalVector with an octave designation set to octave,
unqualify_octave Returns a TonalVector without an octave designation.

__format__

__format__(spec: str)

Display form of the Tone, used by str.format and f-strings.

For pitched tones, the format spec names an attribute of the Tone’s PitchRepresentation, defaulting to unicode; unpitched tones fall back to str(). str() and repr() are unaffected, so they remain available as debug forms (use {tone!r} or {tone!s} in a template to get them).

>>> from openmusickit.systems.wsmn.tonal.tonal_vector import TonalVector
>>> from openmusickit.values.tone.silent_tone import SilentTone
>>> Eb = TonalVector((2, 3))
>>> f"{Eb} major"
'E♭ major'
>>> f"{Eb:ascii} major"
'Eb major'
>>> f"{Eb!r}"
'TonalVector((2, 3))'
>>> f"{SilentTone()}"
'SilentTone()'

The spec must name a string attribute of the PitchRepresentation:

>>> f"{Eb:nonsense}"
Traceback (most recent call last):
...
ValueError: ...

__new__

__new__(*args)

TonalVector is an immutable value: a tuple, compared by value.

The canonical way to create a TonalVector is to pass in a tuple:

>>> TonalVector((0, 0, 0))
TonalVector((0, 0, 0))

For convenience, you can also pass in positional arguments:

>>> TonalVector(0, 0, 0)
TonalVector((0, 0, 0))
>>> TonalVector(0, 0) == TonalVector((0, 0))
True

There is no per-instance state, so nothing can be set on one:

>>> TonalVector((0, 0)).d = 1
Traceback (most recent call last):
...
AttributeError: ...
>>> TonalVector((0, 0)).anything = 1
Traceback (most recent call last):
...
AttributeError: ...

from_string

from_string(
    s: str,
    mid_c: int = 4,
    solfege_style: SolfegeStyle = SolfegeStyle.EURO_FIXED,
)

Creates and returns a TonalVector, given a parsable string representation of a pitch or interval.

Accepts letter names (A-G, case-insensitive) with ASCII, Unicode, or spelled-out accidentals; numeric octave designations (mid_c sets which octave number is treated as middle C); solfege syllables; and interval names (quality abbreviation or word, plus a number or ordinal). Lilypond-style spellings (“is”/“es” accidentals, “’”/“,” octave marks) are not accepted here – use from_ly instead.

Solfege syllables are ambiguous between two conventions, selected with solfege_style: EURO_FIXED (the default) treats each syllable as a fixed diatonic letter name with an optional separate accidental (e.g. “Si” = B, “Sol#” = G-sharp); OMK_MOVEABLE treats syllables as moveable-do, with dedicated chromatic syllables of their own (e.g. “Si” = so-sharp, “Di” = do-sharp).

Examples

>>> TonalVector.from_string('C')
TonalVector((0, 0))
>>> TonalVector.from_string('G#')
TonalVector((4, 8))
>>> TonalVector.from_string('Bb3')
TonalVector((6, 10, -1))
>>> TonalVector.from_string('perfect fifth')
TonalVector((4, 7))
>>> TonalVector.from_string('M9')
TonalVector((1, 2, 1))

from_ly

from_ly(s: str, prev_note: tuple[int, ...] | None = None)

Creates and returns an octave-qualified TonalVector, given a Lilypond-style pitch string.

Accepts Lilypond note names using “is”/“es” accidental suffixes (including the Dutch contractions “as”/“es” for “aes”/“ees”), and either absolute (“’”/“,”) or relative (resolved against prev_note) octave marks. Since Lilypond has no notion of an octave-less (abstract) pitch, the result is always octave-qualified – with no octave mark and no prev_note, the pitch is assumed to be in Lilypond’s default octave (OMK octave 0).

Relative octaves follow Lilypond’s rule: the note goes in whichever octave puts its letter name within a fourth of prev_note, ignoring accidentals, and any octave marks shift it from there.

Examples

>>> TonalVector.from_ly('cis')
TonalVector((0, 1, 0))
>>> TonalVector.from_ly("g'")
TonalVector((4, 7, 1))
>>> TonalVector.from_ly("g", prev_note=TonalVector((0, 0, 0)))
TonalVector((4, 7, -1))
>>> TonalVector.from_ly("as")
TonalVector((5, 8, 0))

__repr__

__repr__()
>>> TonalVector((0,0))
TonalVector((0, 0))
>>> TonalVector((2,4,1))
TonalVector((2, 4, 1))

__str__

__str__()

Returns a string that includes the repr string, along with human readable pitch and interval annotations in a Python-style inline comment.

This is a debug form. Note that f-strings and str.format do not use it: they go through Tone.__format__, which gives the display form (pitch.unicode by default).

Examples

>>> print(TonalVector((0,1)))
TonalVector((0, 1)) # C♯
>>> f"{TonalVector((0,1))}"
'C♯'
>>> print(TonalVector((2,3,1)))
TonalVector((2, 3, 1)) # E♭5

__add__

__add__(x: tuple[int, ...])

Examples

>>> TonalVector((0,1)) + TonalVector((1,1))
TonalVector((1, 2))
>>> TonalVector((6,11,1)) + TonalVector((1,1))
TonalVector((0, 0, 2))

__sub__

__sub__(x: tuple[int, ...])

Examples

>>> TonalVector((0,1)) - TonalVector((1,1))
TonalVector((6, 0))
>>> TonalVector((6,11,1)) - TonalVector((1,1))
TonalVector((5, 10, 1))
>>> abs(TonalVector((6,11,1)) - TonalVector((1,1,0))) == abs(TonalVector((1,1,0)) - TonalVector((6,11,1)))
True

distance

distance(x: tuple[int, ...])

Returns the smallest difference between self and x, as an interval (the absolute distance: never larger than a tritone for abstract vectors).

Examples

>>> TonalVector((0,0,0)).distance(TonalVector((4,7,0)))
TonalVector((4, 7, 0))
>>> TonalVector((4,7,0)).distance(TonalVector((0,0,0)))
TonalVector((4, 7, 0))
>>> TonalVector((0,0)).distance(TonalVector((4,7)))
TonalVector((3, 5))

nearest_instance

nearest_instance(x: tuple[int, ...])

Returns a Tonal Vector that has the same pitch class or interval type as x, closest to self.

Examples

>>> TonalVector((0,0)).nearest_instance(TonalVector((1,1,-3)))
TonalVector((1, 1))
>>> TonalVector((0,0)).nearest_instance(TonalVector((6,11,3)))
TonalVector((6, 11))
>>> TonalVector((0,0,0)).nearest_instance(TonalVector((1,1,-3)))
TonalVector((1, 1, 0))
>>> TonalVector((0,0,0)).nearest_instance(TonalVector((6,11,3)))
TonalVector((6, 11, -1))

__abs__

__abs__()

Returns the distance, in half-steps, from self to the origin.

Examples

>>> abs(TonalVector((0,0,-1)))
12
>>> abs(TonalVector((0,0,1)))
12

__int__

__int__()

Returns the signed distance, in half-steps, from self to the origin.

Examples

>>> int(TonalVector((0,0,-1)))
-12
>>> int(TonalVector((0,0,1)))
12

__gt__

__gt__(x: tuple[int, ...])

Returns True if self is higher (in pitch) or larger (in interval size) than x, otherwise False.

Examples

>>> TonalVector((1,1,0)) > TonalVector((0,0,0))
True
>>> TonalVector((2,4,1)) > (3,5,1)
False
>>> TonalVector((3,6,1)) > 6
True

__lt__

__lt__(x: tuple[int, ...])

Returns True if self is lower (in pitch) or smaller (in interval size) than x, otherwise False.

Examples

>>> TonalVector((1,1,0)) < TonalVector((0,0,0))
False
>>> TonalVector((2,4,1)) < (3,5,1)
True
>>> TonalVector((3,6,1)) < 6
False

transpose

transpose(x: tuple[int, ...], direction: TonalDirection = TonalDirection.UP)

Returns a TonalVector transposed by x, in the given direction.

Examples

>>> TonalVector((0,0)).transpose(TonalVector((1,1)))
TonalVector((1, 1))

inversion

inversion(x: tuple[int, ...] = (0, 0))

Returns the inversion of self over x.

When x is unspecified, returns the inversion of self over the origin, which is equivalent to the standard definition of inverting an interval.

Examples

>>> TonalVector((2,4)).inversion() # Maj3 --> min6
TonalVector((5, 8))
>>> TonalVector((5,8)).inversion() # min6 --> Maj3
TonalVector((2, 4))
>>> TonalVector((3,6)).inversion() # Aug4 --> dim5 (tritone)
TonalVector((4, 6))
>>> TonalVector((0,1,0)).inversion((0,0,0)) # augment unison --> diminished octave
TonalVector((0, 11, 0))

__eq__

__eq__(x)

Returns True if self and x are the same (d, c, [o]) values. Can compare with TonalVectors and plain (d, c, [o]) tuples.

Enharmonic equivalents are not equal (C♯ is not D♭); compare half-step values with int() for that.

Examples

>>> TonalVector((0,1,0)) == (0,1,0)
True
>>> TonalVector((0,1)) == TonalVector((1,1))
False
>>> TonalVector((0,1)) == 1
False
>>> int(TonalVector((0,1))) == int(TonalVector((1,1)))
True

__hash__

__hash__()

Hashes as its tuple, so a TonalVector is a set member and a dict key by value.

>>> hash(TonalVector((0, 0))) == hash((0, 0))
True
>>> len({TonalVector((0, 0)), TonalVector(0, 0)})
1

__call__

__call__(other)

Adds another TonalVector, or applies other to this one: C(maj) realizes a chord type at C, so a chord reads root first.

>>> from openmusickit.systems.wsmn.tonal.symbols import C, M3, maj
>>> C(M3)
TonalVector((2, 4))
>>> str(C(maj))
'C'

qualify_octave

qualify_octave(octave: int = 0)

Returns a TonalVector with an octave designation set to octave.

Example

>>> TonalVector((1, 2)).qualify_octave()
TonalVector((1, 2, 0))
>>> TonalVector((3, 4)).qualify_octave(2)
TonalVector((3, 4, 2))
>>> TonalVector((1, 2, 1)).qualify_octave()
TonalVector((1, 2, 0))
>>> TonalVector((3, 4, -1)).qualify_octave(2)
TonalVector((3, 4, 2))

conditional_qualify_octave

conditional_qualify_octave(octave: int = 0)

Returns a TonalVector with an octave designation set to octave, but does not change an existing octave designation if present.

>>> TonalVector((1, 2)).conditional_qualify_octave(1)
TonalVector((1, 2, 1))
>>> TonalVector((1, 2, 0)).conditional_qualify_octave(1)
TonalVector((1, 2, 0))

unqualify_octave

unqualify_octave()

Returns a TonalVector without an octave designation.

Example

>>> TonalVector.unqualify_octave(TonalVector((1, 2, 3)))
TonalVector((1, 2))