
    rh                   N   S r SSKJr  SSK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  \R                   (       a  SSK	Jr  \
R$                  " S5      r " S S\R(                  5      r " S S\R,                  5      r " S S\\R0                  5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      r " S S \5      r  " S! S"\5      r! " S# S$\5      r" " S% S&\5      r# " S' S(\5      r$ " S) S*\5      r%\" 5       \" 5       \" 5       \" 5       \ " 5       \!" 5       \"" 5       \#" 5       \$" 5       \%" 5       /
r&S?S+S,.S@S- jjjr'S+S,.S. jr(S+S/S0.S1 jr) " S2 S3\R,                  5      r* " S4 S5\RV                  \   5      r, " S6 S7\R,                  5      r- " S8 S9\R,                  5      r. " S: S;\R,                  5      r/ " S< S=5      r0\\\\\\\\ \!\"\#\$\%\0/r1\2S>:X  a  SSK	r	\	Rf                  " 5         gg)Aa  
This module provides the base class for all RepeatMark objects: entities that denote repeats.

Some RepeatMark objects are Expression objects; others are Bar objects. See for instance,
the :class:`~music21.bar.Repeat` which represents a normal barline repeat.
    )annotationsN)
StreamType)environment)exceptions21)expressions)prebase)spanner)stylestreamrepeatc                      \ rS rSrSrSrg)
RepeatMark*   as  
Base class of all repeat objects, including RepeatExpression objects and
Repeat (Barline) objects.

This object is used for multiple-inheritance of such objects and to filter by class in order
to get all things that mark repeats.

The RepeatMark is not itself a :class:`~music21.base.Music21Object` so you should use multiple
inheritance to put these things in Streams.

The following demonstration shows how a user might see if a Stream has any repeats in it.


>>> class PartialRepeat(repeat.RepeatMark, base.Music21Object):
...    def __init__(self, **keywords):
...        super().__init__(**keywords)

>>> s = stream.Stream()
>>> s.append(note.Note())
>>> s.append(PartialRepeat())
>>> repeats = s.getElementsByClass('RepeatMark')  # not a Music21Object, so use quotes
>>> if repeats:
...    print('Stream has %s repeat(s) in it' % (len(repeats)))
Stream has 1 repeat(s) in it
 N)__name__
__module____qualname____firstlineno____doc____static_attributes__r       H/home/james-whalen/.local/lib/python3.13/site-packages/music21/repeat.pyr   r   *   s    r   r   c                      \ rS rSrSrg)RepeatExpressionExceptionG   r   Nr   r   r   r   r   r   r   r   r   r   G       r   r   c                  r   ^  \ rS rSrSr\R                  rU 4S jrS r	S r
S rSS jrS rS	 rS
 rSrU =r$ )RepeatExpressionK   a  
This class models any mark added to a Score to mark
repeat start and end points that are designated by
text expressions or symbols, such as D.S. Al Coda, etc.

N.B. Repeat(Barline) objects are not RepeatExpression objects,
but both are RepeatMark subclasses.

This class stores internally a
:class:`~music21.expressions.TextExpression`. This object
is used for rendering text output in translation. A
properly configured TextExpression object can also be
used to create an instance of a RepeatExpressions.
c                   > [         TU ]  " S0 UD6  S U l        / U l        SU R                  l        SU l        SU R                  l        g )NcenterF   r   )super__init___textExpression_textAlternativesr
   justify	useSymbol	absoluteYselfkeywords	__class__s     r   r&   RepeatExpression.__init__\   sD    $8$#!#%

  "

r   c                    U R                  5       nUb   [        U5      S:  a  [        US S S-   5      $ Ub  [        U5      $ g)N   z... )getTextlenrepr)r-   contents     r   _reprInternalRepeatExpression._reprInternalj   sG    ,,.3w<"#4u,-- = r   c                .    U R                   R                  $ )z(
Get the text used for this expression.
)r'   r7   r-   s    r   r4   RepeatExpression.getTexts   s     ##+++r   c                    U R                   cG  [        R                  " U5      U l         U R                  U R                   l        U R	                  5         gXR                   l        g)zx
Set the text of this repeat expression.
This is also the primary way that the stored TextExpression object is created.
N)r'   r   TextExpressionr
   applyTextFormattingr7   r-   values     r   setTextRepeatExpression.setTexty   sM    
 '#.#=#=e#DD )-D  &$$&+0  (r   c                t    Uc  U R                   nUb%  U R                  R                  UR                  l        U$ )zQ
Apply the default text formatting to the text expression version of this repeat
)r'   r
   r)   )r-   tes     r   r?   $RepeatExpression.applyTextFormatting   s4     :%%B>#zz11BHH	r   c                    [        U[        R                  5      (       d  [        SU 35      eXl        U R                  5         g)z'
Directly set a TextExpression object.
z,must set with a TextExpression object, not: N)
isinstancer   r>   r   r'   r?   r@   s     r   setTextExpression"RepeatExpression.setTextExpression   sB     %!;!;<<+>ugFH H$  "r   c                ^    U R                   c  g[        R                  " U R                   5      $ )z<
Return a copy of the TextExpression stored in this object.
N)r'   copydeepcopyr;   s    r   getTextExpression"RepeatExpression.getTextExpression   s(     '==!5!566r   c                ^    S nU R                    H  nU" U5      nU" U5      nX:X  d  M    g   g)zT
Return True or False if the supplied text could be used for this RepeatExpression.
c                    U R                  5       n U R                  SS5      n U R                  SS5      n U R                  5       n U $ )N r3   .)stripreplacelower)ss    r   	stripText/RepeatExpression.isValidText.<locals>.stripText   s=    	A		#r"A		#r"A	AHr   TFr(   )r-   rA   rX   	candidates       r   isValidTextRepeatExpression.isValidText   s;    	 //I!),Ie$E!	 0
 r   )r(   r'   r*   N)r   r   r   r   r   r
   	TextStyle_styleClassr&   r8   r4   rB   r?   rI   rN   r\   r   __classcell__r/   s   @r   r    r    K   s@     //K",
1	#7 r   r    c                  ,   ^  \ rS rSrSrU 4S jrSrU =r$ )RepeatExpressionMarker   z
Some repeat expressions are markers of positions
in the score to jump to; these classes model those makers,
such as Coda, Segno, and Fine, which are subclassed below.
c                H   > [         TU ]  " S0 UD6  SU R                  l        g )Nr#   r   )r%   r&   r
   r)   r,   s     r   r&   RepeatExpressionMarker.__init__   s    $8$%

r   r   r   r   r   r   r   r&   r   ra   rb   s   @r   rd   rd      s    & &r   rd   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )Coda   zR
The coda symbol, or the word coda, as placed in a score.

>>> rm = repeat.Coda()
c                  > [         TU ]  " S0 UD6  SU R                  l        / SQU l        Ub/  U R                  U5      (       a  U R                  U5        SU l        g U R                  U R                  S   5        SU l        g )Nr#   )rj   zto Codazal CodaFr   Tr   )r%   r&   r
   r)   r(   r\   rB   r*   r-   textr.   r/   s      r   r&   Coda.__init__   sn    $8$%

!? 0 0 6 6LL"DNLL//23!DNr   r(   r*   r^   rh   rb   s   @r   rj   rj      s    " "r   rj   c                  ,   ^  \ rS rSrSrU 4S jrSrU =r$ )Segno   zU
The segno sign as placed in a score.

>>> rm = repeat.Segno()
>>> rm.useSymbol
True
c                   > [         TU ]  " S0 UD6  S/U l        U R                  U R                  S   5        SU l        g )Nrr   r   Tr   )r%   r&   r(   rB   r*   r,   s     r   r&   Segno.__init__   s;    $8$")T++A./r   rp   rh   rb   s   @r   rr   rr      s     r   rr   c                  ,   ^  \ rS rSrSrU 4S jrSrU =r$ )Fine   z=
The fine word as placed in a score.

>>> rm = repeat.Fine()
c                   > [         TU ]  " S0 UD6  S/U l        U R                  U R                  S   5        SU R                  l        g )Nfiner   rightr   )r%   r&   r(   rB   r
   r)   r,   s     r   r&   Fine.__init__   s@    $8$"(T++A./$

r   rZ   rh   rb   s   @r   rw   rw      s    % %r   rw   c                  ,   ^  \ rS rSrSrU 4S jrSrU =r$ )RepeatExpressionCommand   zu
Some repeat expressions are commands, instructing
the reader to go somewhere else. DaCapo and
related are examples.
c                V   > [         TU ]  " S0 UD6  SU l        SU R                  l        g )NFr{   r   )r%   r&   repeatAfterJumpr
   r)   r,   s     r   r&    RepeatExpressionCommand.__init__   s)    $8$$ %

r   )r   rh   rb   s   @r   r~   r~      s    
% %r   r~   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )DaCapoi	  z
The Da Capo command, indicating a return to the beginning
and a continuation to the end. By default,
`repeatAfterJump` is False, indicating that any repeats
encountered on the Da Capo repeat not be repeated.
c                   > [         TU ]  " S0 UD6  SS/U l        Ub(  U R                  U5      (       a  U R	                  U5        g U R	                  U R                  S   5        g )NzDa CapozD.C.r   r   r%   r&   r(   r\   rB   rm   s      r   r&   DaCapo.__init__  sY    $8$"+V!4 0 0 6 6LLLL//23r   rZ   r^   rh   rb   s   @r   r   r   	  s    4 4r   r   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )DaCapoAlFinei  a  
The Da Capo al Fine command, indicating a return to
the beginning and a continuation to the
:class:`~music21.repeat.Fine` object. By default,
`repeatAfterJump` is False, indicating that any
repeats encountered on the Da Capo repeat not
be repeated.

