
    3j8              
         U d Z ddlmZ ddlZddlZddlZddlmZ ddlZddl	Z	ddl
mZ ddlmZ ddlmZ ddl
mZ dd	l
mZ dd
l
mZ ddl
mZ ddl
mZ ddl
mZ ddl
mZ  ej.                  d      Zeez  ej6                  z  ej8                  z  Zi Zded<   d Z d Z!dZ"dddddddddd	Z#	 d*	 	 	 d+dZ$ G d dejJ                        Z& G d d ejJ                        Z' G d! d"e(      Z) G d# d$ejT                        Z+ G d% d&e+ejX                        Z- G d' d(ej\                        Z/e+e-gZ0e1d)k(  rddl
Z
 e
jd                  e/       yy),aQ  
This module defines objects for representing key signatures as well as key
areas. The :class:`~music21.key.KeySignature` is used in
:class:`~music21.stream.Measure` objects for defining notated key signatures.

The :class:`~music21.key.Key` object is a fuller representation not just of
a key signature but also of the key of a region.
    )annotationsN)overload)base)cacheMethod)StepName)environment)exceptions21)interval)note)pitch)scale)stylekeyzdict[int, pitch.Pitch]_sharpsToPitchCachec                    | j                  d      r| dk(  r	 | S | dk(  rd} | S | dk(  rd} | S t        |       dk(  r| d   dk(  r
| d   d	z   } | S t        | d
d       dhk(  r| d   d	t        |       d
z
  z  z   } | S )a+  
    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--'
    bbbzb-BbB-   r   -   N)endswithlenset)
textStrings    8/DATA/.local/lib/python3.12/site-packages/music21/key.py"convertKeyStringToMusic21KeyStringr   1   s    4 $s):  
t	
  
t	

 	 
ZA	*R.C"7]S(
  
Z^		%]SC
Oa,?%@@
    c                P   | d} | t         v rt        j                  t         |          S t        j                  d      }d|_        | dkD  rd}n
| dk  rd}n|S t        j                  |      }t        t        |             D ]  }|j                  |      } d|_        |t         | <   |S )a  
    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 :class:`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>

    OMIT_FROM_DOCS

    The second time we do something it should be in the cache, so let's make sure it still works:

    >>> key.sharpsToPitch(1)
    <music21.pitch.Pitch G>
    >>> key.sharpsToPitch(1)
    <music21.pitch.Pitch G>
    >>> 1 in key._sharpsToPitchCache
    True
    >>> key._sharpsToPitchCache[1]
    <music21.pitch.Pitch G>
    Nr   CP5zP-5)r   copydeepcopyr   Pitchoctaver
   IntervalrangeabstransposePitch)
sharpCount	pitchInitintervalStrintervalObjis        r   sharpsToPitchr1   X   s    J 
((}}0<==C IIA~	a##K0K3z?#..y9	 $I&/
#r    )Fr"   GDAEBr   r   )	majorionianminoraeoliandorianphrygianlydian
mixolydianlocrianc                   t        | t              rt        j                  |       }nRt        | t        j                        r| }n5t        | t        j
                        r| j                  }nt        d|        t        j                  |j                        dz
  }|j                  N|j                  j                         du rt        d      t        |j                  j                        }|d|z  z   }||t        v r|t        |   z  }|S )a  
    Given a pitch string or :class:`music21.pitch.Pitch` or
    :class:`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!
    z&Cannot get a sharp number from value: r   Fz5Cannot determine sharps for quarter-tone keys! silly!   )
