
    3j                   8   d Z ddlmZ ddlZddlZddlZddlmZ ddl	m
Z
 ddl	mZ ddl	mZ ddl	mZ dd	l	mZ dd
l	mZ ej                   rddl	mZ  e
j$                  d      Z G d dej(                        Z G d dej,                        Z G d deej0                        Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d d e      Z  G d! d"e      Z! G d# d$e      Z" G d% d&e      Z# G d' d(e      Z$ G d) d*e      Z% e        e        e        e        e         e!        e"        e#        e$        e%       g
Z&d?d+d,d@d-Z'd+d,d.Z(d+d/d0d1Z) G d2 d3ej,                        Z* G d4 d5ejV                  e         Z, G d6 d7ej,                        Z- G d8 d9ej,                        Z. G d: d;ej,                        Z/ G d< d=      Z0eeeeeeee e!e"e#e$e%e0gZ1e2d>k(  rddl	Z	 e	jf                          yy)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                      e Zd ZdZy)
RepeatMarka  
    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(f'Stream has {len(repeats)} repeat(s) in it')
    Stream has 1 repeat(s) in it
    N)__name__
__module____qualname____doc__     ;/DATA/.local/lib/python3.12/site-packages/music21/repeat.pyr   r   )   s    r   r   c                      e Zd Zy)RepeatExpressionExceptionNr   r   r   r   r   r   r   r   E       r   r   c                  f     e Zd ZdZej
                  Z fdZd Zd Z	d Z
d
dZd Zd Zd	 Z xZS )RepeatExpressiona'  
    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        |   di | d | _        g | _        d| j                  _        d| _        d| j                  _        y )NcenterF   r   )super__init___textExpression_textAlternativesr
   justify	useSymbol	absoluteYselfkeywords	__class__s     r   r!   zRepeatExpression.__init__Z   sD    $8$#!#%

  "

r   c                    | j                         }|t        |      dkD  rt        |d d dz         S |t        |      S y)N   z... )getTextlenrepr)r(   contents     r   _reprInternalzRepeatExpression._reprInternalh   sG    ,,.3w<"#4u,-- = r   c                .    | j                   j                  S )z8
        Get the text used for this expression.
        )r"   r1   r(   s    r   r.   zRepeatExpression.getTextq   s     ##+++r   c                    | j                   Ft        j                  |      | _         | j                  | j                   _        | j	                          y|| j                   _        y)z
        Set the text of this repeat expression.
        This is also the primary way that the stored TextExpression object is created.
        N)r"   r   TextExpressionr
   applyTextFormattingr1   r(   values     r   setTextzRepeatExpression.setTextw   sO    
 '#.#=#=e#DD )-D  &$$&+0D  (r   c                p    || j                   }|%| j                  j                  |j                  _        |S )za
        Apply the default text formatting to the text expression version of this repeat
        )r"   r
   r$   )r(   tes     r   r7   z$RepeatExpression.applyTextFormatting   s4     :%%B>#zz11BHH	r   c                    t        |t        j                        st        d|       || _        | j                          y)z7
        Directly set a TextExpression object.
        z,must set with a TextExpression object, not: N)
isinstancer   r6   r   r"   r7   r8   s     r   setTextExpressionz"RepeatExpression.setTextExpression   sA     %!;!;<+>ugFH H$  "r   c                Z    | j                   yt        j                  | j                         S )zL
        Return a copy of the TextExpression stored in this object.
        N)r"   copydeepcopyr4   s    r   getTextExpressionz"RepeatExpression.getTextExpression   s(     '==!5!566r   c                Z    d }| j                   D ]  } ||      } ||      }||k(  s y y)zd
        Return True or False if the supplied text could be used for this RepeatExpression.
        c                    | j                         } | j                  dd      } | j                  dd      } | j                         } | S )N r-   .)stripreplacelower)ss    r   	stripTextz/RepeatExpression.isValidText.<locals>.stripText   s=    	A		#r"A		#r"A	AHr   TF)r#   )r(   r9   rL   	candidates       r   isValidTextzRepeatExpression.isValidText   s=    	 //I!),Ie$E	!	 0
 r   N)r   r   r   r   r
   	TextStyle_styleClassr!   r2   r.   r:   r7   r?   rC   rN   __classcell__r*   s   @r   r   r   I   s;     //K",
1	#7r   r   c                  "     e Zd ZdZ fdZ xZS )RepeatExpressionMarkerz
    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                F    t        |   di | d| j                  _        y )Nr   r   )r    r!   r
   r$   r'   s     r   r!   zRepeatExpressionMarker.__init__   s    $8$%