>>> rm = repeat.DaCapoAlFine()
c                   > [         TU ]  " S0 UD6  SS/U l        Ub(  U R                  U5      (       a  U R	                  U5        g U R	                  U R                  S   5        g )NzDa Capo al finezD.C. al finer   r   r   rm   s      r   r&   DaCapoAlFine.__init__%  Y    $8$"3^!D 0 0 6 6LLLL//23r   rZ   r^   rh   rb   s   @r   r   r     s    	4 4r   r   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )DaCapoAlCodai/  a_  
The Da Capo al Coda command, indicating a return
to the beginning and a continuation to the
:class:`~music21.repeat.Coda` object. The music
resumes at a second :class:`~music21.repeat.Coda`
object. By default, `repeatAfterJump` is False,
indicating that any repeats encountered on the
Da Capo repeat not be repeated.


>>> rm = repeat.DaCapoAlCoda()
c                   > [         TU ]  " S0 UD6  SS/U l        Ub(  U R                  U5      (       a  U R	                  U5        g U R	                  U R                  S   5        g )NzDa Capo al CodazD.C. al Codar   r   r   rm   s      r   r&   DaCapoAlCoda.__init__=  r   r   rZ   r^   rh   rb   s   @r   r   r   /  s    4 4r   r   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )AlSegnoiG  zW
Jump to the sign. Presumably a forward jump, not a repeat.

>>> rm = repeat.AlSegno()
c                   > [         TU ]  " S0 UD6  S/U l        Ub(  U R                  U5      (       a  U R	                  U5        g U R	                  U R                  S   5        g )Nzal Segnor   r   r   rm   s      r   r&   AlSegno.__init__M  sV    $8$", 0 0 6 6LLLL//23r   rZ   r^   rh   rb   s   @r   r   r   G  s    
4 4r   r   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )DalSegnoiV  z
The Dal Segno command, indicating a return to the segno
and a continuation to the end. By default, `repeatAfterJump`
is False, indicating that any repeats encountered on
the Da Capo repeat not be repeated.

>>> rm = repeat.DaCapoAlFine()
c                   > [         TU ]  " S0 UD6  SS/U l        Ub(  U R                  U5      (       a  U R	                  U5        g U R	                  U R                  S   5        g )Nz	Dal SegnozD.S.r   r   r   rm   s      r   r&   DalSegno.__init___  sY    $8$"-v!6 0 0 6 6LLLL//23r   rZ   r^   rh   rb   s   @r   r   r   V  s    4 4r   r   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )DalSegnoAlFineih  a  
The Dal Segno al Fine command, indicating a return to the
segno and a continuation to the :class:`~music21.repeat.Fine`
object. By default, `repeatAfterJump` is False, indicating
that any repeats encountered on the Dal Segno repeat not
be repeated.

>>> rm = repeat.DaCapoAlFine()
c                   > [         TU ]  " S0 UD6  SS/U l        Ub(  U R                  U5      (       a  U R	                  U5        g U R	                  U R                  S   5        g )NzDal Segno al finezD.S. al finer   r   r   rm   s      r   r&   DalSegnoAlFine.__init__r  Y    $8$"5~!F 0 0 6 6LLLL//23r   rZ   r^   rh   rb   s   @r   r   r   h  s    4 4r   r   c                  0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )DalSegnoAlCodai{  aa  
The Dal Segno al Coda command, indicating a return to the
beginning and a continuation to the :class:`~music21.repeat.Coda`
object. The music resumes at a second
:class:`~music21.repeat.Coda` object. By default,
`repeatAfterJump` is False, indicating that any repeats encountered
on the Da Segno repeat not be repeated.

>>> rm = repeat.DaCapoAlCoda()
c                   > [         TU ]  " S0 UD6  SS/U l        Ub(  U R                  U5      (       a  U R	                  U5        g U R	                  U R                  S   5        g )NzDal Segno al CodazD.S. al Codar   r   r   rm   s      r   r&   DalSegnoAlCoda.__init__  r   r   rZ   r^   rh   rb   s   @r   r   r   {  s    	4 4r   r   FinPlacec          	        U(       d  U R                  S5        U c  gU R                  5       (       d(  U R                   H  n[        XQX#SS9  M     U(       a  gU $ [	        XS-   5       Vs/ s H  o`R                  U5      PM     nn[        R                  " XsS9nUS   R                  U 5      n	U R                  X5        USL a  gU $ s  snf )a  
Designates a range of measures as being repeated endings (i.e. first and second endings)
within a stream s, where s either contains measures,
or contains parts which contain measures.  Start and end are integers
corresponding to the first and last measure
number of the "repeatNum" ending.  e.g. if start=6, end=7, and repeatNum=2,
the method adds a second ending
from measures 6 to 7.

Does not (yet) add a :class:`~music21.repeat.RepeatMark` to the end of the first ending.

Example: create first and second endings over measures 4-6 and measures 11-13 of a chorale,
respectively.


>>> c1 = corpus.parse('bwv10.7.mxl')
>>> repeat.insertRepeatEnding(c1,  4,  6, 1, inPlace=True)
>>> repeat.insertRepeatEnding(c1, 11, 13, 2, inPlace=True)

We now have 8 repeatBrackets since each part gets its own first and second ending.