isinstancestrr   r&   r   NoteKeyExceptionfifthsOrderindexstep
accidentalisTwelveToneintaltermodeSharpsAlter)valuemode
pitchValuesharpsvaas        r   pitchToSharpsrX      s    R %[['
	E5;;	'
	E499	%[[
CE7KLL z/!3F(  --/58VWW*''--.!c'!DO3/$''Mr    c                      e Zd Zy)KeySignatureExceptionN__name__
__module____qualname__ r    r   rZ   rZ         r    rZ   c                      e Zd Zy)rJ   Nr[   r_   r    r   rJ   rJ     r`   r    rJ   c                      e Zd Zy)
KeyWarningNr[   r_   r    r   rc   rc     r`   r    rc   c                  P    e Zd ZdZej
                  ZdZdZdd fdZ	d Z
d ZdddZeedd              Zej                   	 	 dd	       Zedd
       ZddZedd	 	 	 	 	 dd       Ze	 	 	 	 	 	 d d       Zdd	 	 	 	 	 d!dZddd"dZd#dZd$dZd%dZ eeed      Z xZS )&KeySignaturea&	  
    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 :class:`~music21.key.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 :class:`~music21.key.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.
    )rV   r   c                    t        |   di | 	 | |t        |      k7  rt        d|ddz         || _        d | _        d| _        y # t        $ r}t        d|ddz         |d }~ww xY w)Nz8Cannot get a KeySignature from this "number" of sharps: z; z/did you mean to use a key.Key() object instead?Fr_   )super__init__rP   rZ   
ValueError_sharps_alteredPitchesaccidentalsApplyOnlyToOctave)selfrV   keywordsve	__class__s       r   rh   zKeySignature.__init__d  s    $8$		!vV'<+NvjXZ[GHI I  8<,1)  	'J6*TVWCD 	s   "A
 
	A+A&&A+c           	        d}| j                   }|:ddj                  | j                  D cg c]  }t        |       c}      z   dz   }|S |dkD  r| d}|S |dk(  rd}|S |dk(  rd	}|S |d
k(  rd}|S t	        |       d}|S c c}w )N z
pitches: [z, ]r   z sharpsz1 sharpr   zno sharps or flatsr   z1 flatz flats)rV   joinalteredPitchesrH   r*   )rm   outputnsps       r   _strDescriptionzKeySignature._strDescription{  s    [[:!DIIt?R?R.S?R!s1v?R.S$TTWZZF  !Vt7^F  1WF  1W)F
 	 2XF  By'F /Ts   B
c                (    d| j                         z   S Nzof )ry   rm   s    r   _reprInternalzKeySignature._reprInternal  s    t++---r    c                4   | j                   xs d}|!|t        j                  d| t        d       ||d}|=|;t        j                         D ci c]  \  }}||
 }}}t        |      }	 |||z
     }t        j                  t        |      }|j                         }|t        vrt        d	| d
      t        |   }	t        ||	z
        }
t        |
j                  |      S c c}}w # t        $ r!}t        d| j                    d|       |d}~ww xY w)a  
        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.
        r   Nzignoring provided tonic: r   )
stacklevelr<   z%Could not solve for mode from sharps=z, tonic=zMode z is unknown)rV   warningswarnrc   rR   itemsrX   KeyErrorrJ   tcastrH   lowerr1   Keyname)rm   rT   tonic
our_sharpskvmajorSharpsToModemajorSharpskesharpAlterationFromMajorpitchObjs              r   asKeyzKeySignature.asKey  s=   B [[%A
 1MM5eW=zVWX<EMD<E-2A2G2G2I J2I$!QA2I J'.Kb(k)AB vvc4 zz|&tfK899#24#8  .F!FG8==$'' !K  b";DKK=QVPWXZ_abbs   C'1C- -	D6DDc                   | j                   | j                   S g }| j                  |S | j                  dkD  rt        j                  d      }| j                  dkD  r	 t	        | j                        D ]B  }|j                  dd       t        j                  |      }d|_        |j                  |       D |S | j                  dk  rxt        j                  d      }t	        t        | j                              D ]B  }|j                  d	d       t        j                  |      }d|_        |j                  |       D |S )