r   r   r   r   r   r!   rR   rS   s   @r   rU   rU      s    & &r   rU   c                  $     e Zd ZdZd fd	Z xZS )Codaz^
    The coda symbol, or the word coda, as placed in a score.

    >>> rm = repeat.Coda()
    c                    t        |   di | d| j                  _        g d| _        |*| j                  |      r| j                  |       d| _        y | j                  | j                  d          d| _        y )Nr   )rY   zto Codazal CodaFr   Tr   )r    r!   r
   r$   r#   rN   r:   r%   r(   textr)   r*   s      r   r!   zCoda.__init__   sk    $8$%

!? 0 0 6LL"DNLL//23!DNr   rO   rW   rS   s   @r   rY   rY      s    " "r   rY   c                  "     e Zd ZdZ fdZ xZS )Segnozi
    The segno sign as placed in a score.

    >>> rm = repeat.Segno()
    >>> rm.useSymbol
    True
    c                ~    t        |   di | dg| _        | j                  | j                  d          d| _        y )Nr^   r   Tr   )r    r!   r#   r:   r%   r'   s     r   r!   zSegno.__init__   s;    $8$")T++A./r   rW   rS   s   @r   r^   r^      s     r   r^   c                  "     e Zd ZdZ fdZ xZS )FinezI
    The fine word as placed in a score.

    >>> rm = repeat.Fine()
    c                    t        |   di | dg| _        | j                  | j                  d          d| j                  _        y )Nfiner   rightr   )r    r!   r#   r:   r
   r$   r'   s     r   r!   zFine.__init__   s@    $8$"(T++A./$

r   rW   rS   s   @r   ra   ra      s    % %r   ra   c                  "     e Zd ZdZ fdZ xZS )RepeatExpressionCommandz
    Some repeat expressions are commands, instructing
    the reader to go somewhere else. DaCapo and
    related are examples.
    c                T    t        |   di | d| _        d| j                  _        y )NFrd   r   )r    r!   repeatAfterJumpr
   r$   r'   s     r   r!   z RepeatExpressionCommand.__init__   s)    $8$$ %

r   rW   rS   s   @r   rf   rf      s    
% %r   rf   c                  $     e Zd ZdZd fd	Z xZS )DaCapoz
    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        |   di | ddg| _        |#| j                  |      r| j	                  |       y | j	                  | j                  d          y )NzDa CapozD.C.r   r   r    r!   r#   rN   r:   r[   s      r   r!   zDaCapo.__init__  sV    $8$"+V!4 0 0 6LLLL//23r   rO   rW   rS   s   @r   rj   rj     s    4 4r   rj   c                  $     e Zd ZdZd fd	Z xZS )DaCapoAlFinea:  
    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        |   di | ddg| _        |#| j                  |      r| j	                  |       y | j	                  | j                  d          y )NzDa Capo al finezD.C. al finer   r   rl   r[   s      r   r!   zDaCapoAlFine.__init__#  V    $8$"3^!D 0 0 6LLLL//23r   rO   rW   rS   s   @r   rn   rn     s    	4 4r   rn   c                  $     e Zd ZdZd fd	Z xZS )DaCapoAlCodaa  
    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        |   di | ddg| _        |#| j                  |      r| j	                  |       y | j	                  | j                  d          y )NzDa Capo al CodazD.C. al Codar   r   rl   r[   s      r   r!   zDaCapoAlCoda.__init__:  rp   r   rO   rW   rS   s   @r   rr   rr   -  s    
4 4r   rr   c                  $     e Zd ZdZd fd	Z xZS )AlSegnozc
    Jump to the sign. Presumably a forward jump, not a repeat.

    >>> rm = repeat.AlSegno()
    c                    t        |   di | dg| _        |#| j                  |      r| j	                  |       y | j	                  | j                  d          y )Nzal Segnor   r   rl   r[   s      r   r!   zAlSegno.__init__J  sS    $8$", 0 0 6LLLL//23r   rO   rW   rS   s   @r   ru   ru   D  s    
