music21.key

This module defines objects for representing key signatures as well as key areas. The KeySignature is used in Measure objects for defining notated key signatures.

The Key object is a fuller representation not just of a key signature but also of the key of a region.

KeySignature

class music21.key.KeySignature(sharps: int | None = 0, **keywords)

A KeySignature object specifies the signature to be used for a piece; it normally takes one argument: an int giving the number of sharps, or, if negative, the number of flats.

If you are starting with the name of a key, see the Key object.

>>> A = key.KeySignature(3)
>>> A
<music21.key.KeySignature of 3 sharps>
>>> Eflat = key.KeySignature(-3)
>>> Eflat
<music21.key.KeySignature of 3 flats>

If you want to get a real Key, then use the Key object instead:

>>> illegal = key.KeySignature('c#')
Traceback (most recent call last):
music21.key.KeySignatureException: Cannot get a KeySignature from this
    "number" of sharps: 'c#'; did you mean to use a key.Key() object instead?
>>> legal = key.Key('c#')
>>> legal.sharps
4
>>> legal
<music21.key.Key of c# minor>

To set a non-traditional Key Signature, create a KeySignature object with sharps=None, and then set the alteredPitches list:

>>> unusual = key.KeySignature(sharps=None)
>>> unusual.alteredPitches = ['E-', 'G#']
>>> unusual
<music21.key.KeySignature of pitches: [E-, G#]>
>>> unusual.isNonTraditional
True

To set a pitch as displayed in a particular octave, create a non-traditional KeySignature and then set pitches with octaves:

>>> unusual = key.KeySignature(sharps=None)
>>> unusual.alteredPitches = ['F#4']
>>> unusual
<music21.key.KeySignature of pitches: [F#4]>

If the accidental applies to all octaves but is being displayed differently then you are done, but if you want them to apply only to the octave displayed in then set .accidentalsApplyOnlyToOctave to True:

>>> unusual.accidentalsApplyOnlyToOctave
False
>>> unusual.accidentalsApplyOnlyToOctave = True

Equality

Two KeySignatures are equal if they pass all super().__eq__ checks and their sharps are equal. Currently, non-standard key signatures are not checked (this may change).

>>> sharp2 = key.KeySignature(2)
>>> flat4 = key.KeySignature(-4)
>>> sharp2 == flat4
False
>>> sharp2 == key.KeySignature(2)
True
  • Changed in v7: sharps defaults to 0 (key of no flats/sharps) rather than None for nontraditional keys.

KeySignature bases

KeySignature read-only properties

KeySignature.isNonTraditional

Returns bool if this is a non-traditional KeySignature:

>>> g = key.KeySignature(3)
>>> g.isNonTraditional
False
>>> g = key.KeySignature(sharps=None)
>>> g.alteredPitches = [pitch.Pitch('E`')]
>>> g.isNonTraditional
True
>>> g
<music21.key.KeySignature of pitches: [E`]>
>>> g.accidentalByStep('E')
<music21.pitch.Accidental half-flat>

Read-only properties inherited from Music21Object:

Read-only properties inherited from ProtoM21Object:

KeySignature read/write properties

KeySignature.alteredPitches

Return or set a list of music21.pitch.Pitch objects that are altered by this KeySignature. That is, all Pitch objects that will receive an accidental.

>>> a = key.KeySignature(3)
>>> a.alteredPitches
[<music21.pitch.Pitch F#>, <music21.pitch.Pitch C#>, <music21.pitch.Pitch G#>]
>>> b = key.KeySignature(1)
>>> b.alteredPitches
[<music21.pitch.Pitch F#>]
>>> c = key.KeySignature(9)
>>> [str(p) for p in c.alteredPitches]
['F#', 'C#', 'G#', 'D#', 'A#', 'E#', 'B#', 'F##', 'C##']
>>> d = key.KeySignature(-3)
>>> d.alteredPitches
[<music21.pitch.Pitch B->, <music21.pitch.Pitch E->, <music21.pitch.Pitch A->]
>>> e = key.KeySignature(-1)
>>> e.alteredPitches
[<music21.pitch.Pitch B->]
>>> f = key.KeySignature(-6)
>>> [str(p) for p in f.alteredPitches]
['B-', 'E-', 'A-', 'D-', 'G-', 'C-']
>>> g = key.KeySignature(-8)
>>> [str(p) for p in g.alteredPitches]
['B-', 'E-', 'A-', 'D-', 'G-', 'C-', 'F-', 'B--']

Non-standard, non-traditional key signatures can set their own altered pitches cache.

>>> nonTrad = key.KeySignature(sharps=None)
>>> nonTrad.alteredPitches = ['B-', 'F#', 'E-', 'G#']
>>> nonTrad.alteredPitches
[<music21.pitch.Pitch B->,
 <music21.pitch.Pitch F#>,
 <music21.pitch.Pitch E->,
 <music21.pitch.Pitch G#>]
KeySignature.sharps

Get or set the number of sharps. If the number is negative then it sets the number of flats. Equivalent to musicxml’s ‘fifths’ attribute.

>>> ks1 = key.KeySignature(2)
>>> ks1.sharps
2
>>> ks1.sharps = -4
>>> ks1
<music21.key.KeySignature of 4 flats>

Can be set to None for a non-traditional key signature

Read/write properties inherited from Music21Object:

KeySignature methods

KeySignature.accidentalByStep(step: Literal['C', 'D', 'E', 'F', 'G', 'A', 'B']) Accidental | None

Given a step (C, D, E, F, etc.) return the accidental for that note in this key (using the natural minor for minor) or None if there is none.

>>> g = key.KeySignature(1)
>>> g.accidentalByStep('F')
<music21.pitch.Accidental sharp>
>>> g.accidentalByStep('G') is None
True
>>> f = key.KeySignature(-1)
>>> bbNote = note.Note('B-5')
>>> f.accidentalByStep(bbNote.step)
<music21.pitch.Accidental flat>

Fix a wrong note in F-major:

>>> wrongBNote = note.Note('B#4')
>>> if f.accidentalByStep(wrongBNote.step) != wrongBNote.pitch.accidental:
...    wrongBNote.pitch.accidental = f.accidentalByStep(wrongBNote.step)
>>> wrongBNote
<music21.note.Note B->

Set all notes to the correct notes for a key using the note’s Key Context. Before:

>>> s1 = stream.Stream()
>>> s1.append(key.KeySignature(4))  # E-major or C-sharp-minor
>>> s1.append(note.Note('C', type='half'))
>>> s1.append(note.Note('E-', type='half'))
>>> s1.append(key.KeySignature(-4))  # A-flat-major or F-minor
>>> s1.append(note.Note('A', type='whole'))
>>> s1.append(note.Note('F#', type='whole'))
>>> s1.show()
../_images/keyAccidentalByStep_Before.png

After:

>>> for n in s1.notes:
...    n.pitch.accidental = n.getContextByClass(key.KeySignature).accidentalByStep(n.step)
>>> s1.show()
../_images/keyAccidentalByStep.png
KeySignature.asKey(mode: str | None = None, tonic: str | None = None)

Return a key.Key object representing this KeySignature object as a key in the given mode or in the given tonic. If mode is None, and tonic is not provided, major is assumed. If both mode and tonic are provided, the tonic is ignored.

>>> ks = key.KeySignature(2)
>>> ks.asKey()
<music21.key.Key of D major>
>>> ks.asKey(mode='minor')
<music21.key.Key of b minor>

If mode is None, an attempt is made to solve for the mode:

>>> ks.asKey(tonic='A')
<music21.key.Key of A mixolydian>

But will raise KeyException if an impossible solution is requested:

>>> ks.asKey(tonic='D#')
Traceback (most recent call last):
music21.key.KeyException: Could not solve for mode from sharps=2, tonic=D#

Ionian and Aeolian are supplied instead of major or minor when deriving mode in this way:

>>> ks2 = key.KeySignature()
>>> ks2.asKey()
<music21.key.Key of C major>
>>> ks2.asKey(tonic='C')
<music21.key.Key of C ionian>
  • New in v7: tonic argument to solve for mode.

KeySignature.getScale(mode='major')

Return a music21.scale.Scale object (or, actually, a subclass such as MajorScale or MinorScale) that is representative of this key signature and mode.

Raises KeySignatureException if mode is not in [None, ‘major’, ‘minor’].

>>> ks = key.KeySignature(3)
>>> ks
<music21.key.KeySignature of 3 sharps>
>>> ks.getScale('major')
<music21.scale.MajorScale A major>
>>> ks.getScale('minor')
<music21.scale.MinorScale F# minor>
KeySignature.transpose(value: int | str | Interval | GenericInterval, *, inPlace: Literal[False] = False) KeySignatureType
KeySignature.transpose(value: int | str | Interval | GenericInterval, *, inPlace: Literal[True]) None

Transpose the KeySignature by the user-provided value. If the value is an integer, the transposition is treated in half steps. If the value is a string, any Interval string specification can be provided. Alternatively, a music21.interval.Interval object can be supplied.

>>> a = key.KeySignature(2)
>>> a
<music21.key.KeySignature of 2 sharps>
>>> a.asKey('major')
<music21.key.Key of D major>
>>> b = a.transpose('p5')
>>> b
<music21.key.KeySignature of 3 sharps>
>>> b.asKey('major')
<music21.key.Key of A major>
>>> b.sharps
3
>>> c = b.transpose('-m2')
>>> c.asKey('major')
<music21.key.Key of G# major>
>>> c.sharps
8
>>> d = c.transpose('-a3')
>>> d.asKey('major')
<music21.key.Key of E- major>
>>> d.sharps
-3

Transposition by semitone (or other chromatic interval)

>>> c = key.KeySignature(0)
>>> dFlat = c.transpose(1)
>>> dFlat
<music21.key.KeySignature of 5 flats>
>>> d = dFlat.transpose(1)
>>> d
<music21.key.KeySignature of 2 sharps>
>>> eFlat = d.transpose(1)
>>> eFlat
<music21.key.KeySignature of 3 flats>
KeySignature.transposePitchFromC(p: Pitch, *, inPlace=False) Pitch | None

Takes a pitch in C major and transposes it so that it has the same step position in the current key signature.

Example: B is the leading tone in C major, so given a key signature of 3 flats, get the leading tone in E-flat major:

>>> ks = key.KeySignature(-3)
>>> p1 = pitch.Pitch('B')
>>> p2 = ks.transposePitchFromC(p1)
>>> p2.name
'D'

Original pitch is unchanged:

>>> p1.name
'B'
>>> ks2 = key.KeySignature(2)
>>> p2 = ks2.transposePitchFromC(p1)
>>> p2.name
'C#'

For out of scale pitches the relationship still works; note also that original octave is preserved.

>>> p3 = pitch.Pitch('G-4')
>>> p4 = ks.transposePitchFromC(p3)
>>> p4.nameWithOctave
'B--4'

If inPlace is True then the original pitch is modified and nothing is returned.

>>> p5 = pitch.Pitch('C5')
>>> ks.transposePitchFromC(p5, inPlace=True)
>>> p5.nameWithOctave
'E-5'

Methods inherited from Music21Object:

Methods inherited from ProtoM21Object:

KeySignature instance variables

Instance variables inherited from Music21Object:

Key

class music21.key.Key(tonic: str | Pitch | Note = 'C', mode=None, **keywords)

Note that a key is a sort of hypothetical/conceptual object. It probably has a scale (or scales) associated with it and a KeySignature, but not necessarily.

A Key object has all the attributes of a KeySignature and all the attributes of a DiatonicScale.

>>> cm = key.Key('c')  # lowercase = c minor.
>>> cm
<music21.key.Key of c minor>
>>> cm.mode
'minor'
>>> cm.tonic
<music21.pitch.Pitch C>
>>> cm.sharps
-3
>>> cm.pitchFromDegree(3)
<music21.pitch.Pitch E-4>
>>> cm.pitchFromDegree(7)
<music21.pitch.Pitch B-4>
>>> cSharpMaj = key.Key('C#')  # uppercase = C# major
>>> cSharpMaj
<music21.key.Key of C# major>
>>> cSharpMaj.sharps
7
>>> fFlatMaj = key.Key('F-')
>>> fFlatMaj
<music21.key.Key of F- major>
>>> fFlatMaj.sharps
-8
>>> fFlatMaj.accidentalByStep('B')
<music21.pitch.Accidental double-flat>
>>> eDor = key.Key('E', 'dorian')
>>> eDor
<music21.key.Key of E dorian>
>>> eDor.sharps
2
>>> eDor.pitches
[<music21.pitch.Pitch E4>,
 <music21.pitch.Pitch F#4>,
 <music21.pitch.Pitch G4>,
 <music21.pitch.Pitch A4>,
 <music21.pitch.Pitch B4>,
 <music21.pitch.Pitch C#5>,
 <music21.pitch.Pitch D5>,
 <music21.pitch.Pitch E5>]

If you prefer not to use uppercase and lowercase to distinguish major and minor, the shorthand of CM or Cm can also be used:

>>> key.Key('EM')
<music21.key.Key of E major>
>>> key.Key('F#m')
<music21.key.Key of f# minor>

Equality

Two Keys are equal if their tonics’ names are equal, their sharps are equal, and their modes are equal (and they pass all superclass tests)

>>> k = key.Key(pitch.Pitch('C4'))
>>> k2 = key.Key(pitch.Pitch('C5'))
>>> k == k2
True
>>> k.mode = 'minor'
>>> k == k2
False
  • Changed in v8: keys now compare equal regardless of the octave of their tonics.

Key bases

Key read-only properties

Key.parallel

if the Key is major or minor, return the parallel minor or major.

Otherwise, just returns self – this is the best way to not have random crashes in the middle of large datasets.

>>> k = key.Key('D')
>>> k
<music21.key.Key of D major>
>>> k.parallel
<music21.key.Key of d minor>
>>> k.parallel.parallel
<music21.key.Key of D major>
>>> key.Key('D', 'dorian').parallel
<music21.key.Key of D dorian>
Key.relative

if the Key is major or minor, return the relative minor or major.

Otherwise, just returns self – this is the best way to not have random crashes in the middle of large datasets.

Note that this uses .sharps as a speedup, so if that has been changed, there will be a problem…

>>> k = key.Key('E-')
>>> k
<music21.key.Key of E- major>
>>> k.relative
<music21.key.Key of c minor>
>>> k.relative.relative
<music21.key.Key of E- major>
>>> key.Key('D', 'dorian').relative
<music21.key.Key of D dorian>
Key.tonicPitchNameWithCase

Return the pitch name as a string with the proper case (upper = major; lower = minor)

Useful, but simple:

>>> k = key.Key('c#')
>>> k.tonicPitchNameWithCase
'c#'
>>> k = key.Key('B')
>>> k.tonicPitchNameWithCase
'B'
>>> k.mode = 'minor'
>>> k.tonicPitchNameWithCase
'b'

Anything else will return the default (capital)

>>> k.mode = 'dorian'
>>> k.tonicPitchNameWithCase
'B'

Read-only properties inherited from KeySignature:

Read-only properties inherited from ConcreteScale:

Read-only properties inherited from Music21Object:

Read-only properties inherited from ProtoM21Object:

Key read/write properties

Read/write properties inherited from KeySignature:

Read/write properties inherited from ConcreteScale:

Read/write properties inherited from Music21Object:

Key methods

Key.__eq__(other)

Define equality for Music21Objects. See main class docs.

Key.deriveByDegree(degree, pitchRef)

Given a degree and pitchReference derive a new Key object that has the same mode but a different tonic

Example: What minor key has scale degree 3 as B-flat?

>>> minorKey = key.Key(mode='minor')
>>> newMinor = minorKey.deriveByDegree(3, 'B-')
>>> newMinor
<music21.key.Key of g minor>

Note that in minor, the natural form is used:

>>> minorKey.deriveByDegree(7, 'E')
<music21.key.Key of f# minor>
>>> minorKey.deriveByDegree(6, 'G')
<music21.key.Key of b minor>

To use the harmonic form, change .abstract on the key to another abstract scale:

>>> minorKey.abstract = scale.AbstractHarmonicMinorScale()
>>> minorKey.deriveByDegree(7, 'E')
<music21.key.Key of f minor>
>>> minorKey.deriveByDegree(6, 'G')
<music21.key.Key of b minor>

Currently because of a limitation in bidirectional scale searching, melodic minor scales cannot be used as abstracts for deriving by degree.

  • New in v6: preserve mode in key.Key.deriveByDegree

Key.tonalCertainty(method='correlationCoefficient') float

Provide a measure of tonal ambiguity for Key determined with one of many methods.

The correlationCoefficient assumes that the alternateInterpretations list has been filled from the use of a KeyWeightKeyAnalysis subclass.

>>> littlePiece = converter.parse("tinyNotation: 4/4 c4 d e f g a b c' e' g' e' c'")
>>> k = littlePiece.analyze('key')
>>> k
<music21.key.Key of C major>
>>> k.tonalCertainty()
1.1648...

Three most likely alternateInterpretations:

>>> k.alternateInterpretations[0:3]
[<music21.key.Key of a minor>, <music21.key.Key of F major>, <music21.key.Key of d minor>]
>>> k.correlationCoefficient
0.9068...
>>> k.alternateInterpretations[0].correlationCoefficient
0.7778...

least likely interpretation:

>>> k.alternateInterpretations[-1]
<music21.key.Key of F# major>

Note that this method only exists if the key has come from an analysis method. Otherwise it raises a KeySignatureException

>>> k2 = key.Key('b-')
>>> k2.tonalCertainty()
Traceback (most recent call last):
music21.key.KeySignatureException: cannot process ambiguity without a
    list of .alternateInterpretations
>>> k2.alternateInterpretations
[]
Key.transpose(value: int | str | Interval | GenericInterval, *, inPlace: Literal[False] = False) KeyType
Key.transpose(value: int | str | Interval | GenericInterval, *, inPlace: Literal[True]) None

Transpose the Key by the user-provided value. If the value is an integer, the transposition is treated in half steps. If the value is a string, any Interval string specification can be provided. Alternatively, a music21.interval.Interval object can be supplied.

>>> dMajor = key.Key('D')
>>> dMajor
<music21.key.Key of D major>
>>> aMaj = dMajor.transpose('p5')
>>> aMaj
<music21.key.Key of A major>
>>> aMaj.sharps
3
>>> aMaj.tonic
<music21.pitch.Pitch A>
>>> aMaj.mode
'major'

inPlace=True works here and returns None while changing the Key itself.

>>> changingKey = key.Key('g')
>>> changingKey
<music21.key.Key of g minor>
>>> changingKey.sharps
-2
>>> changingKey.transpose('m-3', inPlace=True)
>>> changingKey
<music21.key.Key of e minor>
>>> changingKey.sharps
1
>>> changingKey.transpose(1, inPlace=True)
>>> changingKey
<music21.key.Key of f minor>
>>> changingKey.sharps
-4
>>> changingKey.transpose(1, inPlace=True)
>>> changingKey
<music21.key.Key of f# minor>
>>> changingKey.transpose(1, inPlace=True)
>>> changingKey
<music21.key.Key of g minor>
>>> changingKey.transpose(1, inPlace=True)
>>> changingKey
<music21.key.Key of g# minor>

Methods inherited from KeySignature:

Methods inherited from DiatonicScale:

Methods inherited from ConcreteScale:

Methods inherited from Scale:

Methods inherited from Music21Object:

Methods inherited from ProtoM21Object:

Key instance variables

Instance variables inherited from Music21Object:

Functions

music21.key.convertKeyStringToMusic21KeyString(textString)

Utility function to change strings in the form of “Eb” to “E-” (for E-flat major) and leaves alone proper music21 strings (like “E-” or “f#”). A little bit complex because of parsing bb as B-flat minor and Bb as B-flat major.

>>> key.convertKeyStringToMusic21KeyString('Eb')
'E-'
>>> key.convertKeyStringToMusic21KeyString('f#')
'f#'
>>> key.convertKeyStringToMusic21KeyString('bb')
'b-'
>>> key.convertKeyStringToMusic21KeyString('Bb')
'B-'
>>> key.convertKeyStringToMusic21KeyString('b#')
'b#'
>>> key.convertKeyStringToMusic21KeyString('c')
'c'
>>> key.convertKeyStringToMusic21KeyString('Bbb')
'B--'
>>> key.convertKeyStringToMusic21KeyString('bbb')
'b--'
>>> key.convertKeyStringToMusic21KeyString('Ebb')
'E--'
music21.key.pitchToSharps(value: str | Pitch | Note, mode: str | None = None) int

Given a pitch string or music21.pitch.Pitch or music21.note.Note object, return the number of sharps found in that mode.

The mode parameter can be ‘major’, ‘minor’, or most of the common church/jazz modes (‘dorian’, ‘mixolydian’, etc.) including Locrian.

If mode is omitted or not found, the default mode is major.

(extra points to anyone who can find the earliest reference to the Locrian mode in print. David Cohen and I (MSAC) have been looking for this for years).

>>> key.pitchToSharps('c')
0
>>> key.pitchToSharps('c', 'minor')
-3
>>> key.pitchToSharps('a', 'minor')
0
>>> key.pitchToSharps('d')
2
>>> key.pitchToSharps('e-')
-3
>>> key.pitchToSharps('a')
3
>>> key.pitchToSharps('e', 'minor')
1
>>> key.pitchToSharps('f#', 'major')
6
>>> key.pitchToSharps('g-', 'major')
-6
>>> key.pitchToSharps('c#')
7
>>> key.pitchToSharps('g#')
8
>>> key.pitchToSharps('e', 'dorian')
2
>>> key.pitchToSharps('d', 'dorian')
0
>>> key.pitchToSharps('g', 'mixolydian')
0
>>> key.pitchToSharps('e-', 'lydian')
-2
>>> key.pitchToSharps('e-', 'lydian')
-2
>>> key.pitchToSharps('a', 'phrygian')
-1
>>> key.pitchToSharps('e', 'phrygian')
0
>>> key.pitchToSharps('f#')
6
>>> key.pitchToSharps(note.Note('f-'))
-8
>>> key.pitchToSharps(pitch.Pitch('f--'))
-15
>>> key.pitchToSharps('f--', 'locrian')
-20
>>> key.pitchToSharps('a', 'ionian')
3
>>> key.pitchToSharps('a', 'aeolian')
0

But quarter tones don’t work:

>>> key.pitchToSharps('C~')
Traceback (most recent call last):
music21.key.KeyException: Cannot determine sharps for quarter-tone keys! silly!
music21.key.sharpsToPitch(sharpCount)

Given a positive/negative number of sharps, return a Pitch object set to the appropriate major key value.

>>> key.sharpsToPitch(1)
<music21.pitch.Pitch G>
>>> key.sharpsToPitch(2)
<music21.pitch.Pitch D>
>>> key.sharpsToPitch(-2)
<music21.pitch.Pitch B->
>>> key.sharpsToPitch(-6)
<music21.pitch.Pitch G->

Note that these are music21.pitch.Pitch objects not just names:

>>> k1 = key.sharpsToPitch(6)
>>> k1
<music21.pitch.Pitch F#>
>>> k1.step
'F'
>>> k1.accidental
<music21.pitch.Accidental sharp>