a  
        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#>]

        OMIT_FROM_DOCS

        Ensure at least something is provided when the user hasn't provided enough info:

        >>> nonTrad2 = key.KeySignature(sharps=None)
        >>> nonTrad2.alteredPitches
        []

        Nr   r7      r#   TinPlacer2   P4)rk   rV   r   r&   r)   	transposer$   r%   r'   appendr*   )rm   postpKeepr0   rx   s        r   ru   zKeySignature.alteredPitches  s   p +'''"$;;K;;?KK$E{{Q4;;'d3MM%(A	 (  [[1_KK$E3t{{+,d3MM%(A	 - r    c                   | j                          g }|D ]  }t        |t              r%|j                  t	        j
                  |             8t        |t        j
                        r|j                  |       dt        |t        j                        s|j                  t        j                  |j                                || _
        y N)
clearCacherG   rH   r   r   r&   r   rI   r$   r%   rk   )rm   newAlteredPitchesnewListrx   s       r   ru   zKeySignature.alteredPitches  s     	%'"A!S!u{{1~.Au{{+q!Atyy)t}}QWW56 #  'r    c                6    | j                   | j                  ryy)a  
        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>
        TF)rV   ru   r|   s    r   isNonTraditionalzKeySignature.isNonTraditional(  s    ( ;;4#6#6r    c                    t        | j                        D ]N  }|j                  j                         |j                         k(  s/t	        j
                  |j                        c S  y)aN
  
        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'))
        >>> #_DOCS_SHOW s1.show()

        .. image:: images/keyAccidentalByStep_Before.*
            :width: 400

        After:

        >>> for n in s1.notes:
        ...    n.pitch.accidental = n.getContextByClass(key.KeySignature).accidentalByStep(n.step)
        >>> #_DOCS_SHOW s1.show()

        .. image:: images/keyAccidentalByStep.*
            :width: 400

        OMIT_FROM_DOCS
        >>> s1.show('text')
        {0.0} <music21.key.KeySignature of 4 sharps>
        {0.0} <music21.note.Note C#>
        {2.0} <music21.note.Note E>
        {4.0} <music21.key.KeySignature of 4 flats>
        {4.0} <music21.note.Note A->
        {8.0} <music21.note.Note F>

        Test to make sure there are not linked accidentals (fixed bug 22 Nov. 2010)

        >>> nB1 = note.Note('B', type='whole')
        >>> nB2 = note.Note('B', type='whole')
        >>> s1.append(nB1)
        >>> s1.append(nB2)
        >>> for n in s1.notes:
        ...    n.pitch.accidental = n.getContextByClass(key.KeySignature).accidentalByStep(n.step)
        >>> (nB1.pitch.accidental, nB2.pitch.accidental)
        (<music21.pitch.Accidental flat>, <music21.pitch.Accidental flat>)
        >>> nB1.pitch.accidental.name = 'sharp'
        >>> (nB1.pitch.accidental, nB2.pitch.accidental)
        (<music21.pitch.Accidental sharp>, <music21.pitch.Accidental flat>)
        N)reversedru   rM   r   r$   r%   rN   )rm   rM   thisAlterations      r   accidentalByStepzKeySignature.accidentalByStepA  sQ    R 't':':;N""((*djjl:}}^%>%>?? <
 r    Fr   c                    y r   r_   rm   rS   r   s      r   r   zKeySignature.transpose      
 	r    c                    y r   r_   r   s      r   r   zKeySignature.transpose  r   r    c                  t        |t        j                        r|}n2t        |t        j                        r|}nt        j                  |      }|st	        j
                  |       }n| }|j                  d      }|j                  }|j                  |      }t        |t              r't        t        |            dkD  r|j                         }t        |      |_        |j                          |s|S y)aG  
        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
        :class:`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>
        r<      N)rG   r
   r(   GenericIntervalr$   r%   r   r   r+   rP   r*   rX   getEnharmonicrV   r   )rm   rS   r   r/   r   k1p1p2s           r   r   zKeySignature.transpose  s    f eX../Kx778K"++E2K==&DDZZ XX''+eS!c-*;&<q&@!!#B#B' Kr    c                  d}d}|j                   }|st        j                  |      }| j                  dk(  r|ry|S | j                  dk  r+t	        | j                        }t        j                  d      }n!| j                  }t        j                  d      }t        |      D ]  }|j                  |d        |||_         |s|S y)a9  
        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'
        Nr   r   r#   Tr   )	r'   r$   r%   rV   r*   r
   r(   r)   r+   )rm   rx   r   transInterval
transTimesoriginalOctaver0   s          r   transposePitchFromCz KeySignature.transposePitchFromC  s    P 
a A;;!H[[1_T[[)J$--d3MJ$--d3Mz"A((D(9 # %%AHHr    c                    | j                  |      j                  }|dv rt        j                  |      S |dk(  rt        j                  |      S t        d|       )a@  
        Return a :class:`music21.scale.Scale` object (or, actually, a subclass such as
        :class:`~music21.scale.MajorScale` or :class:`~music21.scale.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>
        )Nr<   r>   z0No mapping to a scale exists for this mode yet: )r   r   r   