4 4r   ru   c                  $     e Zd ZdZd fd	Z xZS )DalSegnoa  
    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        |   di | ddg| _        |#| j                  |      r| j	                  |       y | j	                  | j                  d          y )Nz	Dal SegnozD.S.r   r   rl   r[   s      r   r!   zDalSegno.__init__\  sV    $8$"-v!6 0 0 6LLLL//23r   rO   rW   rS   s   @r   rx   rx   S  s    4 4r   rx   c                  $     e Zd ZdZd fd	Z xZS )DalSegnoAlFinea6  
    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        |   di | ddg| _        |#| j                  |      r| j	                  |       y | j	                  | j                  d          y )NzDal Segno al finezD.S. al finer   r   rl   r[   s      r   r!   zDalSegnoAlFine.__init__o  V    $8$"5~!F 0 0 6LLLL//23r   rO   rW   rS   s   @r   r{   r{   e  s    4 4r   r{   c                  $     e Zd ZdZd fd	Z xZS )DalSegnoAlCodaa  
    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        |   di | ddg| _        |#| j                  |      r| j	                  |       y | j	                  | j                  d          y )NzDal Segno al CodazD.S. al Codar   r   rl   r[   s      r   r!   zDalSegnoAlCoda.__init__  r}   r   rO   rW   rS   s   @r   r   r   x  s    	4 4r   r   FinPlacec                  |s| j                  d       | y| j                         s&| j                  D ]  }t        ||||d        |ry| S t	        ||dz         D cg c]  }| j                  |       }}t        j                  ||      }|d   j                  |       }	| j                  |	|       |du ry| S c c}w )a5  
    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)
rK   startendendingNumberr   partimeasuresrbrbOffsets
             r   r   r     s    8 	34y==?GGDtUCtL H&+E37&;<&;		!&;H<			x	=B {**1-HHHXr$ =s   B<c                  | y|s| j                  d       | j                         s%| j                  D ]  }t        |||d        |ry| S ddlm} |j                  dd	      | j                  |      _        |d
k7  st        |       j                         dk7  r&|j                  d      | j                  |      _        |ry| S )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)rK   r   r   r   r   r   s         r   r   r     s    H 	y	~.==?GGDuc48 H"%**uA*"FAIIcN z\!_DDF!K'*zzGz'D		%$r   Tr   correctMeasureNumbersc                  ddl m} | y|s| j                  d      } | j                         r.|D ](  }	 | j	                  |      }|| j                  |       * n%| j                  D ]  }t        ||d|        |ry| S |rNt        | j                  |j                              }|r(|d   j                  }	|	dvrd}	|D ]  }
|	|
_        |	dz  }	 |ry| S # t
        j                  $ r d}Y w xY w)	a  
    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   )rK   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C-,C-c                      e Zd Zy)ExpanderExceptionNr   r   r   r   r   r     r   r   r   c                      e Zd ZdZddZdddZddZddZd dZd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd!dZd Zd Z	 	 	 d"dZ	 d#dZd Zd$dZd%dZd ZddgZy)&Expandera
  
    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                   ddl m} || _        | j                  j                  |j                        j                         | _        | j                  j                         j                  t        j                        j                         | _	        t        | j
                        | _        | j                  dk(  rt        d      | j
                  j                         j                  t              j                         }t        |j                  t                    | _        t        |j                  t                     | _        t        |j                  t$                    | _        t        |j                  t(                    | _        t        |j                  t,                    | _        t        |j                  t0                    | _        t        |j                  t4                    | _        t        |j                  t8                    | _        t        |j                  t<                    | _        t        |j                  t@                    | _!        y )Nr   r   z5no measures found in the source stream to be expanded)"r   r   _srcr   r   _srcMeasureStreamflattenr	   r   _repeatBracketsr/   _srcMeasureCountr   r   rY   
_codaCountr^   _segnoCountra   
_fineCountrj   _dcCountrn   
_dcafCountrr   
_dcacCountru   _asCountrx   _dsCountr{   
_dsafCountr   
_dsacCount)r(   	streamObjr   reStreams       r   r!   z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                *   | j                         }|du rt        d      |dur| j                  j                  d      }n| j                  }|t	        j
                  t        |      S t        j                  | j                        | _	        |D ]<  }| j                  j                  j                  |j                  j                  |       > | j                         }|| j                  |      }n| j!                  |      }|j#                  |       |S )a  
        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   rA   rB   r   spannerBundlereplaceSpannedElement
derivationorigin_daCapoOrSegno_processRecursiveRepeatBars"_processRepeatExpressionAndRepeatsmergeAttributes)r(   rB   	canExpand	srcStreammhasDaCapoOrSegnoposts          r   processz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                >   ddl m} g }g }| j                         }|}t        |j	                  |j
                              D ]?  \  }}|j                  |j                                |j                  |j                         A |dk(  r|S i }	i }
t        | j                        D ]'  \  }}||	|j                         <   ||
|j                  <   ) g }t        |      D ]  \  }}	 |j                  |	|           |S # t        $ r |j                  |
||             Y Aw xY w)al  
        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   