>>> repeatBrackets = c1.flatten().getElementsByClass(spanner.RepeatBracket)
>>> len(repeatBrackets)
8
>>> len(c1.parts.first().getElementsByClass(spanner.RepeatBracket))
2
insertRepeatEndingNTr      )numberr   )
coreCopyAsDerivationhasMeasurespartsr   rangemeasurer	   RepeatBracketgetOffsetBySiteinsert)
rW   startendendingNumberr   partimeasuresrbrbOffsets
             r   r   r     s    : 	34y==??GGDtCtL H&+E7&;<&;		!&;H<			x	=B {**1-HHHX$ =s   *Cc                  U c  gU(       d  U R                  S5        U R                  5       (       d(  U R                   H  n[        XAUSS9  M     U(       a  gU $ SSKJn  UR                  SSS	9U R                  U5      l        US
:w  d  [        U 5      R                  5       S:w  a#  UR                  SS9U R                  U5      l        U(       a  gU $ )a  
Given a stream s, inserts a start-repeat at the beginning of the
bar specified by start and inserts an end-repeat at the bar specified
by barEnd. Only alters the stream s if inPlace=True.

>>> from copy import deepcopy
>>> chorale1 = corpus.parse('bwv10.7.mxl')
>>> s = repeat.insertRepeat(chorale1, 3, 6, inPlace=False)
>>> m4 = search.translateStreamToString( chorale1.parts[1].measure(4).notesAndRests)
>>> resm4 = search.translateStreamToString( s.parts[1].measure(4).notesAndRests)
>>> m6 = search.translateStreamToString( chorale1.parts[1].measure(4).notesAndRests)
>>> resm6 = search.translateStreamToString( s.parts[1].measure(4).notesAndRests)
>>> m7 = search.translateStreamToString( chorale1.parts[1].measure(4).notesAndRests)
>>> resm7 = search.translateStreamToString( s.parts[1].measure(4).notesAndRests)
>>> m4 == resm4
True
>>> m6 == resm6
True
>>> m7 == resm7
True

We should have 2 repeats in each part (a start and end) for a total of 8 repeats

>>> len(s.parts[0].flatten().getElementsByClass(bar.Repeat))
2
>>> len(s[bar.Repeat])
8
>>> s.parts[0].measure(3).leftBarline.direction
'start'
>>> s.parts[0].measure(6).rightBarline.direction
'end'

NinsertRepeatTr   r   barr      )	directiontimesr   r   )r   )r   r   r   r   music21r   Repeatr   rightBarlineRepeatFindergetQuarterLengthOfPickupMeasureleftBarline)rW   r   r   r   r   r   s         r   r   r     s    H 	y	~.==??GGDc48 H"%**uA*"FAIIcN z\!_DDF!K'*zzGz'D		%$r   Tr   correctMeasureNumbersc               ,   SSK Jn  U c  gU(       d  U R                  S5      n U R                  5       (       a2  U H+  n U R	                  U5      nUc  M  U R                  U5        M-     O)U R                   H  n[        UUSUS9  M     U(       a  gU $ U(       aV  [        U R                  UR                  5      5      nU(       a+  US   R                  n	U	S;  a  Sn	U H  n
Xl        U	S-  n	M     U(       a  gU $ ! [
        R                   a    Sn Nf = f)	af  
Given a Stream `s` and a list of numbers, toDelete, removes each measure
with a number corresponding to a number in toDelete and then renumbers
the remaining measures in the Stream.

TODO: Move to someplace more appropriate.

>>> from copy import deepcopy
>>> chorale1 = corpus.parse('bwv10.7.mxl')
>>> s = deepcopy(chorale1)
>>> repeat.deleteMeasures(s, [6, 3, 4], inPlace=True)
>>> m2 = search.translateStreamToString(chorale1.parts[1].measure(2).notesAndRests)
>>> resm2 = search.translateStreamToString(s.parts[1].measure(2).notesAndRests)
>>> m2 == resm2
True
>>> m5 = search.translateStreamToString(chorale1.parts[1].measure(5).notesAndRests)
>>> resm3 = search.translateStreamToString(s.parts[1].measure(3).notesAndRests)
>>> m5 == resm3
True
>>> m7 = search.translateStreamToString(chorale1.parts[1].measure(7).notesAndRests)
>>> resm4 = search.translateStreamToString(s.parts[1].measure(4).notesAndRests)
>>> m7 == resm4
True
>>> lenS = len(s.parts[0].getElementsByClass(stream.Measure))
>>> lenChorale1 = len(chorale1.parts[0].getElementsByClass(stream.Measure))
>>> lenS + 3 == lenChorale1
True

OMIT_FROM_DOCS

>>> chorale3 = corpus.parse('bwv102.7.mxl')
>>> s = repeat.deleteMeasures(chorale3, [2, 3])
>>> (len(s.parts[2].getElementsByClass(stream.Measure)) ==
...     len(chorale3.parts[2].getElementsByClass(stream.Measure)) - 2)
True
>>> s = repeat.deleteMeasures(chorale3, [2, 3])
>>> (len(s.parts[2].getElementsByClass(stream.Measure)) ==
...  len(chorale3.parts[2].getElementsByClass(stream.Measure)) - 2)
True
>>> s = repeat.deleteMeasures(chorale3, [999, 1001001])
>>> len(s.parts[2]) == len(chorale3.parts[2])
True
r   r   NdeleteMeasuresTr   r   r   r   )r   r   r   r   r   r   Music21Exceptionremover   r   listgetElementsByClassMeasurer   )rW   toDeleter   r   r   mNumberremoveMer   r   r   r   s              r   r   r     s   Z y""#34}}G 99W- #"   GGD4##'1FH 
 H ,,V^^<=""A #!"Q $ C  00   s   C::DDc                      \ rS rSrSrg)ExpanderExceptioni  r   Nr   r   r   r   r   r     r   r   r   c                      \ rS rSrSrSS jrSSS jjrS S jrS!S jrS"S jr	S r
S	 rS
 rS rS rS rS rS rS#S jrS rS r   S$S jr S%S jrS rS&S jrS'S jrS rSS/rSrg)(Expanderi  a	  
The Expander object can expand a single Part or Part-like Stream with repeats. Nested
repeats given with :class:`~music21.bar.Repeat` objects, or
repeats and sections designated with
:class:`~music21.repeat.RepeatExpression` objects, are all expanded.

This class is a utility processor. Direct usage is more commonly
from the :meth:`~music21.stream.Stream.expandRepeats` method.

To use this object directly, call :meth:`~music21.repeat.Expander.process` on the
score

>>> s = converter.parse('tinynotation: 3/4 A2. C4 D E F2.')
>>> s.makeMeasures(inPlace=True)
>>> s.measure(2).leftBarline = bar.Repeat(direction='start')
>>> s.measure(2).rightBarline = bar.Repeat(direction='end', times=3)
>>> s.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
    {0.0} <music21.clef.BassClef>
    {0.0} <music21.meter.TimeSignature 3/4>
    {0.0} <music21.note.Note A>
{3.0} <music21.stream.Measure 2 offset=3.0>
    {0.0} <music21.bar.Repeat direction=start>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.bar.Repeat direction=end times=3>
{6.0} <music21.stream.Measure 3 offset=6.0>
    {0.0} <music21.note.Note F>
    {3.0} <music21.bar.Barline type=final>

>>> e = repeat.Expander(s)
>>> e.repeatBarsAreCoherent()
True
>>> s2 = e.process()
>>> s2.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
    {0.0} <music21.clef.BassClef>
    {0.0} <music21.meter.TimeSignature 3/4>
    {0.0} <music21.note.Note A>
{3.0} <music21.stream.Measure 2 offset=3.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.bar.Barline type=double>
{6.0} <music21.stream.Measure 2a offset=6.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.bar.Barline type=double>
{9.0} <music21.stream.Measure 2b offset=9.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.bar.Barline type=double>
{12.0} <music21.stream.Measure 3 offset=12.0>
    {0.0} <music21.note.Note F>
    {3.0} <music21.bar.Barline type=final>

Changed in v9: Expander must be initialized with a Stream object.

OMIT_FROM_DOCS

TODO: Note bug: barline style = double for each!
Clefs and TimesSignatures should only be in first one!

THIS IS IN OMIT
c                   SSK Jn  Xl        U R                  R                  UR                  5      R                  5       U l        U R                  R                  5       R                  [        R                  5      R                  5       U l	        [        U R
                  5      U l        U R                  S:X  a  [        S5      eU R
                  R                  5       R                  [        5      R                  5       n[        UR                  [        5      5      U l        [        UR                  [         5      5      U l        [        UR                  [$        5      5      U l        [        UR                  [(        5      5      U l        [        UR                  [,        5      5      U l        [        UR                  [0        5      5      U l        [        UR                  [4        5      5      U l        [        UR                  [8        5      5      U l        [        UR                  [<        5      5      U l        [        UR                  [@        5      5      U l!        g )Nr   r   z5no measures found in the source stream to be expanded)"r   r   _srcr   r   _srcMeasureStreamflattenr	   r   _repeatBracketsr5   _srcMeasureCountr   r    rj   
_codaCountrr   _segnoCountrw   
_fineCountr   _dcCountr   
_dcafCountr   
_dcacCountr   _asCountr   _dsCountr   
_dsafCountr   
_dsacCount)r-   	streamObjr   reStreams       r   r&   Expander.__init__  s   " )	 AE		@\@\NNA

&( 	 II2273H3HIPPR 	 &))?)?%@  A%#$[\\
 ""**,??@PQXXZ 	 h99$?@x::5ABh99$?@H77?@h99,GHh99,GHH77@AH77ABh99.IJh99.IJr   c                :   U R                  5       nUSL a  [        S5      eUSLa  U R                  R                  S5      nOU R                  nUc  [        R
                  " [        U5      $ [        R                  " U R                  5      U l	        U H=  nU R                  R                  R                  UR                  R                  U5        M?     U R                  5       nUc  U R                  U5      nOU R!                  U5      nUR#                  U5        U$ )at  
This is the main call for Expander

Processes all repeats. Note that this processing only
happens for Measures contained in the given Stream.
Other objects in that Stream are neither processed nor copied.

if deepcopy is False then it will leave the stream in an unusual state, but acceptable if
the source stream has already been deep-copied and will be discarded later
Fz@cannot expand Stream: badly formed repeats or repeat expressionsexpandRepeats)isExpandabler   r   r   tcastr   rL   rM   r   spannerBundlereplaceSpannedElement
derivationorigin_daCapoOrSegno_processRecursiveRepeatBars"_processRepeatExpressionAndRepeatsmergeAttributes)r-   rM   	canExpand	srcStreammhasDaCapoOrSegnoposts          r   processExpander.process  s    %%'	#RT T
 5 ..CCOTI..I66*i00  $}}T-A-AB A  ..DD##Q(   ..0#33I>D::9ED
 	Y'r   c                B   SSK Jn  / n/ nU R                  5       nUn[        UR	                  UR
                  5      5       H?  u  pxUR                  UR                  5       5        UR                  UR                  5        MA     US:X  a  U$ 0 n	0 n
[        U R                  5       H%  u  pxXyUR                  5       '   XzUR                  '   M'     / n[        U5       H  u  p| UR                  X   5        M     U$ ! [         a    UR                  XU      5         MB  f = f)a  
returns a list where for each measure in the expanded stream, the index of the
measure in the original
stream is given.  if returnType = 'measureNumber' then the str(measureNumber)
of the original instead of the
index of the original is used -- suffixes are important here for endings etc..

Inefficient, because the entire stream is expanded before making this call,
rather than just seeing
what needs to be expanded and returning that.


>>> s = converter.parse('tinynotation: 3/4 A2.  C4 D E   F2.    G4 a b   c2.')
>>> s.makeMeasures(inPlace=True)
>>> s.measure(2).leftBarline = bar.Repeat(direction='start')
>>> s.measure(2).rightBarline = bar.Repeat(direction='end', times=3)
>>> s.measure(4).leftBarline = bar.Repeat(direction='start')
>>> s.measure(4).rightBarline = bar.Repeat(direction='end', times=2)
>>> e = repeat.Expander(s)
>>> e.measureMap()
[0, 1, 1, 1, 2, 3, 3, 4]
>>> e.measureMap(returnType='measureNumber')
['1', '2', '2a', '2b', '3', '4', '4a', '5']
r   r   measureNumber)r   r   r   	enumerater   r   appendmeasureNumberWithSuffixr   r   KeyError)r-   
returnTyper   measureNumberListmeasureNumberNoSuffixListr   measureContainingStreamsr   r   measureNumberDictmeasureNumberNoSuffixDict	indexListr  s                r   
measureMapExpander.measureMap0  s%   2 	#$&!||~#' 6II&..YZDA$$Q%>%>%@A%,,QXX6 [ ($$$&!d445DA=>a779:23ahh/ 6
 	*34E*F&AZ  !2!KL +G
   Z  !:UV;W!XYZs   !C:: DDc                    SSK Jn  UR                  nUR                  nUb&  SUR                  ;   a  UR                  U5      Ul        Ub(  SUR                  ;   a  UR                  U5      Ul        ggg)z}
Given a measure, strip barlines if they are repeats, and
replace with Barlines that are of the same style. Modify in place.
r   r   Nmusic21.bar.Repeat)r   r   r   r   classSetBarline)r-   r   newTyper   lbr   s         r   _stripRepeatBarlinesExpander._stripRepeatBarlinesg  sc     	 ]]^^>2bkkAKK0AM>2bkkA [[1AN B>r   c                .   SSK Jn  UR                  5       (       d  U/nO$[        UR	                  UR
                  5      5      nU HL  n/ nUR	                  [        5       H  nUR                  U5        M     U H  nUR                  U5        M     MN     g)zW
Given a Stream of measures or a Measure, strip all RepeatExpression
objects in place.
r   r   N)	r   r   r   r   r   r   r    r   r   )r-   r   r   mListr   r   es          r   _stripRepeatExpressions Expander._stripRepeatExpressionsv  s|    
 	#$$&&KE55fnnEFEAF))*:;a  < 	 r   c                L   SnSnSnU R                    H  nUR                  nUR                  nUbU  SUR                  ;   aE  UR                  S:X  a  US-  nUS-  nO*UR                  S:X  a  US:X  a
  US-  nUS-  nUS-  nUS-  nUc  Mx  SUR                  ;   d  M  UR                  S:X  a  US:X  a
  US-  nUS-  nUS-  nUS-  nM  [        SU SU 35      e   US;  a  [        R                  S	U 3/5        g
XUS-
  4;  a  [        R                  SU< SU< 3/5        g
g)zG
Check that all repeat bars are paired properly. Returns True or False
r   r  r   r   r   z3a right barline is found that cannot be processed: , r   z(Repeats are not balanced: countBalance: Fz'start count not the same as end count: z / T)r   r   r   r  r   r   environLocal
printDebug)r-   
startCountendCountcountBalancer   r  r   s          r   repeatBarsAreCoherentExpander.repeatBarsAreCoherent  sg    
''ABB~"6"++"E<<7*!OJ A%L\\U*#q("a
$)MH A%L~"6"++"E<<5( $q("a
$)MH A%L+MaSPRSURVW 3 (8 v%##'OP\~%^$_`155##H&& %' ( r   c                    U R                   U R                  -   U R                  -   nU R                  U R                  -   U R
                  -   U R                  -   nUS:X  a  US:X  a  [        $ US:X  a  US:X  a  [        $ g)z
Return a DaCapo object if this piece uses any form of DaCapo; return
a Segno object if this piece uses any form of Segno. Returns None if
incoherent or the piece uses neither.

r   r   N)	r   r   r   r   r   r   r   r   rr   )r-   sumDcsumDss      r   r   Expander._daCapoOrSegno  sw     /$//A??#??# ==!
 A:%1*MaZEQJLr   c                   U R                   S:X  a  gU R                  S:X  a  gU R                  S:X  a  gU R                  S:X  a  gU R                  S:X  a  gU R
                  S:X  a  gU R                  S:X  a  g[        S	5      e)
z
Return the class of the repeat expression command. This should
only be called if it has been determined that there is one
repeat command in this Stream.
r   r   r   r   r   r   r   r   zno repeat command found)r   r   r   r   r   r   r   r   r;   s    r   _getRepeatExpressionCommandType(Expander._getRepeatExpressionCommandType  sy     ==A__!!__!!]]a]]a__!#__!##$=>>r   c                d    UR                  5       R                  [        5      R                  5       $ )zC
Get the instance found in this stream; assumes that there is one.
)r   r   r~   first)r-   r   s     r   _getRepeatExpressionCommand$Expander._getRepeatExpressionCommand  s(       "556MNTTVVr   c                $   U R                   U R                  -   U R                  -   nUS:  a  gU R                   S:X  a  U R                  S:X  a  gU R                  S:X  a  U R                  S:X  a  gU R                  S:X  a  U R                  S:X  a  gg)z&
Check of a DC statement is coherent.
r   Fr   Tr   )r   r   r   r   r   )r-   r#  s     r   _daCapoIsCoherentExpander._daCapoIsCoherent  s    
 /$//A19 ==A$//Q"6 __!doo&: __!doo&: r   c                @   U R                   U R                  -   U R                  -   U R                  -   nUS:  a  gU R                   S:X  a!  U R                  S:X  a  U R
                  S:X  a  gU R                  S:X  a!  U R                  S:X  a  U R
                  S:X  a  gU R                  S:X  a1  U R
                  S:X  a!  U R                  S:X  a  U R                  S:X  a  gU R                  S:X  a1  U R
                  S:X  a!  U R                  S:X  a  U R                  S:X  a  gg)z,
Check of a sa segno statement is coherent.
r   Fr   Tr   )r   r   r   r   r   r   r   )r-   r$  s     r   _dalSegnoIsCoherentExpander._dalSegnoIsCoherent  s   
 ==!??# ??# 19 MMQ$$)OOq(MMQ$$)OOq( oo"OOq($$)OOq( oo"OOq($$)OOq( r   c                   / n[        [        U5      5      n/ n/ / S.nSnU[        U5      :  Ga  X   nU R                   H  nUR	                  U5      (       d  M  UR
                  S   U;   a  UR                  U5        / n/ / S.nXHR
                  -  nUS   R                  U5        UR                  5       n	U Hg  u  pX:  a.  [        U5      [        U	5      :w  a  US   R                  U
5        M8  [        U	5      [        U5      :X  d  MR  US   R                  U
5          M     M     US-  nU[        U5      :  a  GM  U(       a  UR                  U5        U$ )a  
Return a list of dictionaries that contains two
entries: one for all indices that are involved with
a collection of repeat bracket, and the repeat brackets
themselves.

This is used to handle when there are more than
one group of repeat brackets per Stream.


>>> s = converter.parse('tinynotation: 3/4 A2.  C4 D E   F2.    G4 a b   c2.')
>>> s.makeMeasures(inPlace=True)
>>> s.measure(2).leftBarline = bar.Repeat(direction='start')
>>> s.measure(2).rightBarline = bar.Repeat(direction='end', times=3)
>>> rb = spanner.RepeatBracket(s.measure(2))
>>> s.insert(0, rb)
>>> s.measure(4).leftBarline = bar.Repeat(direction='start')
>>> s.measure(4).rightBarline = bar.Repeat(direction='end', times=2)
>>> e = repeat.Expander(s)

>>> from pprint import pprint as pp
>>> pp(e._groupRepeatBracketIndices(s))
[{'measureIndices': [2],
  'repeatBrackets': [<music21.spanner.RepeatBracket
                          <music21.stream.Measure 2 offset=3.0>>]}]
)repeatBracketsmeasureIndicesr   r4  r5  r   )	r   r   r5   r   isFirstnumberRanger   getLastid)r-   r   groupsmEnumeratedfoundRBNumbersgroupIndicesr   r   r   mLastiSubmSubs               r   _groupRepeatBracketIndices#Expander._groupRepeatBracketIndices0  sP   8 9Y/0   
 #i. A** ::a==~~a(N:l3)+:<PR'S"nn4N !!1299"=JJLE&1
  9DRY)>()9:AA$GY"T(2()9:AA$G " '2! +@ FAG #i. H MM,'r   c           	        U R                  U R                  5       GHi  nUS   nU(       d    g[        U5      S:X  a  Ol[        U5      S:  a]  / nU H  nX4R                  -  nM     [	        [        S[        U5      S-   5      5      nXS:w  a  [        R                  SU SU 3/5          g/ n[        U5       H  u  ptUR                  5       nUR                  5        HF  n[        U5      U;   a  [        R                  S/5              gUR                  [        U5      5        MH     UR                  n	U	b  SU	R                  ;  d  M  [        U5      S:X  d  U[        U5      S-
  :  d  M  [        R                  S	/5            g   GMl     g)
zr
Check if repeat brackets are coherent.

This must be done for each group of brackets, not for the entire Stream.
r4  Tr   z0repeat brackets are not numbered consecutively: r  Fz!found overlapping repeat bracketsr   z8repeat brackets are not terminated with a repeat barline)rA  r   r5   r7  r   r   maxr  r  r   r8  getSpannedElementsr9  r   r   classes)
r-   group	rBracketstargetr   matchspannedMeasureIdsrbCountr   rightBars
             r   _repeatBracketsAreCoherent#Expander._repeatBracketsAreCoherent  s    44T5K5KLE ./I 9~"Y!##B
 nn,F $ U1c&kAo67? ++J5'QSTZS[\-^ _  "(3 JJL ..0A!u 11$//1T0UV$%,,RU3	 1 >>#xx7G7G'G I!+&Y!);;$//V1   %+  4? Mj r   c                    [        [        U5      5       H]  nX   nUR                  nUR                  nUb  SUR                  ;   a    gUc  M9  SUR                  ;   d  MK  UR
                  S:X  d  M]    g   g)zL
Return True if this Stream of Measures has a repeat
pair still to process.
r  Tr   F)r   r5   r   r   r  r   )r-   r   r   r   r  r   s         r   
_hasRepeatExpander._hasRepeat  sk     s9~&AABB ,;,;- ' r   c                *   / n/ n[        [        U5      5       H  nX   n UR                  nUR                  nUbg  SUR
                  ;   aW  UR                  S:X  a  UR                  U5        O5UR                  S:X  a%  U(       d  [        U5      n  Og[        US   U5      n  OVUc  M  SUR
                  ;   d  M  UR                  S:X  d  M  U(       d  [        US-   5      n  O[        US   US-   5      n  O   [        U5      $ ! [         a     M  f = f)a!  
Find the innermost repeat bars. Return raw index values.
For a single measure, this could be [2]
For many contiguous measures, this might be [2, 3, 4, 5]

The provided Stream must be a Stream only of Measures.


>>> s = converter.parse('tinynotation: 3/4 A2.  C4 D E   F2.    G4 a b   c2.')
>>> s.makeMeasures(inPlace=True)
>>> s.measure(2).leftBarline = bar.Repeat(direction='start')
>>> s.measure(2).rightBarline = bar.Repeat(direction='end', times=3)
>>> s.measure(4).leftBarline = bar.Repeat(direction='start')
>>> s.measure(4).rightBarline = bar.Repeat(direction='end', times=2)
>>> e = repeat.Expander(s)
>>> e.findInnermostRepeatIndices(s)
[1]

>>> s.measure(2).rightBarline = None
>>> s.measure(4).leftBarline = None
>>> e2 = repeat.Expander(s)
>>> e2.findInnermostRepeatIndices(s)
[1, 2, 3]
r  r   r   r   )	r   r5   r   r   AttributeErrorr  r   r   r   )r-   r   startIndicesbarRepeatIndicesr   r   r  r   s           r   findInnermostRepeatIndices#Expander.findInnermostRepeatIndices  s   4  s9~&AA]]^^ ~"6"++"E<<7* ''* \\U*'+08(+0b1A1+E(,;- $',QU|$',\"-=q1u'E$C 'D $%%9 " s   D
DDc                t   X   nUR                   nUb/  SUR                  ;   a  UR                  S:X  a  UnUR                  nOnU[	        U5      S-
  :  a  [        SU 35      eXS-      nUR                  nUb-  SUR                  ;   a  UR                  S:X  a  UR                  nO[        S5      eUc  SnX5U4$ )aJ  
Get the last measure to be processed in the repeat,
as well as the measure that has the end barline.
These may not be the same: if an end repeat bar is
placed on the left of a measure that is not actually
being copied.


The `index` parameter is the index of the last
measure to be copied. The streamObj must only have Measures.
r  r   r   z3cannot find an end Repeat bar after the given end: z6cannot find an end Repeat bar in the expected positionr   )r   r  r   r   r5   r   r   )r-   r   indexr>  r   mEndBarlinerepeatTimesr  s           r   _getEndRepeatBarExpander._getEndRepeatBar  s      N(BKK7LLE)K((K I**'I%QS S $AI.K((B,;- hh'(`aaK;..r   Nc                x   [         R                  nUR                  5       nSnUc  U R                  U5      nOSnSnSn	Sn
U	[	        U5      :  GaQ  U(       d   U$ XS   :X  a  SnSn U R                  UUS   5      u  pn
Uc  U
n[        U5       H  nU H~  n[        R                  " X   5      nXS   US   4;   a  U R                  U5        US:  a  XS-
  :  a  U R                  U5        US:w  a  X]S-
  S-     Ul        UR                  U5        M     M     XLa  SnUS   S-   n	OfU(       dZ  [        R                  " X   5      nX   nU(       a&  U R                  U5        U R                  X   5        SnUR                  U5        U	S-  n	U	[	        U5      :  a  GMQ  U$ ! [         a    U(       d  e  GN9f = f)	a  
Process and return a new Stream of Measures, likely a Part.

If `repeatIndices` are given, only these indices will be copied.
All the included indices must be listed, not just the start and end.

If `returnExpansionOnly` is True, only the expanded portion is
returned, the rest of the Stream is not retained.


>>> s = converter.parse('tinynotation: 3/4 A2.  C4 D E   F2.    G4 a b   c2.')
>>> s.makeMeasures(inPlace=True)
>>> s.measure(2).leftBarline = bar.Repeat(direction='start')
>>> s.measure(2).rightBarline = bar.Repeat(direction='end', times=3)
>>> s.measure(4).leftBarline = bar.Repeat(direction='start')
>>> s.measure(4).rightBarline = bar.Repeat(direction='end', times=2)

processInnermostRepeatBars only will expand the first set of repeats.

>>> e = repeat.Expander(s)
>>> s2 = e.processInnermostRepeatBars(s)
>>> s2.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
    {0.0} <music21.clef.BassClef>
    {0.0} <music21.meter.TimeSignature 3/4>
    {0.0} <music21.note.Note A>
{3.0} <music21.stream.Measure 2 offset=3.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.bar.Barline type=double>
{6.0} <music21.stream.Measure 2a offset=6.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.bar.Barline type=double>
{9.0} <music21.stream.Measure 2b offset=9.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {2.0} <music21.note.Note E>
    {3.0} <music21.bar.Barline type=double>
{12.0} <music21.stream.Measure 3 offset=12.0>
    {0.0} <music21.note.Note F>
{15.0} <music21.stream.Measure 4 offset=15.0>
    {0.0} <music21.bar.Repeat direction=start>
    {0.0} <music21.note.Note G>
    {1.0} <music21.note.Note A>
    {2.0} <music21.note.Note B>
    {3.0} <music21.bar.Repeat direction=end times=2>
{18.0} <music21.stream.Measure 5 offset=18.0>
    {0.0} <music21.note.Note C>
    {3.0} <music21.bar.Barline type=final>

Calling it again will complete the job, as .process() does

>>> s3 = e.processInnermostRepeatBars(s2)
>>> s3.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
...
{3.0} <music21.stream.Measure 2 offset=3.0>
...
{6.0} <music21.stream.Measure 2a offset=6.0>
...
{9.0} <music21.stream.Measure 2b offset=9.0>
...
{12.0} <music21.stream.Measure 3 offset=12.0>
...
{15.0} <music21.stream.Measure 4 offset=15.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note G>
    {1.0} <music21.note.Note A>
    {2.0} <music21.note.Note B>
    {3.0} <music21.bar.Barline type=double>
{18.0} <music21.stream.Measure 4a offset=18.0>
    {0.0} <music21.bar.Barline type=double>
    {0.0} <music21.note.Note G>
    {1.0} <music21.note.Note A>
    {2.0} <music21.note.Note B>
    {3.0} <music21.bar.Barline type=double>
{21.0} <music21.stream.Measure 5 offset=21.0>
...


Should work even if no start repeat is given:

>>> s = converter.parse('tinynotation: 3/4 A2.  C4 D E   F2.    G4 a b   c2.')
>>> s.makeMeasures(inPlace=True)
>>> s.measure(2).rightBarline = bar.Repeat(direction='end')
>>> e = repeat.Expander(s)
>>> s2 = e.processInnermostRepeatBars(s)
>>> s2.show('text')
{0.0} <music21.stream.Measure 1 offset=0.0>
...
{3.0} <music21.stream.Measure 2 offset=3.0>
...
{6.0} <music21.stream.Measure 1a offset=6.0>
...
{9.0} <music21.stream.Measure 2a offset=9.0>
...
    {3.0} <music21.bar.Barline type=double>
{12.0} <music21.stream.Measure 3 offset=12.0>
...
{15.0} <music21.stream.Measure 4 offset=15.0>
...
{18.0} <music21.stream.Measure 5 offset=18.0>
...
    {3.0} <music21.bar.Barline type=final>
FNTr   rT  r   r      )stringascii_lowercaser/   rX  r5   r^  r   r   rL   rM   r  r  numberSuffixr   )r-   r   repeatIndicesr]  returnExpansionOnlylowercase_alphabetnewforcedIndicesstripFirstNextMeasurer   repeatTimesFoundr\  r>  r   jr@  junkr   s                     r   processInnermostRepeatBars#Expander.processInnermostRepeatBars<  s   h $33!!#   ;;IFM M !&#i.  X 
O !$$";?;P;PQZQ^_aQb<d8E(8 &"2K";/E +#}}Y\: q!1=3D EE 55d;
 '!+a0G 88> A:0BAIQSCS0TD-

4(! +	 00 +,0)!"%) +
  ==6D "A
 -11!411),?05- JJqMQY #i. \ 
C ) ( )s   'F# #F98F9c                   Uc  0 nU R                  U5      nU(       d  U R                  U5      $ U R                  U5      nSnU Hn  nU(       d  M  US   nXS      nXS      n	U HD  n
[        U
5      U;   a    O4U
R	                  U5      (       d  U
R	                  U	5      (       a  Un  OMF     Uc  Mn    O   Uc  U R                  U5      $ US   nUSUS    n/ nSn/ nU GHF  n
X[        U
5      '   US   nU
R                  5       nU
R                  5       nSnSn[        U5       H<  u  nn[        U5      [        U5      :X  a  Un[        U5      [        U5      :X  d  M:  UnM>     Ub  Uc  [        S5      eUR                  nUb)  SUR                  ;   a  [        [        UUS-   5      5      nO[        [        UUS-   5      5      n[        [        UUS-   5      5      nUb.  U H(  nUS    H  nUU;   d  M  UR                  U5        M     M*     U
UUS	.nUR                  U5        GMI     U HW  nUS
   c  M  [        US   R                   5      nU R                  UUS
   USS9nUR                  U5        [#        US
   5      nMY     UR%                  5       nU H  nUR                  U5        M     U H.  nU H%  nU R'                  U5        UR                  U5        M'     M0     XS-   S nU H  nUR                  U5        M     U$ )z
Return a new complete Stream with repeats and brackets
expanded.

The `repeatBracketsMemo` is a dictionary that stores
id(rb): rb entries for all RepeatBrackets.

This is not recursively applied here, but done in __processRecursiveRepeatBars
Nr4  r   rT  z6failed to find start or end index of bracket expansionr  r   bracketIndices)repeatBracketvalidIndicesrq  rs  rr  T)re  r]  rf  )rA  rn  rX  r9  hasSpannedElementgetFirstr8  r   r   r   r  r   r   r   r   r5   r7  rD  r/   r  ) r-   r   repeatBracketsMemor:  	innermost
groupFocusrG  rH  mStartmEndr   streamObjPrestreamBracketRepeatshighestIndexRepeated
boundaries
startIndexmFirstr>  endIndexbracketStartIndexr   r   mLastRightBarindicesrq  dataqr]  outrh  substreamObjPosts                                    r   #_processInnermostRepeatsAndBrackets,Expander._processInnermostRepeatsAndBrackets  sk    %!#
 00; 229== 33I>	
E./I|,Fr]+Db6//))&11R5I5I$5O5O!&J   %) .  229==/0	 )A,/!  $ 
B)+r"v&"1J [[]FJJLEH $!),1a5BuI% Ha5BvJ&()% - #4#<'LN N "..M),0F0FFuZA>? uZA>? "%(98a<"HIN"&D!"23<#NN1- 4 '
 &(&46Dd#W Z D N#/!$"7"C"CD 55"&~"6 +(,	 6  %++C0'*4+?'@$/ 2 !!#AJJqM 'C))!,

1  (
 "":";<AJJqM 
r   c                   / n[        U5       Hj  u  pEUR                  [        5       HL  nX&R                  ;   d)  [	        U[
        5      (       a  M)  [	        Xb5      (       d  M;  UR                  U5        MN     Ml     U(       a  U$ g)a  
Return a list of index positions of a Measure given a
stream of measures. This requires the provided stream
to only have measures.

>>> s = converter.parse('tinynotation: 3/4 A2. C4 D E F2.')
>>> s.makeMeasures(inPlace=True)
>>> s.measure(3).append(repeat.Segno())
>>> e = repeat.Expander(s)

getRepeatExpressionIndex returns the measureIndex not measure number

>>> e.getRepeatExpressionIndex(s.getElementsByClass(stream.Measure), 'Segno')
[2]
N)r   r   r    rF  rH   strr   )r-   r   rI  r   r   r   r  s          r   getRepeatExpressionIndex!Expander.getRepeatExpressionIndex  si    " i(DA))*:;ii' *63 7 7Jq<Q<QKKN < ) Kr   c                    U R                  5       nUc6  U R                  U R                  5      (       d  [        R	                  S5        gU R                  5       (       d  [        R	                  S5        gU R                  5       (       d  [        R	                  S5        gUbl  U[        :X  a-  U R                  5       (       d  [        R	                  S5        g gU[        :X  a+  U R                  5       (       d  [        R	                  S5        gg)	z
Return True or False if this Stream is expandable, that is,
if it has balanced repeats or sensible Da Capo or Dal Segno
indications.

Return None if there's nothing to expand (a third case).
Nz?no dc/segno, no repeats; is expandable but will not do anythingzrepeat bars not coherentFz repeat brackets are not coherentzdc not coherentzds not coherentT)r   rQ  r   r  r  r   rN  r   r.  rr   r1  )r-   rJ  s     r   r   Expander.isExpandable  s     ##%=1G1G!H!H##Q ))++##$>?..00##$FG--// ++,=>  0 	 %//11 ++,=> r   c                    USL a  [         R                  " U5      n0 nSnUS:  a7  US-
  nU R                  UUS9nU R                  U5      (       a  O U$ US:  a  M7  U$ )z
Recursively expand any number of nested repeat bars.
Will also expand all repeat brackets.

if makeDeepCopy is True, then it will make a deepcopy of the stream.  Otherwise
assumes it has already been done.
Td   r   r   )rv  )rL   rM   r  rQ  )r-   r   makeDeepCopyrv  maxProcessess        r   r   $Expander._processRecursiveRepeatBars  s     4i0IQ'!+L @@#5 A 7I
 y))
 # Q" r   c                   U R                  5       nU R                  5       nU R                  U5      nU R                  X5      S   nU[        L a  SnO*U[
        L a  U R                  US5      S   nO[        S5      eUS;   a  U R                  US5      S   nO[        U5      S-
  nUS;   a  U R                  US5      nUS   n	US   n
OS	n	S	n
/ nUR                  SU/5        US;   a2  UR                  Xi/5        UR                  U
[        U5      S-
  /5        OUR                  Xg/5        UR                  5       nUS   R                  nUc  Sn[        U5       H  u  pUR                  5       n[        US   US   S-   5       H9  n[        R                  " UU   5      nUUl
        UR                  U5        US-  nM;     U R                  U5      (       aT  US:X  a  UR                   (       d  O#U R#                  U5      nUS
   R                  S-   nU H  nU R%                  USS9  M     U H  nUR                  U5        M     M     U R'                  U5        U$ )zi
Process and return a new Stream of Measures, likely a Part.
Expand any repeat expressions found within.
r   rr   zMust be DaCapo or Segno)r   r   rw   r   )r   r   rj   NrT  double)r  )r   r'  r+  r  r   rr   
ValueErrorr5   r   r/   r   r   r   rL   rM   rQ  r   r   r  r  )r-   r   capoOrSegnorecTyperecObjjumpBackr   r   codascodaJump	codaStartindexSegmentsrh  r   subCountr  	subStreamr   r   s                      r   r   +Expander._processRepeatExpressionAndRepeats  sp    ))+66811)<00DQG & EE!11)WEaHE677 88//	6B1ECi.1$C 8811)VDEQxHaIHI a]+88  %!23  )S^a-?!@A  %. !!#1$$>F '}5MH!++-I3q63q6A:.MM)A,/!  #! / y)) q=)?)? $ @ @ KI&r]11A5F"A--a-B # 

1 1 66 	$$S)
r   r   r
  )r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   )T)rM   boolreturnr   )r[  )r  )r   stream.Stream)r   r  r  r  )NNFr^   )r  zbool | NoneF)r   r   r   r   r   r&   r   r
  r  r  r   r   r'  r+  r.  r1  rA  rN  rQ  rX  r^  rn  r  r  r   r   r   
_DOC_ORDERr   r   r   r   r   r     s    FN$KL3j5n2&,\*?.W6*XN`;z,@&D%/R 26/37<	Yz @DWv8!F D[z \*Jr   r   c                      \ rS rSrSrg)UnequalPartsLengthExceptioniu  r   Nr   r   r   r   r  r  u  r   r   r  c                      \ rS rSrSrg)InsufficientLengthExceptioniy  r   Nr   r   r   r   r  r  y  r   r   r  c                      \ rS rSrSrg)NoInternalStreamExceptioni}  r   Nr   r   r   r   r  r  }  r   r   r  c                      \ rS rSr% Sr/ SQrSSSS.rS\S	'   SS jrS r	S r
S rS rSS jrSSS.S jjrSS jrSrg
)r   i  a  
An object for finding and simplifying repeated sections of music. Must be passed a stream
which contains either measures or parts containing measures.

To collapse a repeated section, call RepeatFinder.simplify() and to see
which sections of a piece
are repeated, call either RepeatFinder.getMeasureSimilarityList() or
RepeatFinder.getSimilarMeasureGroups (see below for full documentation).

If the internal stream passed to RepeatFinder is altered in any way
(e.g. if you call simplify() with inplace=True)
then to ensure proper functionality, you should use a new RepeatFinder object.

Below is an example of calling simplify on a Bach chorale.

>>> chorale = corpus.parse('bwv117.4.mxl')
>>> #_DOCS_SHOW chorale.show()

Only the first 8 bars are displayed below

.. image:: images/repeat-SimplifyExample_Chorale.*
   :width: 600

>>> #_DOCS_SHOW repeat.RepeatFinder(chorale).simplify().show()

The same chorale as before, but simplified

.. image:: images/repeat-SimplifyExample_ChoraleSimplified.*
   :width: 600

)simplifygetMeasureSimilarityListgetSimilarMeasureGroupsr   	hasPickupa  A function that takes a stream of notes and rests and
                                returns a string or an
                                integer such that two measures are equal if their
                                hashes are equal under the '==' operatorzAThe internal stream which is being analyzed for repeated sectionsz3boolean whether measure numbers should be corrected)defaultHashrW   r   zdict[str, str]	_DOC_ATTRNc                |    SSK Jn  Xl        Uc  UR                  U l        OX l        S U l        S U l        SU l        g )Nr   )searchT)r   r  rW   translateStreamToStringr  _mList_mGroupsr   )r-   	inpStreamdefaultMeasureHashFunctionr  s       r   r&   RepeatFinder.__init__  s:    "%-%==D9%)"r   c                r   U R                   c  [        S5      eU R                   R                  5       (       a  U R                   nOU R                   R                  S   n[	        UR                  5       R                  5       5      n[        U5      S:  a  [        S5      eUS   US   -
  nUS   US   -
  nX4-  $ )a  
Looks at RepeatFinder's internal stream and returns the duration of the pickup bar
in quarterLengths.  If there is no pickup, returns 0.0.

Raises an exception if RepeatFinder's internal stream is too short
(i.e. fewer than 3 measures long)


>>> noPickup = corpus.parse('bwv10.7.mxl')
>>> repeat.RepeatFinder(noPickup).getQuarterLengthOfPickupMeasure()
0.0
>>> #_DOCS_SHOW noPickup.parts[0].measures(0, 5).show()

.. image:: images/repeat-rf_noPickup.*
   :width: 600

>>> hasPickup = corpus.parse('bwv101.7.mxl')
>>> repeat.RepeatFinder(hasPickup).getQuarterLengthOfPickupMeasure()
1.0
>>> #_DOCS_SHOW hasPickup.parts[0].measures(0, 2).show()

.. image:: images/repeat-rf_hasPickup.*
   :width: 600

>>> tooShort = noPickup.parts[0].measures(1, 2)
>>> repeat.RepeatFinder(tooShort).getQuarterLengthOfPickupMeasure()
Traceback (most recent call last):
music21.repeat.InsufficientLengthException: Cannot determine length
    of pickup given fewer than 3 measures

OMIT_FROM_DOCS

>>> repeat.RepeatFinder().getQuarterLengthOfPickupMeasure()
Traceback (most recent call last):
music21.repeat.NoInternalStreamException:
    RepeatFinder must be initialized with a stream

.RepeatFinder must be initialized with a streamr      z=Cannot determine length of pickup given fewer than 3 measuresr   r   )	rW   r  r   r   r   measureOffsetMapkeysr5   r  )r-   s2mOffsetspickupnormMeasures        r   r   ,RepeatFinder.getQuarterLengthOfPickupMeasure  s    N 66>+@  66BaB++-2245x=1-O  !x{*qkHQK/##r   c                X    U R                   c  [        S5      eU R                  5       S:g  $ )a  
Returns True when the RepeatFinder's internal stream has a pickup bar.

Raises an exception if the internal stream is too short
(i.e. fewer than 3 bars long).

>>> noPickup = corpus.parse('bwv10.7.mxl')
>>> repeat.RepeatFinder(noPickup).hasPickup()
False
>>> #_DOCS_SHOW noPickup.parts[0].measures(0, 5).show()

.. image:: images/repeat-rf_noPickup.*
   :width: 600

>>> hasPickup = corpus.parse('bwv101.7.mxl')
>>> repeat.RepeatFinder(hasPickup).hasPickup()
True
>>> #_DOCS_SHOW hasPickup.parts[0].measures(0, 2).show()

.. image:: images/repeat-rf_hasPickup.*
   :width: 600

_OMIT_FROM_DOCS_
>>> repeat.RepeatFinder(noPickup.parts[0].measures(1, 2)).hasPickup()
Traceback (most recent call last):
music21.repeat.InsufficientLengthException: Cannot determine length of pickup
    given fewer than 3 measures
>>> repeat.RepeatFinder().hasPickup()
Traceback (most recent call last):
music21.repeat.NoInternalStreamException: RepeatFinder must be initialized with a stream
r  g        )rW   r  r   r;   s    r   r  RepeatFinder.hasPickup  s.    @ 66>+,\]]335<<r   c                    SSK Jn  U R                  c  [        S5      eU R                  b  U R                  $ U R
                  nU R                  nUR                  5       (       a  UR                  UR                  5      /nO4UR                   Vs/ s H  oUR                  UR                  5      PM     nn[        XDSS 5       H(  u  pg[        U5      [        U5      :w  d  M  [        S5      e   [        [        U5      5       HA  n[        [        XH   5      5       V	s/ s H  n	U" XH   U	   R                  5      PM     sn	XH'   MC     [        [        U6 5      n0 n
[        [        U5      5       Vs/ s H  n/ PM     nn[        [        U5      S-
  SS5       HL  nSR!                  XH   5      nX;   a-  X   R#                  X   5        X   R%                  XU      5        XU'   MN     Xl        U$ s  snf s  sn	f s  snf )	a  
Returns a list mList = [ [2, 3], [3], ... ] such that measures i and j are the
same (with i < j) if and only
if mList[i] contains j.  NOTE: this function refers to the very first measure
as measure 0 regardless of whether
s starts with measure 0 or 1 (i.e. treats a pickup bar as an entire measure).

For instance, if getMeasureSimilarityList returned [[4], [5], [6], [7, 8],
[], [], [], [8], []], we would know that the first
four measures repeat and the 4th, 8th, and 9th measures are the same.

Measures are considered the same if the defaultHash maps
them to two values which are
equal under the '==' operator.

>>> chorale = corpus.parse('bwv154.3.mxl')

Expand the repeats:

>>> chorale = repeat.Expander(chorale.parts[0]).process()

Search for similarity:

>>> repeat.RepeatFinder(chorale).getMeasureSimilarityList()
[[4, 12], [5, 13], [6], [7], [12], [13], [], [], [], [], [], [], [], [], [], []]

>>> chorale2 = corpus.parse('bwv153.5.mxl')
>>> chorale2 = repeat.Expander(chorale2.parts[0]).process()
>>> repeat.RepeatFinder(chorale2).getMeasureSimilarityList()  # bwv153.5 has a pickup
[[5], [6], [7], [8], [9], [], [], [], [], [], [15], [], [], [], [19], [], [], [], [], []]
>>> hashFunction = lambda m : str(len(m))

>>> repeat.RepeatFinder(chorale.measures(1, 8),
...                     defaultMeasureHashFunction=hashFunction).getMeasureSimilarityList()
[[1, 2, 4, 5, 6, 8, 10], [2, 4, 5, 6, 8, 10], [4, 5, 6, 8, 10],
 [7, 9, 11], [5, 6, 8, 10], [6, 8, 10], [8, 10], [9, 11], [10], [11], [], []]

_OMIT_FROM_DOCS_
>>> repeat.RepeatFinder().getMeasureSimilarityList()
Traceback (most recent call last):
music21.repeat.NoInternalStreamException: RepeatFinder must be initialized with a stream
r   r   Nr  r   z1Parts must each have the same number of measures.rT  r3   )r   r   rW   r  r  r  r   r   r   r   zipr5   r  r   notesAndRestsr   joinr   extend)r-   r   hashFunctionrW   mListspmThismNextr   rl  tempDict_resmHashs                 r   r  %RepeatFinder.getMeasureSimilarityList   s   X 	#66>+,\]];;";;''FF ==??**6>>:;FDEGGLGq**6>>:GFL  qr
3LE5zSZ'1GI I 4 s6{#A s69~..A VYq\778.FI $ c6l# !V-.-ar-.s6{QB/AGGFI&E ho.c5/23  UO 0 
W M /s   $G1!G62G;c                   X#4U;   a  gUS-   XS-      ;   a  U R                  XS-   US-   XE5      nU/U/4nUS   R                  US   5        US   R                  US   5        US   S   US   S   :  a  SXRS-   US-   4'   O=US   S   US   S   :  a$  US   SS US   SS 4nUS   S   US   S   :  a  M$  OU/U/4nXtX#4'   SXRU4'   U$ )a  
Recursive helper function used by getSimilarMeasureGroupsFromList.
Should only be called if the "source" measure of a piece is the same
as the "compare" measure.

When called, updates resDict such that resDict[(source, compare)] is equal to
( sourceList=[source, source + 1, source + 2, ...],
compareList=[compare, compare + 1, compare + 2, ...]), where
measure sourceList[i] is the same as measure compareList[i]

Inputs:
measures -  A list returned from getMeasureSimilarityList.
source   -  The measure number which you are considering
compare  -  The measure number which is compared to the source measure
            (this is a repeat of the source measure)
resDict  -  A dictionary of memoized results where for each key (i,j),
            there is stored a tuple
            ([i, i + 1, i + 2, ...], [j, j + 1, j + 2, ...])
            where measures i and j are equal,
            and measure i + 1 and j + 1 are equal,
            and measures i + 2 and j + 2 are equal, etc.
useDict  -  A dictionary for each input that maps to False if
            and only if the function calls
            the same input m and i. Has the result that if resDict((i, j)) maps to
            something like ([i, i + 1, i + 2...],
            [j, j + 1, j + 2, ...]), then
            useDict(i,j) is only False if resDict(i - 1, j - 1) is
            something like ([i - 1, i, i + 1, ...],
            [j - 1, j, j + 1, ..])

See getSimilarMeasureGroupsFromList documentation for tests.
Nr   r   rT  FT)_getSimilarMeasuresHelperr  )r-   r   sourcecompareresDictuseDictnextOner  s           r   r  &RepeatFinder._getSimilarMeasuresHelper  s0   D 'q[HaZ00 44Xz7UV;6=HG 8gY'CFMM'!*%FMM'!*%1vbzCF1I% 6;!Wq[12 !fRjCF1I-q6#2;As4C !fRjCF1I- 8gY'C%(!"%)!"
r   Fc           	        [        U(       + 5      n0 n0 n[        [        U5      5       H!  nX    H  nU R                  XXtU5        M     M#     [	        U5       H  nXX   (       a  M  XH	 M     / n	UR                  5        HD  n
U
S    Vs/ s H  owU-   PM	     snU
S    Vs/ s H  oU-   PM	     sn4nU	R                  U5        MF     Xl        U	$ s  snf s  snf )aS  
Input is a list formatted as the output described in getMeasureSimilarityList().
Output is a list of tuples of the form (l1, l2), where l1 and l2 are
lists of measure numbers such that measure l1[i]
is identical to measure l2[i] and l1[-1] < l2[0]

For all tuples t1 and t2, it is guaranteed that we never
have t1.l1 contains t2.l1 or t2.l2 contains t2.l2

>>> mList = [[5, 6], [7], [8], [9], [11, 12], [6, 13],
...          [], [], [], [], [], [12], [], []]
>>> res1 = repeat.RepeatFinder()._getSimilarMeasureTuples(mList, False)
>>> ([1, 2, 3, 4], [7, 8, 9, 10]) in res1
True
>>> ([1], [6]) in res1
True
>>> ([5],[12]) in res1
True
>>> ([5, 6], [13, 14]) in res1
True
>>> ([6],[7]) in res1
True
>>> ([12],[13]) in res1
True
>>> len(res1)
6
>>> mList = [[], [5, 10], [6, 11], [7, 12], [8, 13],
...          [10], [11], [12], [13], [], [], [], [], []]
>>> res2 = repeat.RepeatFinder()._getSimilarMeasureTuples(mList, True)
>>> ([1, 2, 3, 4], [5, 6, 7, 8]) in res2
True
>>> ([1, 2, 3, 4], [10, 11, 12, 13]) in res2
True
>>> ([5, 6, 7, 8], [10, 11, 12, 13]) in res2
True
>>> len(res2)
3

>>> s = stream.Stream()
>>> n1 = note.Note('C')
>>> n2 = note.Note('D')
>>> n3 = note.Note('E')
>>> n4 = note.Note('F')
>>> for i in range(3):
...    m = stream.Measure()
...    s.append(m)
...    m.append(n1)
...    m.append(n2)
...    m.append(n3)
...    m.append(n4)

>>> rf = repeat.RepeatFinder()
>>> res3 = rf._getSimilarMeasureTuples([[1, 2], [2], []], False)
>>> ([1], [2]) in res3
True
>>> ([2], [3]) in res3
True
>>> ([1], [3]) in res3
True
>>> len(res3)
3

>>> s = stream.Stream()
>>> n1 = note.Note('C')
>>> n2 = note.Note('D')
>>> n3 = note.Note('E')
>>> n4 = note.Note('F')
>>> for i in range(5):
...    m = stream.Measure()
...    s.append(m)
...    m.append(n1)
...    m.append(n2)
...    m.append(n3)
...    m.append(n4)
>>> rf = repeat.RepeatFinder()
>>> res3 = rf._getSimilarMeasureTuples([[1, 2, 3, 4], [2, 3, 4], [3, 4], [4], []], False)
>>> ([1, 2], [3, 4]) in res3
True
>>> ([1, 2], [4, 5]) in res3
True
>>> ([2, 3], [4, 5]) in res3
True
>>> ([1],[3]) in res3
False
>>> ([1],[4]) in res3
False
>>> ([1],[5]) in res3
True
r   r   )intr   r5   r  r   valuesr   r  )r-   r  r  pickupCorrectionr  usefulr   r   krealResmTuplerl  	appendTups                r   _getSimilarMeasureTuples%RepeatFinder._getSimilarMeasureTuples  s    v 9}-s5z"AX..uH  #
 cA99F  jjlF8>q	B	1..	B8>q	B	1..	BDINN9% #
   CBs   	C Cr   c          	     f   U R                  5       nU R                  X@R                  5       5      n0 n[        US S9nU(       a  U R                  nOU R                  R                  S5      nUc  [        S5      e/ n/ n	/ n
U GH)  nSnUS   US   -   nU H  nX;   d  M
  S	n  O   U(       a  M,  US   S   US   S
   -
  S-
  n[        S[        US   5      S-  S-   5      n[        US   5      U:  a>  US:X  a8  US   S   US   S
   nnU
R                  UU45        U	R                  US   5        On[        US   5      U:  aY  UUs=:  a  S:  aL  O  OIUS   S   nUS   S
   S-   nUS   S   S-
  nUUU4nUR                  U5        U	R                  US   5        OGM  U H  nS	Xn'   M	     GM,     U HE  u  nnn[        UUUS	S9  UU-
  S-   nUU-
  S-   nUU-   n[        UUUSS	S9  [        UUUU-   SS	S9  MG     U
 H  u  nn[        UUUS	S9  M     [        UU	S	U R                  S9  U(       d  U$ g)aD	  
Takes the piece stored in the RepeatFinder object and collapses repeated sections by
replacing them with repeat signs. Includes first and second endings where appropriate.

Only detects repeated sections which are repeatThreshold bars long and only
detects repeat endings
where the repeated sections is more than repeatEndingThreshold bars long.
If inPlace is True, does not return a new music21 object, but instead alters
the stream passed to
the RepeatFinder object.

In the below example, we have an 8-measure stream where the last four measures
are identical to the
first four.

>>> s = stream.Stream()
>>> notes = [note.Note('D'), note.Note('E-'), note.Note('C'), note.Note('B3'),
...           note.Note('D'), note.Note('E-'), note.Note('C'), note.Note('B3')]
>>> for i in range(8):
...    m = stream.Measure()
...    m.number = i + 1
...    myNote = notes[i]
...    myNote.duration.quarterLength = 4.0
...    m.append(myNote)
...    s.append(m)
>>> #_DOCS_SHOW s.show()


.. image:: images/repeat-RepeatFinderDSCH.*
    :width: 600

>>> s2 = repeat.RepeatFinder(s).simplify()
>>> #_DOCS_SHOW s2.show()


.. image:: images/repeat-RepeatFinderDSCHsimplified.*
    :width: 600



OMIT_FROM_DOCS

>>> c1 = corpus.parse('bwv115.6.mxl')    # has a repeated section
>>> c1p0 = repeat.Expander(c1.parts[0]).process()
>>> c1simple = repeat.RepeatFinder(c1p0).simplify()
>>> m4 = search.translateStreamToString(c1p0.measure(3).notesAndRests)
>>> m5 = search.translateStreamToString(c1p0.measure(4).notesAndRests)
>>> m9 = search.translateStreamToString(
...    c1p0.getElementsByClass(stream.Measure)[7].notesAndRests)
>>> resm4 = search.translateStreamToString(c1simple.measure(3).notesAndRests)
>>> resm5 = search.translateStreamToString(c1simple.measure(4).notesAndRests)
>>> m4 == resm4
True
>>> m5 == resm5
True
>>> m9 == resm5
True
>>> initialRepeats = c1p0[bar.Repeat]
>>> len(initialRepeats)
0
>>> resRepeats = c1simple[bar.Repeat]
>>> len(resRepeats)
1

>>> s = stream.Stream()
>>> for i in range(1, 6):
...    m = stream.Measure()
...    s.append(m)
...    m.number = i
...    m.append(note.Note('D'))
...    m.append(note.Note('E-'))
...    m.append(note.Note('C'))
...    m.append(note.Note('B3'))
>>> s2 = repeat.RepeatFinder(s).simplify(repeatThreshold=2)
>>> len(s2.getElementsByClass(stream.Measure))
3
>>> len(s2.flatten().getElementsByClass(bar.Repeat))
1
c                B    S[        U S   5      -  U S   S   U S   S   4$ NrT  r   r   r5   xs    r   <lambda>'RepeatFinder.simplify.<locals>.<lambda>	  s'    S1Y!Q1a'Ir   keyzRepeatFinder.simplifyNzGThis function only works when RepeatFinder is initialized with a streamFr   r   TrT  g      0@g       @r   r   r   )r  r  r  sortedrW   r   r  minr5   r   r  r   r   r   r   )r-   repeatThresholdrepeatEndingThresholdr   r  mGroups	processedrW   repeatEndingBarsr   
repeatBarsmGroupalreadyProcessedmeasureNumbersmNumdistancemaxAcceptableDistancestartBarendBarstartingBarfirstEndingBarrepeatSignBartoProcessTuplelengthOfRepeatEndinglengthOfRepeatedSectionstartOfSecondEndings                             r   r  RepeatFinder.simplify=	  s   b --///~~7GH	 I A++,CDA9+Y  
F$#AY2N&$'+$ '  ay|fQim3a7H$'c&)ns.BQ.F$G! 6!9~0X]#)!9Q<2&!!8V"45q	*fQi.$99+x;!;$Qil!'2!2 &q	!q 0"-~}!M ''7q	* '"&	 'G L ;K6KKE#0>#AA#E &4{&BQ&F#"/2I"Iq-, '+	-
 q225II '+	- ;K" !+HfHfd; !+ 	q#-1-G-G	I
 H r   c                8   U R                   cJ  U R                  c  U R                  5       nOU R                  nU R                  X R	                  5       5      nOU R                   nU Vs/ s H  n[        US   5      U:  d  M  UPM     nn[        US S9nU$ s  snf )a9  
Returns a list of tuples containing information on repeated groups of measures.

Specifically, returns a list of tuples of the form (l1, l2)
where l1 and l2 are lists
of measure numbers such that measure l1[i] is the same as measure l2[i].

>>> chorale = corpus.parse('bwv117.4.mxl')

Expand repeats

>>> chorale = repeat.Expander(chorale.parts[0]).process()
>>> #_DOCS_SHOW chorale.show()

Measures 0-4 are the same as measures 5-9.

.. image:: images/repeat-SimplifyExample_Chorale.*
   :width: 600

>>> repeat.RepeatFinder(chorale).getSimilarMeasureGroups()
[([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]), ([1, 2, 3, 4, 5], [6, 7, 8, 9, 10]), ([0], [10])]

Notice that although measures 2-3 are the same as measures 6-7, we
don't have ([2, 3], [6, 7]) in our result, since ([1, 2, 3], [5, 6, 7])
already contains that information.

r   c                B    S[        U S   5      -  U S   S   U S   S   4$ r  r  r  s    r   r  6RepeatFinder.getSimilarMeasureGroups.<locals>.<lambda>(
  s'    c!A$i1a!A$q'0Rr   r  )r  r  r  r  r  r5   r  )r-   	thresholdr  r  r  s        r   r  $RepeatFinder.getSimilarMeasureGroups	  s    : == {{"55733E>>;KLGmmG%@gQqTi)?1g@ &RS As   (BB)r  r  r   r  rW   )NNr  )   r  r   )r   r   r   r   r   r  r  __annotations__r&   r   r  r  r  r  r  r  r   r   r   r   r   r     sf    >JL Q!V!XI~ X*9$v#=JhT?Bpdve vp4r   r   __main__r  )r   r  )4r   
__future__r   rL   rb  typingr   music21.common.typesr   r   r   r   r   r   r	   r
   TYPE_CHECKINGr   Environmentr  ProtoM21Objectr   r   r   
Expressionr    rd   rj   rr   rw   r~   r   r   r   r   r   r   r   repeatExpressionReferencer   r   r   r   Genericr   r  r  r  r   r  r   mainTestr   r   r   <module>r"     s8   #    +        ?? &&x0'' :	 = = 	hz;#9#9 hV
&- 
&"! "," $%! %%. %4$ 4"4* 4*4* 404% 44& 4$4, 4&4, 42 	FEGTVVX|~NGIxz>+;^=M 6 6 6r ,1 <~ ,1 Zp	55 	c+qyy$ c+P'	,"?"? 		,"?"? 		 = = 	f
 f
X  6eT%v|GX~~|]
 z r   