MajorScale
MinorScalerZ   )rm   rT   r   s      r   getScalezKeySignature.getScale4  s^      ::d#))?"##H--W_##H--'*Z[_Z`(abbr    c                    | j                   S r   )rj   r|   s    r   
_getSharpszKeySignature._getSharpsO  s    ||r    c                R    || j                   k7  r|| _         | j                          y y r   )rj   r   )rm   rS   s     r   
_setSharpszKeySignature._setSharpsR  s$    DLL  DLOO !r    a  
        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
        )doc)r   )rV   
int | None)NN)rT   
str | Noner   r   )returnzlist[pitch.Pitch])r   z#list[str | pitch.Pitch | note.Note]r   None)r   bool)rM   r   r   zpitch.Accidental | NonerS   TransposeTypesr   zt.Literal[False]r   zt.SelfrS   r   r   zt.Literal[True]r   r   rS   r   r   r   r   zt.Self | None)rx   pitch.Pitchr   zpitch.Pitch | None)r<   )r   r   )rS   r   )r\   r]   r^   __doc__r   	TextStyle_styleClassequalityAttributesclassSortOrderrh   ry   r}   r   propertyr   ru   setterr   r   r   r   r   r   r   r   rV   __classcell__rp   s   @r   re   re     sU   EL //K$ N2.".6(p O  Ob ' ' '  0Nd  /4' , 9?  ' + 04  #(L'L  L -8L\ >C CJc6
 j*Fr    re   c                  
    e Zd ZU dZdZdZded<   ded<   	 	 d	 ddZd	 Zd
 Z	d Z