measureMapzExpander.measureMap,  s8   0 	#$&!||~#' 6II&..YZDAq$$Q%>%>%@A%,,QXX6 [ ($$$&!d445DAq=>a779:23%ahh/ 6
 	*34E*F&A&Z  !23J!KL +G
   Z  !:;TUV;W!XYZs   !C99 DDc                    ddl m} |j                  }|j                  }|$d|j                  v r|j                  |      |_        |&d|j                  v r|j                  |      |_        yyy)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   _stripRepeatBarlineszExpander._stripRepeatBarlinesb  sc     	 ]]^^>2bkkAKK0AM>2bkkA [[1AN B>r   c                   ddl m} |j                         s|g}n$t        |j	                  |j
                              }|D ]G  }g }|j	                  t              D ]  }|j                  |        |D ]  }|j                  |        I y)zo
        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   _stripRepeatExpressionsz Expander._stripRepeatExpressionsq  sy    
 	#$$&KE55fnnEFEAF))*:;a  < 	 r   c                $   d}d}d}| j                   D ]  }|j                  }|j                  }|Pd|j                  v rB|j                  dk(  r|dz  }|dz  }n(|j                  dk(  r|dk(  r
|dz  }|dz  }|dz  }|dz  }|pd|j                  v s|j                  dk(  r|dk(  r
|dz  }|dz  }|dz  }|dz  }t        d| d|        |dvrt        j                  d	| g       y
|||dz
  fvrt        j                  d| d| g       y
y)zW
        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   repeatBarsAreCoherentzExpander.repeatBarsAreCoherent  st    
