
    3j*                        d Z ddlmZ ddlZddlZddlZd Z G d d      Z G d d      Z	 G d	 d
ej                        Zedk(  rddlZ ej                  e       yy)z
Harmonic annotations from humdrum to `music21`.

The `**harm` representation is described here: https://www.humdrum.org/rep/harm/
    )annotationsNc                @   t               j                  |       }|sy|d   dk(  r	d}dg|d<   n!|d   dk(  rd}n|d   d	k(  r	d	}dg|d<   n|d   }d
}|d   r|d   }d
}|d   r|d   }d}|d   r	d|d   v rd}|d   rg dj                  |d         }nd}d
}|dk(  r|rdnd
}n|dk(  r|rdnd}n|dk(  r|rdnd}n|dk(  rd}g }|d   r4|j                  d
       |d   }	|	r|j                  |	d          |	d   }	|	rd
}	|rdj	                  |      }	||z   |z   |z   |	z   S )al  
    Converts a `**harm` string into a string that
    can be used to instantiate a RomanNumeral object.

    This is necessary because the two notations are not
    identical. For example, a "V7b" in `**harm` turns into "V65".

    Instantiate a HarmParser to process `**harm` strings

    >>> convertHarmToRoman = humdrum.harmParser.convertHarmToRoman

    Convert a few `**harm` strings to music21.roman.RomanNumeral figures

    >>> diatonicTriads = ['I', 'Vc', 'Ib', 'iib', 'V', 'viiob', 'vib']
    >>> [convertHarmToRoman(x) for x in diatonicTriads]
    ['I', 'V64', 'I6', 'ii6', 'V', 'viio6', 'vi6']

    A few seventh-chord inversions
    >>> diatonicSevenths = ['V7', 'viio7c', 'V7d', 'viio7b', 'V7c']
    >>> [convertHarmToRoman(x) for x in diatonicSevenths]
    ['V7', 'viio43', 'V2', 'viio65', 'V43']

    Inversion-wise, augmented sixth chords are a bit tricky
    German and French are treated as seventh-chords (4 notes)
    Italians are treated as triads

    >>> italianSixths = ['Lt', 'Ltb', 'Ltc']
    >>> [convertHarmToRoman(x) for x in italianSixths]
    ['It', 'It6', 'It64']

    >>> frenchSixths = ['Fr', 'Frb', 'Frc', 'Frd']
    >>> [convertHarmToRoman(x) for x in frenchSixths]
    ['Fr7', 'Fr65', 'Fr43', 'Fr2']

    >>> germanSixths = ['Gn', 'Gnb', 'Gnc', 'Gnd']
    >>> [convertHarmToRoman(x) for x in germanSixths]
    ['Ger7', 'Ger65', 'Ger43', 'Ger2']
    NrootGnGer7	intervalsLtItFr 
accidental	attributeFT	inversion)abcdr      656   4364   2	secondary/)
HarmParserparseindexappendjoin)
harmStrharmdegree
alterationfifthsQuality	isSeventhinversionNumberr   secondaryFunctionsr   s
             G/DATA/.local/lib/python3.12/site-packages/music21/humdrum/harmParser.pyconvertHarmToRomanr-      s   R <g&DF|t E[	f		f	 E[fJL,'
MK[)IKSD$55	K.44T+5FGI!$C"		A	%D3		A	%D4		A		K!!"%%	%%i&78!+.I  IHH/0	.:YFF    c                  d    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ez   ez   ez   ez   ez   e
z   ez   dz   Zy)HarmDefszA
    Regular expression definitions for the HarmParser class
    zK
    (?P<accidental>          # Named group _accidental
    [#-]{0,2})
    z
    (?P<root>               # Named group _root_
     i|ii|iii|iv|v|vi|vii|  # Minor mode degrees
     I|II|III|IV|V|VI|VII|  # Major mode degrees
     N|Gn|Lt|Fr|Tr)         # Special chords
    zF
    (?P<attribute>          # Named group _attribute_
    [o+]?)
    aO  
    ((?P<intervals>         # Named group _intervals
    \d+|[mMPAD]\d+|         # Detect minor, Major, Augmented or Diminished intervals
    AA\d+|                  # Double-augmented intervals
    DD\d+)                  # Double-diminished intervals
    *)                      # Not a limit on how many intervals can be added
    z
    (?P<inversion>          # Named group _inversions_
    [b-d]?)                 # Only third inversions possible so far
    a  
    ^(                      # Match for entire string or fail
    \(                      # Open parenthesis
    (?P<implied_harmony>    # Group the expression
    ([^\(^\)])+             # At least one expression
    )                       # /Group the expression
    \)                      # Closing parenthesis
    )$                      # /Match for entire string or fail
    aQ  
    (\[                     # Open brackets
    (?P<alternative>        # Named group _alternative_
    ([^\[^\]])+)            # Match at least one time for any expression inside brackets
    \]                      # Close brackets
    )?                      # If no alternative expression, then no brackets should appear at all
    a(  
    (/                      # Slash implies a secondary function
    (?P<secondary>          # Named group _secondary_
    ([\s\S])+)              # Get all the expression after the slash symbol
    )?                      # If no secondary function, then the slash symbol should not appear
    z^(z)$N)__name__
__module____qualname____doc__r   rootsr   r	   r   impliedalternativer   harmExpression r.   r,   r0   r0   v   s    
JEIIIGKI 

  	
    Nr.   r0   c                  ,    e Zd ZdZ e       Zd ZddZy)r   z1
    Parses an expression in `**harm` syntax
    c                   t        j                  t        j                  j                  t         j
                        | _        t        j                  t        j                  j                  t         j
                        | _        y )N)	recompiler   defsr8   VERBOSE