d Zedd       Zedd       Zedd       Z fdZd ZdddZedd	 	 	 	 	 dd       Ze	 	 	 	 	 	 dd       Zdd	 	 	 	 	 d  fdZ xZS )!r   a  
    Note that a key is a sort of hypothetical/conceptual object.
    It probably has a scale (or scales) associated with it and a :class:`~music21.key.KeySignature`,
    but not necessarily.

    A Key object has all the attributes of a KeySignature and all the attributes of a
    :class:`~music21.scale.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.
    r   Nr   _moder   r   c                (   t        |t        j                  t        j                  f      r|j
                  }n|}|Ud|v rd}t        j                  dd|      }nGd|v rd}t        j                  dd|      }n)|j                         |k(  rd}nd}n|j                         }t        ||      }t        |t        j                        r|}n<t        |t        j                        r|j                  }nt        j                  |      }t        j                  | |fi | t        j                  j                  | fd|i| || _        || _        || _        | j"                  %| j"                  j%                  | j                         d | _        g | _        y )Nmr>   rr   Mr<   r   )rG   r   rI   r   r&   r   resubr   rX   re   rh   r   DiatonicScaler   typerT   	_abstractbuildNetworkcorrelationCoefficientalternateInterpretations)rm   r   rT   rn   tonicStrrV   
tonicPitchs          r   rh   zKey.__init__  sR    edii56zzHH <h66#r8466#r84!X-::<Dx.eU[[)Jtyy)JX.JdF7h7$$THHxH
		 >>%NN''		2
 '+# 46%r    c                    dt        |       z   S r{   )rH   r|   s    r   r}   zKey._reprInternal  s    s4y  r    c                <    | j                   }| d| j                   S )N )tonicPitchNameWithCaserT   )rm   r   s     r   __str__zKey.__str__  s$     ++$))%%r    c                    t         j                  | |      sy| j                  j                  |j                  j                  k(  xr | j                  |j                  k(  S )NF)re   __eq__r   r   rT   )rm   others     r   r   z
Key.__eq__  sD    ""4/zz%++"2"22NtyyEJJ7NNr    c                    t        |       dz	  S )N   )idr|   s    r   __hash__zKey.__hash__  s    $x1}r    c                    | j                   dvr| S | j                   dk(  r$t        | j                        j                  d      S t        | j                        j                  d      S )an  
        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>
        r>   r<   r<   r>   )rT   re   rV   r   r|   s    r   relativezKey.relative  sV    , 99..K99,227;;,227;;r    c                    | j                   dvr| S | j                   dk(  rt        | j                  d      S t        | j                  d      S )a  
        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>
        r   r<   r>   )rT   r   r   r|   s    r   parallelzKey.parallel  sD    & 99..K99tzz7++tzz7++r    c                    | j                   j                  }| j                  dk(  r|j                         }|S | j                  dk(  r|j	                         }|S )a  
        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'
        r<   r>   )r   r   rT   upperr   )rm   r   s     r   r   zKey.tonicPitchNameWithCase7  sO    . ::??99~~'H  YY'!~~'Hr    c                f    t         |   ||      }| j                  |_        d|_        g |_        |S )ai  
        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.
        N)rg   deriveByDegreerT   r   r   )rm   degreepitchRefretrp   s       r   r   zKey.deriveByDegreeU  s9    D g$VX699 &*"')$
r    c                \   | j                   st        d      g }|j                  | j                         | j                   D ]%  }|j                  }|dkD  s|j                  |       ' t	        |      dk  r| j                  dk  ry| j                  S |d   }|d   |d   z
  }|dz  |dz  z   S )NzDcannot process ambiguity without a list of .alternateInterpretationsr   r   g        r   )r   rZ   r   r   r   )rm   focussubKeyccabsMagnitude
leaderSpans         r   %_tonalCertaintyCorrelationCoefficientz)Key._tonalCertaintyCorrelationCoefficient  s    ,,'VX XT00133F..BAvR  4 u:>**a/222 Qx 1Xa(
 q Z!^44r    c                H    |dk(  r| j                         S t        d|       )al  
        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
        []
        r   zUnknown method: )r   ri   )rm   methods     r   tonalCertaintyzKey.tonalCertainty  s0    T --==??/x899r    Fr   c                    y r   r_   r   s      r   r   zKey.transpose       	r    c                    y r   r_   r   s      r   r   zKey.transpose  r  r    c                   |du rt         |   ||       | }nt         |   ||      }|j                  | j                        }|j                  |_        |j                          |s|S y)a  
        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
        :class:`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>
        Tr   N)rg   r   r   rT   r   r   )rm   rS   r   r   postKeyrp   s        r   r   zKey.transpose  sl    l d?GeW5D7$UG$<D**TYY']]
 Kr    )r"   N)r   str | pitch.Pitch | note.Note)r   r   )r   rH   )r   )r   floatr   r   r   )r\   r]   r^   r   rj   r   __annotations__rh   r}   r   r   r   r   r   r   r   r   r   r  r   r   r   r   s   @r   r   r   h  s.   JV GE8 5826126h!&O < <: , ,4  :)X58-:^  /4' , 	  ' + 	  #(C'C  C #	C Cr    r   c                  *    e Zd Zd Zd Zd Zd Zd Zy)Testc                2    ddl m}  || t                      y )Nr   )testCopyAll)music21.test.commonTestr  globals)rm   r  s     r   testCopyAndDeepcopyzTest.testCopyAndDeepcopy%  s    7D')$r    c                P    t               }| j                  |j                  d       y )Nr   )re   assertEqualrV   )rm   as     r   	testBasiczTest.testBasic)  s    N1%r    c                6   ddl m} t               }t        j                  d      }||_        | j                  |j
                  |       |j                  d      j                         }t        |      }| j                  |j
                  j                  d       y )Nr   )chordr7   z	Bb4 D5 F5r   r   )music21r  r   r   r&   r   assertIsChordrootr  r   )rm   r  r   r   