''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\~%^$_`h155##9,c(-%  
 r   c                    | j                   | j                  z   | j                  z   }| j                  | j                  z   | j
                  z   | j                  z   }|dk(  r|dk(  rt        S |dk(  r|dk(  rt        S y)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   rj   r^   )r(   sumDcsumDss      r   r   zExpander._daCapoOrSegno  sw     /$//A??#??# ==!
 A:%1*MaZEQJLr   c                    | j                   dk(  ry| j                  dk(  ry| j                  dk(  ry| j                  dk(  ry| j                  dk(  ry| j
                  dk(  ry| j                  dk(  ryt        d	      )
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   rj   rr   rn   ru   rx   r   r{   zno repeat command found)r   r   r   r   r   r   r   r   r4   s    r   _getRepeatExpressionCommandTypez(Expander._getRepeatExpressionCommandType  sy     ==A__!!__!!]]a]]a__!#__!##$=>>r   c                d    |j                         j                  t              j                         S )zS
        Get the instance found in this stream; assumes that there is one.
        )r   r   rf   first)r(   r   s     r   _getRepeatExpressionCommandz$Expander._getRepeatExpressionCommand  s(       "556MNTTVVr   c                   | j                   | j                  z   | j                  z   }|dkD  ry| j                   dk(  r| j                  dk(  ry| j                  dk(  r| j                  dk(  ry| j                  dk(  r| j                  dk(  ryy)z6
        Check of a DC statement is coherent.
        r   Fr   Tr   )r   r   r   r   r   )r(   r   s     r   _daCapoIsCoherentzExpander._daCapoIsCoherent  s    
 /$//A19 ==A$//Q"6 __!doo&: __!doo&: r   c                "   | j                   | j                  z   | j                  z   | j                  z   }|dkD  ry| j                   dk(  r| j                  dk(  r| j
                  dk(  ry| j                  dk(  r| j                  dk(  r| j
                  dk(  ry| j                  dk(  r.| j
                  dk(  r| j                  dk(  r| j                  dk(  ry| j                  dk(  r.| j
                  dk(  r| j                  dk(  r| j                  dk(  ryy)z<
        Check of a sa segno statement is coherent.
        r   Fr   Tr   )r   r   r   r   r   r   r   )r(   r   s     r   _dalSegnoIsCoherentzExpander._dalSegnoIsCoherent  s   
 ==!??# ??# 19 MMQ$$)OOq(MMQ$$)OOq( oo"OOq($$)OOq( oo"OOq($$)OOq( r   c                   g }t        t        |            }g }g g d}d}|t        |      k  r||   }| j                  D ]  }|j	                  |      s|j
                  d   |v r|j                  |       g }g g d}||j
                  z  }|d   j                  |       |j                         }	|D ]c  \  }
}|
|k\  r,t        |      t        |	      k7  r|d   j                  |
       7t        |	      t        |      k(  sO|d   j                  |
          |dz  }|t        |      k  r|r|j                  |       |S )aZ  
        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   r  r	  r   )	r   r   r/   r   isFirstnumberRanger   getLastid)r(   r   groupsmEnumeratedfoundRBNumbersgroupIndicesr   r   r   mLastiSubmSubs               r   _groupRepeatBracketIndicesz#Expander._groupRepeatBracketIndices/  sV   6 9Y/0   
 #i. !A** ::a=~~a(N:l3)+:<PR'S"bnn4N !!1299"=JJLE&1
d  19DRY)>()9:AA$GY"T(2()9:AA$G " '2! +@ FAG #i. H MM,'r   c           	        | j                  | j                        D ]U  }|d   }|s yt        |      dk(  rnjt        |      dkD  r\g }|D ]  }||j                  z  } t	        t        dt        |      dz               }||k7  rt        j                  d| d| g        yg }t        |      D ]  \  }}|j                         }|j                         D ]C  }t        |      |v rt        j                  dg          y|j                  t        |             E |j                  }	|	d|	j                  vst        |      dk(  s|t        |      dz
  k  st        j                  d	g         y X y)
z
        Check if repeat brackets are coherent.

        This must be done for each group of brackets, not for the entire Stream.
        r  Tr   z0repeat brackets are not numbered consecutively: r   Fz!found overlapping repeat bracketsr   z8repeat brackets are not terminated with a repeat barline)r  r   r/   r  r   r   maxr   r   r   r  getSpannedElementsr  r   r   classes)
r(   group	rBracketstargetr   matchspannedMeasureIdsrbCountr   rightBars
             r   _repeatBracketsAreCoherentz#Expander._repeatBracketsAreCoherent~  s    44T5K5KLE ./I 9~"Y!##B
 bnn,F $ U1c&kAo67F? ++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                    t        t        |            D ]T  }||   }|j                  }|j                  }|d|j                  v r y|5d|j                  v sD|j
                  dk(  sT y y)zd
        Return True if this Stream of Measures has a repeat
        pair still to process.
        r   Tr   F)r   r/   r   r   r   r   )r(   r   r   r   r   r   s         r   
_hasRepeatzExpander._hasRepeat  sm     s9~&A!ABB ,;,;- ' r   c                L   g }g }t        t        |            D ]  }||   }	 |j                  }|j                  }|rd|j
                  v rd|j                  dk(  r|j                  |       nC|j                  dk(  r4|st        |      } t        |      S t        |d   |      } t        |      S |d|j
                  v s|j                  dk(  s|st        |dz         } t        |      S t        |d   |dz         } t        |      S  t        |      S # t        $ r Y 	w xY w)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   r/   r   r   AttributeErrorr   r   r   r   )r(   r   startIndicesbarRepeatIndicesr   r   r   r   s           r   findInnermostRepeatIndicesz#Expander.findInnermostRepeatIndices  sP   2  s9~&A!A]]^^ ~"6"++"E<<7* ''* \\U*'+08( $%% ,1b1A1+E( $%% ,;- $',QU|$ $%% (-\"-=q1u'E$$%%E 'D $%%9 " s   D	D#"D#c                f   ||   }|j                   }|,d|j                  v r|j                  dk(  r|}|j                  }nj|t	        |      dz
  k\  rt        d|       ||dz      }|j                  }|*d|j                  v r|j                  dk(  r|j                  }nt        d      |d}|||fS )a  
        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   r/   r   r   )r(   r   indexr  r   mEndBarlinerepeatTimesr   s           r   _getEndRepeatBarzExpander._getEndRepeatBar  s     % N(BKK7LLE)K((K I**'I%QS S $EAI.K((B,;- hh'(`aaKk;..r   Nc                >   t         j                  }|j                         }d}|| j                  |      }nd}d}d}	d}
|	t	        |      k  r<|s	 |S |	|d   k(  rd}d}	 | j                  ||d         \  }}}
||
}t        |      D ]  }|D ]{  }t        j                  ||         }||d   |d   fv r| j                  |       |dk\  r||dz
  k  r| j                  |       |dk7  r||dz
  dz     |_        |j                  |       }  ||urd}|d   dz   }	n^|sWt        j                  ||	         }||	   }|r'| j                  |       | j                  ||	          d}|j                  |       |	dz  }	|	t	        |      k  r<|S # t        $ r |s Y "w xY w)	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   r%  r   r      )stringascii_lowercaser*   r)  r/   r.  r   r   rA   rB   r   r   numberSuffixr   )r(   r   repeatIndicesr-  returnExpansionOnlylowercase_alphabetnewforcedIndicesstripFirstNextMeasurer   repeatTimesFoundr,  r  r   jr  junkr   s                     r   processInnermostRepeatBarsz#Expander.processInnermostRepeatBars8  s   d $33!!#   ;;IFM M !&#i.  X 