harmRegExpr6   impliedRegExp)selfs    r,   __init__zHarmParser.__init__   sC    **Z__%C%CRZZPZZ
(?(?Lr.   c                   | j                   j                  |      }|r-|j                         d   }| j                  |      }|rd|d<   |S | j                  j                  |      }|rW|j                         }d|d<   |d   |d   }| j                  |      }||d<   |d   |d   }| j                  |      }	|	|d<   |S i S )Nimplied_harmonyTr6   Fr7   r   )rA   match	groupdictr    r@   )
rB   r8   impliedMatchimpliedHarmonymmatchHarmRegExpalternativeExpressionr   secondaryExpressionss
             r,   r    zHarmParser.parse   s     ))//?)3356GHN

>*A#)H #oo33NCO#--/$)]#/,-m,<)

#89A'(Am$[>-*+K.'

#67A%&AkNIr.   N)returnzdict[str, t.Any])r1   r2   r3   r4   r0   r>   rC   r    r9   r.   r,   r   r      s     :DMr.   r   c                  $    e Zd Zd Zd Zd Zd Zy)Testc                    g d}d}|D cg c]  }t        |       }}| j                  t        |      |       y c c}w )N)IIbIciiiibiiciiiiiibiiicIVIVbIVcVVbVcvivibvicviioviiobviioc)rS   I6I64rV   ii6ii64rY   iii6iii64r\   IV6IV64r_   V6V64rb   vi6vi64re   viio6viio64r-   assertEqualtuple)rB   
harmTriadsgroundTruthxromanTriadss        r,   
testTriadszTest.testTriads   sH    


 7AAj)!,jA{+[9 B   ;c                    g d}d}|D cg c]  }t        |       }}| j                  t        |      |       y c c}w )N)I7I7bI7cI7dii7ii7bii7cii7diii7iii7biii7ciii7dIV7IV7bIV7cIV7dV7V7bV7cV7dvi7vi7bvi7cvi7dviio7viio7bviio7cviio7d)r   I65I43I2r   ii65ii43ii2r   iii65iii43iii2r   IV65IV43IV2r   V65V43V2r   vi65vi43vi2r   viio65viio43viio2rv   )rB   harmSeventhsrz   r{   romanSeventhss        r,   testSeventhszTest.testSevenths
  sH    

 9EE1+A.E}-{; Fr~   c                    g d}d}|D cg c]  }t        |       }}| j                  t        |      |       y c c}w )N)NNbNcr
   LtbLtcr   FrbFrcFrdr   GnbGncGnd)r   N6N64r   It6It64Fr7Fr65Fr43Fr2Ger7Ger65Ger43Ger2rv   )rB   harmSpecialChordsrz   r{   romanSpecialChordss        r,   testSpecialChordszTest.testSpecialChords   sM    

 >OO=N03=NO12K@ Pr~   c                    g d}d}|D cg c]  }t        |       }}| j                  t        |      |       y c c}w )N)z-IIbz--IIc#IV7z##IV7b)z-II6z--II64r   z##IV65rv   )rB   harmAlterationsrz   r{   romanAlterationss        r,   testAlterationszTest.testAlterations0  sJ    

 <KK?a.q1?K/0+> Lr~   N)r1   r2   r3   r}   r   r   r   r9   r.   r,   rQ   rQ      s    :.<,A ?r.   rQ   __main__)r4   
__future__r   r<   typingtunittestr-   r0   r   TestCaserQ   r1   music21mainTestr9   r.   r,   <module>r      so   
 # 	  ^GBM M`( (VG?8 G?T zGT r.   