b_flat_majs        r   testSetToniczTest.testSetTonic-  sp    !E KKaggq! [[-224
j!t,r    c                   ddl m} ddl m} |j                  d      }|j	                  d      }|j                  d      }| j                  d|cxkD  xr d	kD  nc        |j                  d
d      }|j	                  d      }|j                  d      }| j                  d|cxkD  xr d	kD  nc        t        j                  d      }t        j                  d      }t        j                  d      }t        j                  d      }	|j                         }|j                  D ]&  }
|j                  t        j                  |
             ( |j	                  d      }|j                  d      }| j                  d|cxkD  xr d	kD  nc        |j                         }|j                  |j                  z   |j                  z   |j                  z   D ]&  }
|j                  t        j                  |
             ( |j	                  d      }|j                  d      }| j                  d|cxkD  xr d	kD  nc        |j                         }|j                  |	j                  z   D ]&  }
|j                  t        j                  |
             ( |j	                  d      }|j                  d      }| j                  d|cxkD  xr d	kD  nc        |j                         }dD ]&  }
|j                  t        j                  |
             ( |j	                  d      }|j                  d      }| j                  d|cxkD  xr
 d	kD         y c        y )Nr   )corpus)streamzbwv66.6KrumhanslSchmucklerr   )r  r   g?zschoenberg/opus19r   gdr  zf#)cr$  r&  r&  e)r  r!  r"  parseanalyzer  
assertTruer   r   Streampitchesr   r   rI   )rm   r!  r"  sr   tasc1sc2sc3sc5rx   s              r   testTonalAmbiguityAzTest.testTonalAmbiguityA<  s   ""
 LL#II+,%=>B%LL,a0II+,%=>B%s#s#s#t$MMOAHHTYYq\" II+,%=>B%MMOs{{*S[[83;;FAHHTYYq\" GII+,%=>B%MMOs{{*AHHTYYq\" +II+,%=>B%MMO*AHHTYYq\" +II+,%=>B%%r    c                   t        d      }|j                  d d       }| j                  |j                  d       | j                  |j                  d       |j                  d      }| j                  |j                  d       | j                  |j                  d       d}| j                  t        |      5 }|j                  d	d      }d d d        | j                  |j                  d	       | j                  |j                  d
       d}| j                  t        |      5 }|j                  d d      }d d d        | j                  j                  j                  t               y # 1 sw Y   xY w# 1 sw Y   @xY w)Nr   )rT   r   r<   r4   r6   r  r@   zignoring provided tonic: Er>   r   z0Could not solve for mode from sharps=2, tonic=A-zA-)re   r   r  rT   r   assertWarnsRegexrc   assertRaisesRegexrJ   assertIsInstance	exception	__cause__r   )rm   ksr   expectedcms        r   	testAsKeyzTest.testAsKeys  s7   !_HH$dH+)1137HH3H*1137/"":x8BgS1A 9 	)1137E##L(;rd$/A < 	bll44h? 98 <;s   9E,%E8,E58FN)r\   r]   r^   r  r  r  r3  r=  r_   r    r   r  r  #  s    %&-0&n@r    r  __main__r   )rS   r	  rT   r   r   rP   )3r   
__future__r   r$   r   typingr   r   unittestr   r  r   music21.common.decoratorsr   music21.common.typesr   r   r	   r
   r   r   r   r   EnvironmentenvironLocalrP   rH   r(   r   r   r   r  r   r1   rK   rR   rX   Music21ExceptionrZ   rJ   Warningrc   Music21Objectre   r   r   TestCaser  
_DOC_ORDERr\   mainTestr_   r    r   <module>rL     sr   #  	      1 )        &{&&u-S***8+C+CC
 /1 + 0$N<D 2 !!# 	 $(] ],/]@	L99 		<00 		 	
Q	4%% Q	hw,++ wvf@8 f@V C 
 zGT r    