O M!$$";?;P;PQZQ^_aQb<d8E;(8 &"2K";/E +#}}Yq\: q!1=3D EE 55d;
 '!+a0G 88> A:0BEAIQSCS0TD-

4(! +	 00 +,0)!"%) +
  ==16D "!A
 -11!411)A,?05- JJqMQY #i. \ 
C ) ( )s    F FFc                   |i }| j                  |      }|s| j                  |      S | j                  |      }d}|D ]Z  }|s|d   }||d      }||d      }	|D ]7  }
t        |
      |v r n(|
j	                  |      s|
j	                  |	      r|} n9 |Z n || j                  |      S |d   }|d|d    }g }d}g }|D ]4  }
|
|t        |
      <   |d   }|
j                         }|
j                         }d}d}t        |      D ]8  \  }}t        |      t        |      k(  r|}t        |      t        |      k(  s7|}: ||t        d      |j                  }|'d|j                  v rt        t        ||dz               }nt        t        ||dz               }t        t        ||dz               }|'|D ]"  }|d   D ]  }||v s|j                  |        $ |
||d	}|j                  |       7 |D ]W  }|d
   	t        |d   j                         }| j                  ||d
   |d      }|j                  |       t#        |d
         }Y |j%                         }|D ]  }|j                  |        |D ]+  }|D ]$  }| j'                  |       |j                  |       & - ||dz   d }|D ]  }|j                  |        |S )a#  
        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
        Nr  r   r%  z6failed to find start or end index of bracket expansionr   r   bracketIndices)repeatBracketvalidIndicesr?  rA  r@  T)r4  r-  r5  )r  r=  r)  r  hasSpannedElementgetFirstr  r   r   r   r   r   r   r   r   r/   r  r  r*   r   ) r(   r   repeatBracketsMemor  	innermost
groupFocusr  r  mStartmEndr   streamObjPrestreamBracketRepeatshighestIndexRepeated
boundaries
startIndexmFirstr  endIndexbracketStartIndexr   r   mLastRightBarindicesr?  dataqr-  outr7  substreamObjPosts                                    r   #_processInnermostRepeatsAndBracketsz,Expander._processInnermostRepeatsAndBrackets  so    %!#
 00; 229== 33I>	
E./Iy|,FYr]+Db6//))&1R5I5I$5O!&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  (
 ""6":";<AJJqM 
r   c                    g }t        |      D ]\  \  }}|j                  t              D ]?  }||j                  v st	        |t
              r"t	        ||      s/|j                  |       A ^ |r|S y)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   r  r>   strr   )r(   r   r  r   r   r   r   s          r   getRepeatExpressionIndexz!Expander.getRepeatExpressionIndex  si    " i(DAq))*:;aii' *63 7Jq&<QKKN < ) Kr   c                   | j                         }|1| j                  | j                        st        j	                  d       y| j                         st        j	                  d       y| j                         st        j	                  d       y|_|t        k(  r'| j                         st        j	                  d       yy|t        k(  r&| j                         st        j	                  d       yy)	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   r#  r   r   r   r   r!  rj   r  r^   r  )r(   r  s     r   r   zExpander.isExpandable  s     ##%=1G1G!H##Q ))+##$>?..0##$FG--/ ++,=> 
 	 %//1 ++,=> r   c                    |du rt        j                  |      }i }d}|dkD  r3|dz
  }| j                  ||      }| j                  |      rn	 |S |dkD  r3|S )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   )rD  )rA   rB   rX  r#  )r(   r   makeDeepCopyrD  maxProcessess        r   r   z$Expander._processRecursiveRepeatBars  s     4i0IQ'!+L @@#5 A 7I
 y)
 # Q" r   c                   | j                         }| j                         }| j                  |      }| j                  ||      d   }|t        u rd}n)|t
        u r| j                  |d      d   }nt        d      |dv r| j                  |d      d   }nt        |      dz
  }|dv r| j                  |d      }|d   }	|d   }
