
    rh*|                       % S r SSKJr  SSKrSSKJr  SSKrSSKrSSKJ	r	  SSK
Jr  SSKJr  SSKJr  SS	KJr  SS
KJr  SSKJr  SSKJr  SSKJr  \R&                  " S5      rS r " S S\R,                  5      r " S S5      r " S S\R2                  5      r " S S\R2                  5      r/ rS\S'   \S:X  a  SSKr\R>                  " \5        gg)zK
Automatically reduce a MeasureStack to a single chord or group of chords.
    )annotationsN)Sequence)chord)DocOrder)exceptions21)environment)meter)note)pitch)stream)treereduceChordsc                 &   [         R                  " 5       n [        R                  " S5      n[        R
                  " S5      nSUl        [        R
                  " S5      n[        R
                  " S5      nXX44 H  nU R                  U5        M     U $ )a  
returns a simple measure stream for testing:

>>> s = analysis.reduceChords.testMeasureStream1()
>>> s.show('text')
{0.0} <music21.meter.TimeSignature 4/4>
{0.0} <music21.chord.Chord C4 E4 G4 C5>
{2.0} <music21.chord.Chord C4 E4 F4 B4>
{3.0} <music21.chord.Chord C4 E4 G4 C5>
z4/4C4 E4 G4 C5       @C4 E4 F4 B4)r   Measurer	   TimeSignaturer   ChordquarterLengthappend)measuretimeSignaturechord1chord2chord3elements         W/home/james-whalen/.local/lib/python3.13/site-packages/music21/analysis/reduceChords.pytestMeasureStream1r   %   sr     nnG''.M[['FF[['F[['F!6:w ;N    c                      \ rS rSrSrg)ChordReducerException=    N)__name__
__module____qualname____firstlineno____static_attributes__r$   r    r   r"   r"   =   s    r    r"   c                      \ rS rSrSrS r    SS jr\S 5       r\SS j5       r	S r
S	 rS
 r SS jrS rS rS rS rS rS rS r   SS jrS rSS jr   SS jrS rS rSrg) ChordReducer@   z
A chord reducer.
c                P    U R                   U l        SU l        S U l        S U l        g )N   )qlbsmpConsonanceweightAlgorithm	maxChordspositionInMeasurenumberOfElementsInMeasure)selfs    r   __init__ChordReducer.__init__D   s'    #44!%)-&r    Nc                2   [        U[        R                  5      (       d  [        S5      eUbd  [	        S U 5       5      (       d  [        S5      e/ nU H/  nU R                  UR                  5      nUR                  U5        M1     [        U5      nUbd  [	        S U 5       5      (       d  [        S5      e/ nU H/  nU R                  UR                  5      nUR                  U5        M1     [        U5      n[        R                  R                  US[        R                  [        R                  4S9n	U R!                  U	5        U R#                  U	5        U R%                  U	UUS9  U	R'                  5       n
U R)                  X5        U R+                  XS	S
9  U R)                  X5        U R-                  X5        U R+                  XSS
9  U R)                  X5        U R-                  X5        [        R                  " 5       nSS KnUR1                  5          UR3                  S[4        R6                  S9  [        R8                  R;                  U	US9nS S S 5        [        R<                  " 5       nWR?                  [        R@                  5       H0  nU RC                  UUU RD                  SS9nUR                  U5        M2     UR                  U5        U(       a*  U[        R                      H  nURG                  SSS9  M     U$ ! , (       d  f       N= f)Nz Must be called on a stream.Scorec              3  V   #    U  H  n[        U[        R                  5      v   M!     g 7fN
isinstancer   r   .0xs     r   	<genexpr>#ChordReducer.run.<locals>.<genexpr>T        K?az!U[[11?   ')z"All allowableChords must be Chordsc              3  V   #    U  H  n[        U[        R                  5      v   M!     g 7fr9   r:   r<   s     r   r?   r@   ]   rA   rB   z"All forbiddenChords must be ChordsT)flatten	classList)	scoreTreeallowableChordsforbiddenChords      ?)duration      ?r   ignore)category)templateStream      ?)maximumNumberOfChordsr0   	trimBelow   )forceOctaveinPlace)$r;   r   Scorer"   all_getIntervalClassSetpitchesr   	frozensetr   
fromStreamasTimespansr
   Noter   r   removeZeroDurationTimespanssplitByBassremoveVerticalDissonancestoPartwiseTimespanTreesfillBassGapsremoveShortTimespansfillMeasureGapswarningscatch_warningssimplefilterr   Music21DeprecationWarningtoStream
chordifiedPartgetElementsByClassr   reduceMeasureToNChordsr/   closedPosition)r4   
inputScorerG   rm   rH   rP   intervalClassSetsr>   intervalClassSetrF   partwiseTrees	reductionrd   chordifiedReductionchordifiedPartr   reducedMeasures                    r   runChordReducer.runJ   s    *fll33'(JKK&K?KKK+,PQQ "$#'#<#<QYY#G !(()9: % ((9:O&K?KKK+,PQQ "$#'#<#<QYY#G !(()9: % ((9:OOO//yy%++. 0 0	
 	((3#&&7F7F 	' 	H "99;)3!!)S!I)3Y6!!)S!I)3Y6LLN	 	$$&!!(\5[5[!\"&--":":) #; # '  *==fnnMG!88&; $ 5 5	 9 N !!.1 N 	(u{{+  Q = , + '&s   =L
Lc                    U R                  5       R                  5        H\  u  p[        U5        U H  n[        SU5        M     UR                  5       nUS:  d  M=  [        U5        [        R
                  " S5      e   g )N	   zmaximumOverlap is exceeded)r`   itemsprintmaximumOverlapr   Music21Exception)rF   partsubtreetimespanoverlaps        r   _debugChordReducer._debug   sn    &>>@FFHMD$K#dH% $,,.G!|d"330  Ir    c                   [        5       n/ nU  HZ  n[        U[        R                  5      (       a  UR	                  U5        M5  UR	                  [        R                  " U5      5        M\     [        U5       H_  u  pEX$S-   S  HO  n[        [        UR                  UR                  -
  5      5      nUS-  nUS:  a  SU-
  nUR                  U5        MQ     Ma     SU;   a  UR                  S5        [        U5      $ )z
Return a frozenset of all the interval classes (1-6) in the given
Sequence (list, tuple, etc.) of pitches or
things like strings/ints that can be passed to the Pitch constructor.
rz   N      r   )setr;   r   Pitchr   	enumerateintabspsaddremoverY   )
pitches_inresultrX   pir>   yinterval_ints           r   rW   !ChordReducer._getIntervalClassSet   s     5%'A!U[[))q!u{{1~.	  g&DAUV_"3qttadd{#34"1$#%#4L

<( % ' ;MM!  r    c              #  d  #    [         R                  " 5       n[        R                  [        R
                  [        R                  4nUR                  5        HT  n[        XC5      (       d  M  UR                  U5        [        U5      S:X  d  M7  [        U5      v   UR                  5         MV     g 7f)N   )collectionsdequer   r   r
   r\   RestrD   r;   r   lentuplepopleft)r4   inputStreamelementBuffer	prototyper   s        r   _iterateElementsPairwise%ChordReducer._iterateElementsPairwise   s     #))+KKIIII
	
 #**,Gg11  )=!Q&M**%%' -s   BB0"B0c                   UR                  SS9 GHv  nUu  p4UR                  nUR                  nUR                  (       a  UR                  (       d  MD  UR                  UR                  :w  a  M`  UR                  UR                  :X  a  M|  UR	                  U5      (       aa  UR
                   HO  nUR                  U5        UR                  UR                  S9nUR                  Ul	        UR                  U5        MQ     M  UR	                  U5      (       d  GM  UR
                   HZ  nUR                  UR                  :  d  M  UR                  U5        UR                  UR                  S9nUR                  U5        M\     GMy     g)z)
Aligns hockets between parts in `tree`.
r   noffsetendTimeN)iterateVerticalitiesNwisepitchSetisConsonantmeasureNumberissubsetstartTimespansremoveTimespannewr   beatStrengthinsertr   )	r4   rF   verticalitiesverticalityOneverticalityTwopitchSetOnepitchSetTwor   newTimespans	            r   alignHocketsChordReducer.alignHockets   sX    '@@1@EM-:*N(11K(11K"..)55++~/K/KK&&.*A*AA##K00 . = =H,,X6"*,,-44 #/ #K 0>/J/JK,$$[1 !> %%k22 . = =H''.*?*??!00:&.ll$2$9$9 '3 ' "((5 !>) Fr    c           	     l   UR                  SS9 GH  nUu  p4UR                  (       a  UR                  (       d  M,  [        UR                  5      n[        UR                  5      nUS   R                  US   R                  :w  a  Mx  UR                  UR                  :w  a  M  [        5       nUR                  U Vs/ s H  oR                  PM     sn5        UR                  U Vs/ s H  oR                  PM     sn5        [        U Vs/ s H  n[        R                  " U5      PM     sn5      nUR                  U5      n	U	R                  5        H  u  p[        U5      S:  a  M  [        S U 5       5      (       d  M/  US   R                  US   R                  :X  a  MQ  US   R                  US   R                  -   n[        R                  " U5      nUR!                  U5        US   R#                  UUS   R$                  S9nUR'                  U5        M     GM     gs  snf s  snf s  snf )aH  
Collapses arpeggios in `tree`.

>>> m = stream.Measure([chord.Chord('C4 E4'), chord.Chord('C4 G4')])
>>> cr = analysis.reduceChords.ChordReducer()
>>> spans = m.asTimespans(classList=(note.NotRest,))
>>> len(spans)
2
>>> cr.collapseArpeggios(spans)
>>> len(spans)
1

OMIT_FROM_DOCS

Ensure it doesn't crash without a class filter:

>>> s = corpus.parse('beach')
>>> cr2 = analysis.reduceChords.ChordReducer()
>>> excerpt_tree = s.parts.first().asTimespans()
>>> cr2.collapseArpeggios(excerpt_tree)
>>> excerpt_tree
<TimespanTree {163} (0.0 to 124.0) <music21.stream.Part Soprano I>>
r   r   r   c              3  j   #    U  H)  n[        U[        R                  R                  5      v   M+     g 7fr9   )r;   r   spansPitchedTimespanr<   s     r   r?   1ChordReducer.collapseArpeggios.<locals>.<genexpr>+  s&     ]P\1Z4::+E+EFFP\s   13rz   )r   r   N)r   r   sortednameWithOctaver   r   updater   r   unwrapVerticalitiesr{   r   rV   rX   r   r   removeTimespanListr   r   r   )r4   rF   r   onetwo
onePitches
twoPitchesbothPitchesr>   horizontalitiesunused_parttimespanListsumChordmergeds                 r   collapseArpeggiosChordReducer.collapseArpeggios   s   0 '@@1@EM$HC<<s||-J-J!}++z!}/K/KK""c&7&77 %K*E*Q 0 0*EF*E*Q 0 0*EF +!F+Q%++a.+!FGK (;;MJO-<-B-B-D)|$q(]P\]]]!!_,,Q0G0GG*1o55Q8O8OO ;;{3,,\:%a,,$(O33 -    ( .E9 F  FE!Fs   =H'
(H,
 H1
c                   Uc  U R                   n0 nSU l        [        U5      U l        [	        U5       H  u  pEX@l        UR
                  (       a   [        UR                  R                  5      nO/[        UR                   Vs1 s H  owR                  iM     sn5      nXc;  a  SX6'   X6==   U" U5      -  ss'   M     SU l        SU l        U$ s  snf )a  
Compute measure chord weights:

>>> s = analysis.reduceChords.testMeasureStream1().notes
>>> cr = analysis.reduceChords.ChordReducer()
>>> cws = cr.computeMeasureChordWeights(s)
>>> for pcs in sorted(cws):
...     print("%18r  %2.1f" % (pcs, cws[pcs]))
    (0, 4, 7)  3.0
(0, 11, 4, 5)  1.0

Add beatStrength:

>>> cws = cr.computeMeasureChordWeights(s,
...     weightAlgorithm=cr.quarterLengthBeatStrength)
>>> for pcs in sorted(cws):
...     print("%18r  %2.1f" % (pcs, cws[pcs]))
    (0, 4, 7)  2.2
(0, 11, 4, 5)  0.5

Give extra weight to the last element in a measure:

>>> cws = cr.computeMeasureChordWeights(s,
...     weightAlgorithm=cr.quarterLengthBeatStrengthMeasurePosition)
>>> for pcs in sorted(cws):
...     print("%18r  %2.1f" % (pcs, cws[pcs]))
    (0, 4, 7)  3.0
(0, 11, 4, 5)  0.5

Make consonance count a lot:

>>> cws = cr.computeMeasureChordWeights(s,
...     weightAlgorithm=cr.qlbsmpConsonance)
>>> for pcs in sorted(cws):
...     print("%18r  %2.1f" % (pcs, cws[pcs]))
     (0, 4, 7)  3.0
 (0, 11, 4, 5)  0.1
r           )
quarterLengthOnlyr2   r   r3   r   isNoter   r   
pitchClassrX   )r4   measureObjectr0   
presentPCsr   cr   r>   s           r   computeMeasureChordWeights'ChordReducer.computeMeasureChordWeights8  s    V ""44O
!"),]);&m,DA%&"xx!'',,-;A<<;<" #
M_Q//M - "#)*& <s   C
c                (  ^ U4S jnUR                  5        GH  u  pE[        U5      n[        R                  " Xc5       GH  u  px[        U5      n	Uc  M  UR                  U	S   R                  :  Ga@  UR
                  R                  n
UR                  nTR                  U	S   5      nUb  UR                  U	S   R                  :  ao  S[        UR                  5      -   S-   [        U	S   R                  5      -   S-   [        U5      -   S-   [        U	5      -   S-   [        U	S   5      -   n[        U5        [        XR                  5      nTR                  U	S   5        UR                  U	S   5        U	S   R                  US9nXl        TR                  U5        UR                  U5        XS'   U	S	   R                  UR                  :  al  UR                  nTR                  U	S	   5        UR                  U	S	   5        U	S	   R                  US
9nTR                  U5        UR                  U5        XS	'   [!        [#        U	5      S-
  5       H  nU	U   U	US-      nnUR$                  UR$                  :X  d  UR                  UR                  :w  d  MF  UR                  UR                  S
9nXU'   XUS-   '   TR'                  UU45        UR'                  UU45        TR                  U5        UR                  U5        M     GM     GM     g )Nc                R   > TR                  U R                  5      nUR                  $ r9   )getVerticalityAtr   bassTimespan)r   verticalityrF   s     r   	procedure,ChordReducer.fillBassGaps.<locals>.procedurev  s#    #44X__EK+++r    r   z2Timespan offset errors: previousTimespan.endTime, z should be before z previousTimespan: z	 groups: z group[0]: r   r   rz   )r{   list	itertoolsgroupbyr   r   r   .findPreviousPitchedTimespanInSameStreamByClassr   strreprr|   maxr   r   r   ranger   rX   r   )r4   rF   rq   r   r   r   r   r   group_generatorgroupr   r   previousTimespanmsgr   r   r   timespanOnetimespanTwos    `                 r   ra   ChordReducer.fillBassGapsu  s   	, %2$7$7$9 K=L1:1B1B<1[-_-'&&q8#/#7#7#D#DL)00F'0'_'_a($ (3+33eAhooE T"%&6&>&>"?!@"6!79<U1X__9M!N #8!8 ;??O:P!Q #.	!. 15U	!<
 #0!0
 37uQx.!A   "#J!$V-E-E!F,,U1X6**584"'(,,f,"=K/;,$$[1NN;/*!H9$$|';';;*22G,,U2Y7**595"')-- ' #0 #K $$[1NN;/ +"Is5zA~.A/4Qxq1uK#++{/B/BB*22k6H6HH&1ook>Q>Qo&R#.a'2a!e!44k;5OP22K3MN!((5{3 /[ 2\ %:r    c                   UR                  5        GH,  u  p4[        5       n[        5       n[        R                  " US 5       GH  u  px[	        U5      n	[        [        U	5      S-
  5       H  n
X   XS-      pUR                  UR                  :X  d  UR                  UR                  :w  d  MC  UR                  UR                  S9nXU
'   XU
S-   '   UR                  U5        UR                  U5        UR                  U5        M     U	S   R                  U	S   R                  :w  aO  U	S   R                  U	S   R                  S9nSUl        UR                  U	S   5        UR                  U5        XS'   U	S   R                  U	S   R                  :w  d  GMX  U	S   R                  U	S   R                  S9nUR                  U	S   5        UR                  U5        XS'   GM     UR                  U5        UR!                  U5        UR#                  U5        UR!                  U5        UR#                  U5        GM/     g)	z
Fills measure gaps in `tree`.
c                    U R                   $ r9   )r   )r>   s    r   <lambda>.ChordReducer.fillMeasureGaps.<locals>.<lambda>  s    1??r    rz   r   r   r   rK   r   N)r{   r   r   r   r   r   r   rX   r   r   r   r   parentOffsetr   parentEndTimedifference_updater   r   )r4   rF   rq   r   r   toRemovetoInsertunused_measureNumberr   r   r   r   r   r   s                 r   rc   ChordReducer.fillMeasureGaps  s    %2$7$7$9 KuHuH9B9J9J2:5$ _-s5zA~.A/4x1u#++{/B/BB*22k6H6HH&1ook>Q>Qo&R#.a'2a!e [1 [1 [1 / 8??eAh&;&;;"'(,,eAh6K6K,"LK/2K,LLq*LL-*!H9$$b	(?(??"')-- %b	 7 7 #0 #K LLr+LL- +"I7:< &&x0X&((2NN8$&&x0K %:r    c                @   S nUR                  5       nXB   n[        U5      n[        R                  " Xc5       Hb  u  px[        U5      n[	        U5      S:X  a  M!  UR                  U5        US   R                  US   R                  S9n	UR                  U	5        Md     g )Nc                8    U R                   nU R                  nX4$ r9   )r   rX   )r   r   rX   s      r   r   3ChordReducer.fuseTimespansByPart.<locals>.procedure  s!    $22M&&G ))r    rz   r   r   r   )	r`   r   r   r   r   r   r   r   r   )
r4   rF   r   r   mappingr   r   
unused_keyr   r   s
             r   fuseTimespansByPart ChordReducer.fuseTimespansByPart  s    	*
 335-G}!*!2!2<!KJKE5zQ((/(,,b	)) ' K [) "Lr    c                    UR                  5       (       a  SOSnU R                  U R                  S-
  :X  a  UR                  nOU R	                  U5      nX2-  nU$ )z(
Everything from before plus consonance
rK   g?rz   )r   r2   r3   r   (quarterLengthBeatStrengthMeasurePosition)r4   chordObjectconsonanceScoreweights       r   r/   ChordReducer.qlbsmpConsonance  sZ     "-!8!8!:!:#!!T%C%Ca%GG ..FBB;OF!r    c                8    UR                   UR                  -  nU$ r9   )r   r   )r4   r  r
  s      r   quarterLengthBeatStrength&ChordReducer.quarterLengthBeatStrength  s    **[-E-EEr    c                v    U R                   U R                  S-
  :X  a  UR                  $ U R                  U5      $ )Nrz   )r2   r3   r   r  r4   r  s     r   r  5ChordReducer.quarterLengthBeatStrengthMeasurePosition  s8    !!T%C%Ca%GG,,,11+>>r    c                    UR                   $ r9   )r   r  s     r   r   ChordReducer.quarterLengthOnly  s    (((r    c                   U R                  UR                  5       R                  U5      n[        U[	        U5      5      n[        UUR                  SS9nUSU nU(       d^  [        R                  " 5       nUR                  R                  Ul
        U H  n	UR                  U	5        M     UR                  SU5        U$ XWS      n
/ nU H   nX\   X-  :  a  UR                  U5        M     O   SnSnSnU GHD  n	[        U	[        R                  5      (       a   [!        U	R"                  R$                  5      nOR[        U	[&        R(                  5      (       a1  [!        U	R*                   Vs1 s H  nUR$                  iM     sn5      nOM  UU;   a  UU:w  a  Uc$  U	R,                  S:w  a  U	R,                  nSU	l        OUb  Xl
        SnU	nU	 H7  nUR"                  R.                  c  M  SUR"                  R.                  l        M9     UnXR                  -  nGM%  XR                  -  nUR                  U	5        GMG     Ub  Xl
        [3        S[	        U5      5       Hv  nUU   n	U	R,                  nU[5        U5      -
  n[7        US5      S;   d  M4  UUS-
     nU=R                  U-  sl
        [5        U5      U	l        U	=R                  U-  sl
        Mx     U$ s  snf )	a  
Reduces measure to `n` chords:

>>> s = analysis.reduceChords.testMeasureStream1()
>>> cr = analysis.reduceChords.ChordReducer()

Reduce to a maximum of 3 chords; though here we will only get one
because the other chord is below the trimBelow threshold.

>>> newS = cr.reduceMeasureToNChords(s, 3,
...     weightAlgorithm=cr.qlbsmpConsonance,
...     trimBelow=0.3)
>>> newS.show('text')
{0.0} <music21.meter.TimeSignature 4/4>
{0.0} <music21.chord.Chord C4 E4 G4 C5>

>>> newS[-1].quarterLength
4.0
T)keyreverseNr   r   rz   r.   )rO   g      ?gZd;O?gT㥛 ?gX9v?)r   rD   notesminr   r   getr
   r   rJ   r   r   r   r   r;   r\   r   r   r   r   r   rX   r   
accidentaldisplayStatusr   r   round)r4   r   rP   r0   rQ   chordWeightssortedChordWeights
maxNChordsrr   maxChordWeighttrimmedMaxChordspcTuplescurrentGreedyChordcurrentGreedyChordPCscurrentGreedyChordNewLengthr   r>   r   r   cOffsetCurrentcOffsetSyncoplastCs                          r   rl   #ChordReducer.reduceMeasureToNChords  s   > 66!!#))
 !$$93|;L M#  

 ((>)>?
		A+44BBAO"$$Q' #  A&  %m4"H%)CC ''1	 #
 " $&)#A!TYY''!'',,-Au{{++;A1<<;<$$.C)C%-!((c/23((/"AH'37R425/%&"Aww))5;?**8  )*%+>++>+$$Q'1 2 )/J, q#m,-Aa AXXN*S-@@M]A&*MM%a!e,##}4#~.=0 . G <s   +K
c                   UR                  SS9 H  nUR                  U5      nUR                  5        H  u  pEUR                  (       d  UR                  (       d  M)  US   R
                  US   R
                  :w  a  MK  US   R                  US   R                  S9nUR                  US   US   45        UR                  U5        M     M     g)zF
Removes timespans containing passing and neighbor tones from `tree`.
r.   r   r   rz   r   N)
r   r   r{   hasPassingTonehasNeighborToner   r   r   r   r   )r4   rF   r   r   r   horizontalityr   s          r   removeNonChordTones ChordReducer.removeNonChordTonesr  s     '@@1@EM';;MJO.=.C.C.E*%44 - = ="1%33}Q7G7U7UU&q)--mA6F6N6N-O,,mA.>a@P-QR  ( /F Fr    c                D  ^^ UU4S jnUR                  5        GH  u  pV/ n[        R                  " Xd5       GH=  u  pUu  pn[        U	5      n	U(       d  M  SnU	S   R                  U	S   R
                  :X  a"  U	S   R                  U	S   R                  :X  a  SnUb<  U	S   R                  UR                  :X  a  U	S   R                  UR                  :X  a  SnU(       a  [        R                  " 5       nU	 H#  nXR                  ==   UR                  -  ss'   M%     UR                  5       S   u  nnU	 H&  nUR                  U:w  d  M  UR                  U5        M(     GM,  UR                  U	5        GM@     TR                  U5        UR                  U5        GM     g)z
Removes timespans in `tree` shorter than `duration`.

Special treatment is given to groups of short timespans if they take up
an entire measure. In that case, the timespans with the most common
sets of pitches are kept.
c                   > U R                   nU R                  T:  nTR                  U R                  5      nUR                  nUb  UR                  T:  a  S nXU4$ r9   )r   r   r   r   r   )r   r   proc_isShortr   proc_bassTimespanrJ   rF   s        r   r   4ChordReducer.removeShortTimespans.<locals>.procedure  sd    $22M#11H<L#44X__EK + 8 8 ,$22X=(,% 0AAAr    Fr   r   TN)r{   r   r   r   r   r   r   r   r   CounterrX   r   most_commonr   extendr   )r4   rF   rq   rJ   r   r   r   timespansToRemover  r   r   isShortr   isEntireMeasurecountergroup_timespanbestPitchesunused_totalDurations    ` `              r   rb   !ChordReducer.removeShortTimespans  sv   	B %2$7$7$9 K "'//C
>A;$|U"'8??eAh&;&;;Ry((E!H,B,BB*.+Qx,*=*== 9,,0D0DD.2O")113G*/ 6 67>;W;WW7 +08?8K8K8Ma8P5K!5*/)11[@-44^D +0 &,,U3- D. (():;&&'895 %:r    c                   UR                  5        H  nSnUR                  nU R                  U5      nU(       a  Xr;   a  SnUR                  5       R	                  5       (       a  SnU(       a  Xs;   a  SnU(       a  Ml  UR                  n[        U5      n	UR                   H/  n
[        U
R                  5      U	:w  d  M  UR                  U
5        M1     M     g)zy
Removes timespans in each dissonant verticality of `tree` whose pitches
are above the lowest pitch in that verticality.
FTN)	iterateVerticalitiesr   rW   toChordr   r  r   rX   r   )r4   rF   rG   rH   r   r   rX   rp   r   lowestPitchr   s              r   r_   &ChordReducer.removeVerticalDissonances  s     %99;KK!**G#88A#3#F"""$0022"#3#F#"++Hh-K'66x''(K7,,X6 7# <r    c                v    U Vs/ s H  o"R                   S:X  d  M  UPM     nnUR                  U5        g s  snf )Nr   )r   r   )r4   rF   r>   zeroDurationTimespanss       r   r]   (ChordReducer.removeZeroDurationTimespans  s5    ,5 NIqA9MI N$$%:; !Os   66c                    UR                  5       nU H  nU R                  X5        M     UR                  5       nUS   nXE   nUR                  5       nUR	                  U5        g )Nr   )allPartsr  r`   
allOffsetssplitAt)r4   rF   partsr   r  bassPartbassTreebassOffsetss           r   r^   ChordReducer.splitByBass  sc    ""$D$$Y5 3359$))++&r    )r1   r3   r2   r0   )NFNr.   )r   z!Sequence[pitch.Pitch | str | int]returnzfrozenset[int]r9   )rz   NrO   )rI   )NNN)r%   r&   r'   r(   __doc__r5   rv   staticmethodr   rW   r   r   r   r   ra   rc   r  r/   r  r  r   rl   r/  rb   r_   r]   r^   r)   r$   r    r   r+   r+   @   s    . !  "#Od 
 
 ! !4( 6@B)N ;z>4@)1V*(?)  bH) ,:` 	7><'r    r+   c                      \ rS rSrS rSrg)Testi  c                    [         R                  " 5       n[        R                  " S5      nSUl        [        R                  " S5      n[        R                  " S5      nX#U4 H  nUR                  U5        M     g )Nr   r   r   )r   r   r   r   r   r   )r4   sc1c2c3r   s         r   testSimpleMeasureTest.testSimpleMeasure  sY    NN[['[['[['"AHHQK r    r$   N)r%   r&   r'   r(   r\  r)   r$   r    r   rV  rV    s    r    rV  c                      \ rS rSrSrS rSrg)TestExternali  Tc                0   SSK Jn  UR                  S5      R                  SS5      n[	        5       nUR                  U[        R                  " S5      4SS SS	9nU H  nUR                  SU5        M     U R                  (       a  UR                  5         g g )
Nr   )corpuszPMFC_06_Giovanni-05_Donnarz   
   z	F#4 A4 C5Tr.   )rG   rm   rH   rP   )
music21ra  parsemeasuresr+   rv   r   r   r   show)r4   ra  scorechordReducerrr   r   s         r   testTrecentoMadrigal!TestExternal.testTrecentoMadrigal  s    "89BB1bI $~ $$K(   "# % 
	 DLLD!  99JJL r    r$   N)r%   r&   r'   r(   rf  ri  r)   r$   r    r   r_  r_    s    Dr    r_  r   
_DOC_ORDER__main__) rS  
__future__r   r   collections.abcr   r   unittestrc  r   music21.common.typesr   r   r   r	   r
   r   r   r   EnvironmentenvironLocalr   r~   r"   r+   TestCaserV  r_  rk  __annotations__r%   mainTestr$   r    r   <module>rv     s    #  $    )         &&~60	L99 	[
' [
'B
8 
 8$$  J 
H  z\" r    