nd	}	d	}
g }|j                  d|g       |dv r3|j                  ||	g       |j                  |
t        |      dz
  g       n|j                  ||g       |j                         }|d   j                  }|d}t        |      D ]  \  }}|j                         }t        |d   |d   dz         D ]7  }t        j                  ||         }||_
        |j                  |       |dz  }9 | j                  |      rO|dk(  r|j                   sn#| j#                  |      }|d
   j                  dz   }|D ]  }| j%                  |d        |D ]  }|j                  |         | j'                  |       |S )z
        Process and return a new Stream of Measures, likely a Part.
        Expand any repeat expressions found within.
        r   r^   zMust be DaCapo or Segno)rn   r{   ra   r   )rr   r   rY   Nr%  double)r   )r   r   r  r[  rj   r^   
ValueErrorr/   r   r*   r   r   r   rA   rB   r#  rh   r   r   r   )r(   r   capoOrSegnorecTyperecObjjumpBackr   r   codascodaJump	codaStartindexSegmentsr7  r   subCountrV  	subStreamr   r   s                      r   r   z+Expander._processRepeatExpressionAndRepeats  su    ))+66811)<00G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 '}5MHc!++-I3q63q6A:.MM)A,/!  #! / y) q=)?)? $ @ @ KI&r]11A5F"A--a-B # 

1 1 66 	$$S)
r   r   r   )r   r   )T)rB   boolreturnr   )r+  )rb  )r   stream.Stream)r   rp  ro  rn  )NNFrO   )ro  zbool | NoneF)r   r   r   r   r!   r   r   r   r   r   r   r   r  r  r  r  r!  r#  r)  r.  r=  rX  r[  r   r   r   
_DOC_ORDERr   r   r   r   r     s    FN$KL3j4l2&0d*?.W6*XM^;z,?&B$/P 26/37<	Wv @DWv8!F D[z \*Jr   r   c                      e Zd Zy)UnequalPartsLengthExceptionNr   r   r   r   rt  rt  o  r   r   rt  c                      e Zd Zy)InsufficientLengthExceptionNr   r   r   r   rv  rv  s  r   r   rv  c                      e Zd Zy)NoInternalStreamExceptionNr   r   r   r   rx  rx  w  r   r   rx  c                  n    e Zd ZU dZg dZddddZded<   dd
Zd Zd Z	d Z
d ZddZddddZddZy	)r   aL  
    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)defaultHashrK   r   zdict[str, str]	_DOC_ATTRNc                ~    ddl m} || _        ||j                  | _        n|| _        d | _        d | _        d| _        y )Nr   )searchT)r   r  rK   translateStreamToStringr~  _mList_mGroupsr   )r(   	inpStreamdefaultMeasureHashFunctionr  s       r   r!   zRepeatFinder.__init__  s>    "%-%==D9D%)"r   c                f   | j                   t        d      | j                   j                         r| j                   }n| j                   j                  d   }t	        |j                         j                               }t        |      dk  rt        d      |d   |d   z
  }|d   |d   z
  }||z  S )ai  
        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   )	rK   rx  r   r   r   measureOffsetMapkeysr/   rv  )r(   s2mOffsetspickupnormMeasures        r   r   z,RepeatFinder.getQuarterLengthOfPickupMeasure  s    L 66>+@  66BaB++-2245x=1-O  !x{*qkHQK/##r   c                V    | j                   t        d      | j                         dk7  S )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        )rK   rx  r   r4   s    r   r}  zRepeatFinder.hasPickup  s.    B 66>+,\]]335<<r   c                   ddl m} | j                  t        d      | j                  | j                  S | j
                  }| j                  }|j                         r|j                  |j                        g}n2|j                  D cg c]  }|j                  |j                         }}t        ||dd       D ]'  \  }}t        |      t        |      k7  st        d       t        t        |            D ]@  }t        t        ||               D 	cg c]  }	 |||   |	   j                         c}	||<   B t        t        |       }i }
t        t        |            D cg c]  }g  }}t        t        |      dz
  dd      D ]P  }dj!                  ||         }||
v r1||   j#                  |
|          ||   j%                  ||
|             ||
|<   R || _        |S c c}w c c}	w c c}w )	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.r%  r-   )r   r   rK   rx  r  r~  r   r   r   r   zipr/   rt  r   notesAndRestsr   joinr   extend)r(   r   hashFunctionrK   mListspmThismNextr   r;  tempDict_resmHashs                 r   r{  z%RepeatFinder.getMeasureSimilarityList  s   Z 	#66>+,\]];;";;''FF ==?**6>>:;FDEGGLGqa**6>>:GFL  qr
3LE55zSZ'1GI I 4 s6{#A s6!9~..A VAYq\778.F1I $ c6l# !V-.-ar-.s6{QB/AGGF1I&E Ahuo.Ac(5/23  HUO 0 
W M /s   	"G&G+&	G0c                   ||f|v ry|dz   ||dz      v r| j                  ||dz   |dz   ||      }|g|gf}|d   j                  |d          |d   j                  |d          |d   d   |d   d   k  rd||dz   |dz   f<   n:|d   d   |d   d   k\  r)|d   dd |d   dd f}|d   d   |d   d   k\  r"n|g|gf}||||f<   d|||f<   |S )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   r%  FT)_getSimilarMeasuresHelperr  )r(   r   sourcecompareresDictuseDictnextOner  s           r   r  z&RepeatFinder._getSimilarMeasuresHelper  s?   F G'q[HVaZ00 44Xvz7UV;6=w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           	        t        |       }i }i }t        t        |            D ]!  }||   D ]  }| j                  |||||        # t	        |      D ]  }||   r	||=  g }	|j                         D ]?  }
|
d   D cg c]  }||z   	 c}|
d   D cg c]  }||z   	 c}f}|	j                  |       A |	| _        |	S c c}w c c}w )a
  
        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   r/   r  r   valuesr   r  )r(   r   r}  pickupCorrectionr  usefulr   r   krealResmTupler;  	appendTups                r   _getSimilarMeasureTuplesz%RepeatFinder._getSimilarMeasureTuples  s    v 9}-s5z"A1X..uaCH  #
 cA!9F  jjlF8>q	B	1!..	B8>q	B	1!..	BDINN9% #
   CBs   >B?Cr   c               J   | j                         }| j                  || j                               }i }t        |d       }|r| j                  }n| j                  j                  d      }|t        d      g }g }	g }
|D ]  }d}|d   |d   z   }|D ]
  }||v sd	} n |r#|d   d   |d   d
   z
  dz
  }t        dt        |d         dz  dz         }t        |d         |k\  r=|dk(  r8|d   d   |d   d
   }}|
j                  ||f       |	j                  |d          njt        |d         |k\  rW||cxk\  rdkD  rLn nI|d   d   }|d   d
   dz   }|d   d   dz
  }|||f}|j                  |       |	j                  |d          n|D ]  }d	||<   	  |D ]M  \  }}}t        |||d	       ||z
  dz   }||z
  dz   }||z   }t        |||dd	       t        ||||z   dd	       O |
D ]  \  }}t        |||d	        t        ||	d	| j                         |s|S y)aH  
        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    dt        | d         z  | d   d   | d   d   fS Nr%  r   r   r/   xs    r   <lambda>z'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   Tr%  g      0@g       @r   r   r   )r{  r  r}  sortedrK   r   rx  minr/   r   r  r   r   r   r   )r(   repeatThresholdrepeatEndingThresholdr   r   mGroups	processedrK   repeatEndingBarsr   
repeatBarsmGroupalreadyProcessedmeasureNumbersmNumdistancemaxAcceptableDistancestartBarendBarstartingBarfirstEndingBarrepeatSignBartoProcessTuplelengthOfRepeatEndinglengthOfRepeatedSectionstartOfSecondEndings                             r   rz  zRepeatFinder.simplify9	  s   Z --///t~~7GH	 I A++,CDA9+Y  
F$#AY2N&9$'+$ '  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                2   | j                   J| j                  | j                         }n| j                  }| j                  || j	                               }n| j                   }|D cg c]  }t        |d         |k\  s| }}t        |d       }|S c c}w )a  
        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    dt        | d         z  | d   d   | d   d   fS r  r  r  s    r   r  z6RepeatFinder.getSimilarMeasureGroups.<locals>.<lambda> 
  s'    c!A$i1a!A$q'0Rr   r  )r  r  r{  r  r}  r/   r  )r(   	thresholdr   r  r  s        r   r|  z$RepeatFinder.getSimilarMeasureGroups	  s    : == {{"55733E4>>;KLGmmG%@gQqTi)?1g@ &RS As   'B>B)NNrq  )   r  r   )r   r   r   r   rr  r  __annotations__r!   r   r}  r{  r  r  rz  r|  r   r   r   r   r   }  sg    >JL Q!V!XI~ X*8$t$=LiV@Dpdre rh4r   r   __main__r  )r   r  )4r   
__future__r   rA   r1  typingr   music21.common.typesr   r   r   r   r   r   r	   r
   TYPE_CHECKINGr   Environmentr   ProtoM21Objectr   r   r   
Expressionr   rU   rY   r^   ra   rf   rj   rn   rr   ru   rx   r{   r   repeatExpressionReferencer   r   r   r   Genericr   rt  rv  rx  r   rr  r   mainTestr   r   r   <module>r     s7   #    +        ?? '{&&x0'' 8	 = = 	hz;#9#9 hV
&- 
&"! "," $%! %%. %4$ 4"4* 4*4* 4.4% 44& 4$4, 4&4, 42 	FEGTVVX|~NGIxz>+;^=M 5 5p ,1 <~ ,1 Zp	55 	a+qyy$ a+L'	,"?"? 		,"?"? 		 = = 	d
 d
T  6eT%v|GX~~|]
 zG r   