
    3jQ                    z   d Z ddlmZ ddlmZ ddlZddlZddlmZ ddlm	Z	 ddlm
Z
 ddlmZ dd	lmZ dd
lmZ  e	j"                  d      ZeZe Z G d de
j*                        Z G d dej.                        Z G d de      Z G d dej4                        ZeefZedk(  rddlZ ej<                  e       yy)z
Tools for grouping elements, timespans, and especially
pitched elements into kinds of searchable tree organized by start and stop offsets
and other positions.
    )annotations)infN)common)environment)exceptions21)	SortTuple)core)nodez
tree.treesc                      e Zd Zy)ElementTreeExceptionN)__name__
__module____qualname__     ?/DATA/.local/lib/python3.12/site-packages/music21/tree/trees.pyr   r   &   s    r   r   c                       e Zd ZU dZded<   ej                  ZdZd fd	Z	d Z
d Zd Zd	 Zd
 Zd Zd Zd Zd Zd dZd!dZd Zd Zd Zd Z fdZd!dZd Zd!dZd Zd Zd Ze d        Z!e!jD                  d        Z!e d        Z# xZ$S )"ElementTreea  
    A data structure for efficiently storing a score: flat or recursed or normal.

    This data structure has no connection to the XML ElementTree.

    This data structure stores ElementNodes: objects which implement both a
    `position` and `endTime` property. It provides fast lookups of such
    objects.

    >>> et = tree.trees.ElementTree()
    >>> et
    <ElementTree {0} (-inf to inf)>

    >>> s = stream.Stream()
    >>> for i in range(100):
    ...     n = note.Note()
    ...     n.duration.quarterLength = 2.0
    ...     s.insert(i * 2, n)

    >>> for n in s:
    ...     et.insert(n)
    >>> et
    <ElementTree {100} (0.0 <0.20...> to 200.0)>
    >>> et.rootNode
    <ElementNode: Start:126.0 <0.20...> Indices:(l:0 *63* r:100) Payload:<music21.note.Note C>>

    >>> n2 = s[-1]

    These operations are very fast

    >>> et.index(n2, n2.sortTuple())
    99

    Get a position after a certain position:

    >>> st = s[40].sortTuple()
    >>> st
    SortTuple(atEnd=0, offset=80.0, priority=0, classSortOrder=20, isNotGrace=1, insertIndex=...)
    >>> st2 = et.getPositionAfter(st)
    >>> st2.shortRepr()
    '82.0 <0.20...>'
    >>> st2.offset
    82.0

    >>> st3 = et.getPositionAfter(5.0)
    >>> st3.offset
    6.0
    >>> et.getPositionAfter(4.0).offset
    6.0
    znodeModule.ElementNode | NonerootNode)_sourceparentTreesc                    t         |           t        j                         | _        d | _        |r|| j                  |       || _        y N)super__init__weakrefWeakSetr   r   insertsource)selfelementsr   	__class__s      r   r   zElementTree.__init__j   s?    "??,,KK!r   c                    | j                   }|j                  |      }| j                  |      }||j                  |u ry| D ]  }||u s y y)a  
        Is true when the ElementTree contains the object within it

        If element.sortTuple(self.source) returns the right information, it's a fast
        O(log n) search. If not his is an O(n log n) operation in python not C, so slow.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> lastNote = score.flatten().notes[-1]
        >>> lastNote in scoreTree
        True
        >>> n = note.Note('E--')
        >>> n in scoreTree
        False

        >>> s = stream.Stream(id='tinyStream')
        >>> s.insert(0, n)
        >>> st = s.asTree(flatten=False)
        >>> n in st
        True
        TF)r   	sortTuplegetNodeByPositionpayload)r    elementssourcePositionnodeAtPositionpls         r   __contains__zElementTree.__contains__t   sa    . KK **1- //?%%%0 BW}  r   c                
    | |u S )a)  
        Two ElementTrees are equal only if they are the same object.

        >>> et1 = tree.trees.ElementTree()
        >>> et2 = tree.trees.ElementTree()
        >>> et3 = et1
        >>> et1 == et2
        False
        >>> et1 == et3
        True

        >>> et2 != et1
        True
        r   r    exprs     r   __eq__zElementTree.__eq__   s     t|r   c                    	 | j                  |      }||S t        |t              s|j                  S |D cg c]  }|j                   c}S # t        $ r Y yw xY wc c}w )a_  
        Gets elements by integer index or slice.  This is pretty fast in computational time
        (O(log n)), but it's O(log n) in Python while normal list slicing is O(1) in C, so
        don't use trees for __getitem__ searching if you don't have to.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> scoreTree
        <ElementTree {20} (0.0 <0.-25...> to 8.0) <music21.stream.Score exampleScore>>

        >>> scoreTree[0]
        <music21.instrument.Instrument 'PartA: : '>

        >>> scoreTree[-1]
        <music21.bar.Barline type=final>

        >>> scoreTree[2000] is None
        True

        Slices work

        >>> scoreTree[2:5]
        [<music21.clef.BassClef>, <music21.clef.BassClef>, <music21.meter.TimeSignature 2/4>]

        >>> scoreTree[-6:-3]
        [<music21.note.Note A>, <music21.note.Note B>, <music21.note.Note D#>]

        >>> scoreTree[-100:-200]
        []

        >>> for x in scoreTree[:]:
        ...     x
        <music21.instrument.Instrument 'PartA: : '>
                ...
        <music21.bar.Barline type=final>

        These should all be the same as the flat version:

        >>> scoreFlat = score.flatten()
        >>> for i in (0, -1, 10):
        ...     if scoreFlat[i] is not scoreTree[i]:
        ...          print('false!')

        >>> for i, j in ((2, 5), (-6, -3)):
        ...     sfSlice = scoreFlat[i:j]
        ...     for n in range(i, j):
        ...         sliceOffset = n - i
        ...         if sfSlice[sliceOffset] is not scoreFlat[n]:
        ...             print('false!')
        N)getNodeByIndex
IndexError
isinstancelistr&   )r    inodeOrNodeListns       r   __getitem__zElementTree.__getitem__   sm    h	!003N !!!ND1!)))'56~!AII~66  		 7s   A A	AAc                @    t        t        |       t        |       f      S r   )hashtypeidr    s    r   __hash__zElementTree.__hash__   s    T$ZD*++r   c                H    | j                   y| j                   j                  S )a  
        Gets the length of the ElementTree, i.e., the number of elements enclosed.
        This is a very very fast O(1).

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> len(scoreTree)
        20

        Works well on OffsetTrees also, which are more complex, because they can
        have multiple elements per Node.

        >>> offTree = tree.trees.OffsetTree()
        >>> len(offTree)
        0

        >>> tsList = [(0, 2), (0, 9), (1, 1), (2, 3), (3, 4),
        ...           (4, 9), (5, 6), (5, 8), (6, 8), (7, 7)]
        >>> noteList = [note.Note() for _ in tsList]
        >>> for i,n in enumerate(noteList):
        ...     n.offset, n.quarterLength = tsList[i]
        >>> offTree.insert(noteList)
        >>> len(offTree)
        10
        >>> len(offTree) == len(noteList)
        True

        >>> offTree.removeElements(noteList)
        >>> len(offTree)
        0
        r   )r   subtreeElementsStopIndexr>   s    r   __len__zElementTree.__len__   s"    @ == }}555r   c           	     `   | j                   }| j                         }| j                  }t        |d      r|j	                         }t        |d      r|j	                         }t        |       j                  }dt        t        |             z   dz   }d| d| d| d| d	}||d|z  }|d	z  }|S )
N	shortRepr{}< z (z to )>)	r   lowestPositionendTimehasattrrD   r<   r   strlen)r    oposrL   	classNamelenEnclosedmsgs          r   __repr__zElementTree.__repr__  s    KK!!#,,3$--/C7K('')GJ''	CD	N*S0)Ak]"SEgYa@=Qqe9Cs

r   c           	     F   t        |t              r4| j                  |      }|dt        |        }t	        |      ||_        yt        |t              rt        |t              sd| d| d}t	        |      |j                  |j                  z
  |j                  z  }|t        |      k7  r!| d| d| dt        |       }t	        |      t        t        |j                  |j                  |j                              D ]  \  }}||   | |<    yd	| }t	        |      )
a  
        Sets elements at index `i` to `new`, but keeping the old position
        of the element there. (This is different from OffsetTrees, where things can move around).

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> n = scoreTree[10]
        >>> n
        <music21.note.Note G#>
        >>> scoreTree.getNodeByIndex(10)
        <ElementNode: Start:2.0 <0.20...> Indices:(l:10 *10* r:11)
            Payload:<music21.note.Note G#>>

        >>> scoreTree[10] = note.Note('F#')
        >>> scoreTree[10]
        <music21.note.Note F#>
        >>> scoreTree.getNodeByIndex(10)
        <ElementNode: Start:2.0 <0.20...> Indices:(l:10 *10* r:11)
            Payload:<music21.note.Note F#>>

        >>> scoreTree[10:13]
        [<music21.note.Note F#>, <music21.note.Note F>, <music21.note.Note G>]
        >>> scoreTree[10:14:2] = [note.Note('E#'), note.Note('F-')]
        >>> scoreTree[10:13]
        [<music21.note.Note E#>, <music21.note.Note F>, <music21.note.Note F->]
        NzIndex must be less than zIf z is a slice, then z must be a listz is a slice of len z, so z cannot have len z$Indices must be ints or slices, got )r4   intr2   rO   	TypeErrorr&   slicer5   stopstartstep	enumeraterange)r    r6   newr8   messagesliceLenj	sliceIters           r   __setitem__zElementTree.__setitem__'  s    8 a##A&Ay4SYK@((AI5!c4(s"4SEI(((AFF2H3s8#C28*E#FWX[\_X`Wab(( )%*H I9"%a&Y !J =QC@GG$$r   c                    g }|j                  t        |              | D ]>  }t        |      j                         }|D cg c]  }d|z   	 }}|j	                  |       @ dj                  |      }|S c c}w )a  
        Print the whole contents of the tree.

        Slow: O(n log n) time, but it's just for debugging

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> print(scoreTree)
        <ElementTree {20} (0.0 <0.-25...> to 8.0) <music21.stream.Score exampleScore>>
            PartA: :
            PartB: :
            <music21.clef.BassClef>
            <music21.clef.BassClef>
            <music21.meter.TimeSignature 2/4>
            <music21.meter.TimeSignature 2/4>
            <music21.note.Note C>
            <music21.note.Note C#>
            <music21.note.Note D>
            <music21.note.Note E>
            <music21.note.Note G#>
            <music21.note.Note F>
            <music21.note.Note G>
            <music21.note.Note E#>
            <music21.note.Note A>
            <music21.note.Note B>
            <music21.note.Note D#>
            <music21.note.Note C>
            <music21.bar.Barline type=final>
            <music21.bar.Barline type=final>
        	
)appendreprrN   
splitlinesextendjoin)r    resultx	subResults       r   __str__zElementTree.__str__W  ss    > d4j!AA))+I+459a9I5MM)$  6" 6s   A3c              #  R   K   | j                         D ]  }|j                    yw)a  
        Iterates through all the nodes in the offset tree and returns each node's payload

        Not an especially efficient way of using this beautiful tree object!  But useful
        for debugging or a final iteration for conversion.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> for x in scoreTree:
        ...     print(x)
        PartA: :
        PartB: :
        <music21.clef.BassClef>
        <music21.clef.BassClef>
        <music21.meter.TimeSignature 2/4>
        <music21.meter.TimeSignature 2/4>
        <music21.note.Note C>
        <music21.note.Note C#>
        ...

        N	iterNodesr&   )r    r
   s     r   __iter__zElementTree.__iter__  s#     , NN$D,, %s   %'c                    | j                   4| j                   j                          | j                   j                          | j                         |k7  s| j                  |k7  r| j                  ||       yy)a  
        runs updateIndices and updateEndTimes on the rootNode
        and if the offset or endTime of the tree differs from
        `initialPosition` or `initialEndTime` will run _updateParents()
        as well.

        Called by insert() and remove().
        N)visitedParents)r   updateIndicesupdateEndTimesrK   rL   _updateParents)r    initialPositioninitialEndTimerv   s       r   _updateNodeszElementTree._updateNodes  sc     ==$MM'')MM((*!_4<<>1O 2r   c                    |
t               }| j                  D ]1  }|||v r
|j                  |       |j                  | |       t         y)zt
        Tells all parents that the position of this tree has
        changed.

        Not currently used.
        N)setr   add_removeElementAtPositionNotImplementedError)r    oldPositionrv   parents       r   ry   zElementTree._updateParents  sT     ! UN&&F~>!9v&++D+>%% 'r   c                V   | j                  |      }|yt        |j                  t              rH||j                  v r|j                  j	                  |       |j                  s| j                  |       yy|j                  |u rd|_        |j                  | j                  |       yy)z
        removes an element or ElementTree from a position
        (either its current .offset or its oldPosition) without updating
        the indices, endTimes, etc.
        N)r%   r4   r&   r5   remove
removeNode)r    r'   positionr
   s       r   r   z$ElementTree._removeElementAtPosition  s     %%h/<dllD)$,,&##G,<<)   ||w&#||#) $r   c                8    |j                  | j                        S a  
        A quick but dirty method for getting the likely position (or offset) of an element
        within the elementTree from the element itself.  Such as calling

        el.getOffsetBySite(tree.source) or something like that.

        Pulled out for subclassing
        )r$   r   r    els     r   getPositionFromElementUnsafez(ElementTree.getPositionFromElementUnsafe  s     ||DKK((r   c                J    dfd| j                    |d      | _        y)a  
        This method assumes that the current tree is empty (or will be wiped) and
        that listOfTuples is a non-empty
        list where the first element is a unique position to insert,
        and the second is the complete payload for that node, and
        that the positions are strictly increasing in order.

        This is about an order of magnitude faster (3ms vs 21ms for 1000 items; 31 vs. 30ms for
        10,000 items) than running createNodeAtPosition() for each element in a list if it is
        already sorted.  Thus, it should be used when converting a
        Stream where .isSorted is True into a tree.

        If any of the conditions is not true, expect to get a dangerously
        badly sorted tree that will be useless.

        >>> bFlat = corpus.parse('bwv66.6').flatten()
        >>> bFlat.isSorted
        True

        >>> listOfTuples = [(e.sortTuple(bFlat), e) for e in bFlat]
        >>> listOfTuples[14]
        (SortTuple(atEnd=0, offset=0.0, priority=0, ...),
         <music21.key.Key of f# minor>)

        >>> et = tree.trees.ElementTree()
        >>> et.rootNode is None
        True
        >>> et.populateFromSortedList(listOfTuples)
        >>> et.rootNode
        <ElementNode: Start:14.5 <0.20...> Indices:(l:0 *99* r:199)
            Payload:<music21.note.Note A>>

        >>> n = et.rootNode
        >>> while n is not None:
        ...    print(n)
        ...    n = n.leftChild
        <ElementNode: Start:14.5 <0.20...> Indices:(l:0 *99* r:199) Payload:<music21.note.Note A>>
        <ElementNode: Start:5.5 <0.20...>  Indices:(l:0 *49* r:99) Payload:<music21.note.Note A>>
        <ElementNode: Start:0.0 <0.20...>  Indices:(l:0 *24* r:49) Payload:<music21.note.Note A>>
        <ElementNode: Start:0.0 <0.1...>   Indices:(l:0 *12* r:24)
            Payload:<music21.tempo.MetronomeMark Quarter=96 (playback only)>>
        <ElementNode: Start:0.0 <0.0...>   Indices:(l:0 *6* r:12) Payload:<music21.clef.TrebleClef>>
        <ElementNode: Start:0.0 <0.-25...> Indices:(l:0 *3* r:6)
            Payload:<music21.instrument.Instrument 'P3: Tenor: Instrument 3'>>
        <ElementNode: Start:0.0 <0.-25...> Indices:(l:0 *1* r:3)
            Payload:<music21.instrument.Instrument 'P1: Soprano: Instrument 1'>>
        <ElementNode: Start:0.0 <0.-30...> Indices:(l:0 *0* r:1)
            Payload:<music21.metadata.Metadata object at 0x104adbdd8>>

        >>> n = et.rootNode
        >>> while n is not None:
        ...    print(n)
        ...    n = n.rightChild
        <ElementNode: Start:14.5 <0.20...> Indices:(l:0 *99* r:199)
            Payload:<music21.note.Note A>>
        <ElementNode: Start:25.0 <0.20...> Indices:(l:100 *149* r:199)
            Payload:<music21.note.Note G#>>
        <ElementNode: Start:31.0 <0.20...> Indices:(l:150 *174* r:199)
            Payload:<music21.note.Note B>>
        <ElementNode: Start:34.0 <0.20...> Indices:(l:175 *187* r:199)
            Payload:<music21.note.Note D>>
        <ElementNode: Start:35.0 <0.20...> Indices:(l:188 *193* r:199)
            Payload:<music21.note.Note A#>>
        <ElementNode: Start:36.0 <0.-5...> Indices:(l:194 *196* r:199)
            Payload:<music21.bar.Barline type=final>>
        <ElementNode: Start:36.0 <0.-5...> Indices:(l:197 *198* r:199)
            Payload:<music21.bar.Barline type=final>>
        c                   t        |       }|dk(  ry|dz  }| |   } |d   |d         }||z   |_        ||_        ||z   |_         | d| |      |_         | |dz   d ||z   dz         |_        |j                          |S )z-
            Divide and conquer.
            r   N      )rO   payloadElementIndexsubtreeElementsStartIndexrA   	leftChild
rightChildupdate)subListOfTuplesglobalStartOffsetlenLmidpointmidtupler8   	NodeClassrecurses         r   r   z3ElementTree.populateFromSortedList.<locals>.recurse(  s     'DqyqyH&x0H(1+x{3A$5$@A!*;A'):T)AA&!/)8"<"35AK"?8a<=#A#4x#?!#CEALHHJHr   r   N)returnzcore.AVLNode | None)	nodeClassr   )r    listOfTuplesr   r   s     @@r   populateFromSortedListz"ElementTree.populateFromSortedList  s"    L	( NN	a0r   c                   fdfdt        |t              rg| j                  t        |dk  r| j                  j                  |z   }|dk  s| j                  j                  |k  rt         | j                  |      S t        |t
              rQ| j                  g S |j                  | j                  j                        }|d   |d   }} | j                  ||      S t        d|       )a  
        Get a node whose element is at a particular index (not position).  Works with slices too

        See __getitem__ for caveats about speed.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> scoreTree
        <ElementTree {20} (0.0 <0.-25...> to 8.0) <music21.stream.Score exampleScore>>

        >>> scoreTree.getNodeByIndex(0)
        <ElementNode: Start:0.0 <0.-25...> Indices:(l:0 *0* r:2)
            Payload:<music21.instrument.Instrument 'PartA: : '>>

        >>> scoreTree.getNodeByIndex(-1)
        <ElementNode: Start:End <0.-5...> Indices:(l:19 *19* r:20)
            Payload:<music21.bar.Barline type=final>>

        >>> scoreTree.getNodeByIndex(slice(2, 5))
        [<ElementNode: Start:0.0 <0.0...> Indices:(l:0 *2* r:4) Payload:<music21.clef.BassClef>>,
         <ElementNode: Start:0.0 <0.0...> Indices:(l:3 *3* r:4) Payload:<music21.clef.BassClef>>,
         <ElementNode: Start:0.0 <0.4...> Indices:(l:0 *4* r:8)
             Payload:<music21.meter.TimeSignature 2/4>>]

        >>> scoreTree.getNodeByIndex(slice(-6, -3))
        [<ElementNode: Start:5.0 <0.20...> Indices:(l:9 *14* r:20) Payload:<music21.note.Note A>>,
         <ElementNode: Start:6.0 <0.20...> Indices:(l:15 *15* r:17) Payload:<music21.note.Note B>>,
         <ElementNode: Start:6.0 <0.20...> Indices:(l:16 *16* r:17) Payload:<music21.note.Note D#>>]

        >>> scoreTree.getNodeByIndex(slice(-100, -200))
        []
        c                    | j                   |k(  r| S | j                  r"|| j                   k  r | j                  |      S | j                  r#| j                   |k  r | j                  |      S yy)zB
            Return the node element at a given index
            N)r   r   r   r
   indexrecurseByIndexs     r   r   z2ElementTree.getNodeByIndex.<locals>.recurseByIndex`  sj     ''50ED,D,D$D%dnne<<T%=%=%F%doou== &Gr   c                ^   g }| |S || j                   k  r/| j                  r#|j                   | j                  ||             || j                   cxk  r|k  rn n|j                  |        | j                   |k  r/| j                  r#|j                   | j                  ||             |S )zo
            Return a slice of the nodes (plural) whose indices are between start <= index < stop.
            )r   r   rk   rh   r   )r
   r[   rZ   rm   recurseBySlices       r   r   z2ElementTree.getNodeByIndex.<locals>.recurseBySlicek  s     F|t///DNNnT^^UDIJ00747d#''$.4??nT__eTJKMr   r   r   (Indices must be integers or slices, got r4   rW   r   r3   rA   rY   indicesrX   r    r6   r   outer_start
outer_stopr   r   s        @@r   r2   zElementTree.getNodeByIndex?  s    B		>	 a}}$  1uMM::Q>1u>>!C  !$--335!}}$	ii F FGG&-aj'!*K!$--jIIFqcJKKr   c              #  <   K   t         |          D ]  }|  yw)a{  
        Identical to the iterating on a core.AVLTree -- yields each node in order

        Slow: O(n log n) time so don't make this your main thing.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True)
        >>> scoreTree
        <ElementTree {20} (0.0 <0.-25...> to 8.0) <music21.stream.Score exampleScore>>

        >>> for node in scoreTree.iterNodes():
        ...     print(node)
        <ElementNode: Start:0.0 <0.-25...> Indices:(l:0 *0* r:2)
                Payload:<music21.instrument.Instrument 'PartA: : '>>
        <ElementNode: Start:0.0 <0.-25...> Indices:(l:1 *1* r:2)
                Payload:<music21.instrument.Instrument 'PartB: : '>>
        <ElementNode: Start:0.0 <0.0...> Indices:(l:0 *2* r:4) Payload:<music21.clef.BassClef>>
        <ElementNode: Start:0.0 <0.0...> Indices:(l:3 *3* r:4) Payload:<music21.clef.BassClef>>
        <ElementNode: Start:0.0 <0.4...> Indices:(l:0 *4* r:8)
                Payload:<music21.meter.TimeSignature 2/4>>
        <ElementNode: Start:0.0 <0.4...> Indices:(l:5 *5* r:6)
                Payload:<music21.meter.TimeSignature 2/4>>
        <ElementNode: Start:0.0 <0.20...> Indices:(l:5 *6* r:8) Payload:<music21.note.Note C>>
        <ElementNode: Start:0.0 <0.20...> Indices:(l:7 *7* r:8) Payload:<music21.note.Note C#>>
        <ElementNode: Start:1.0 <0.20...> Indices:(l:0 *8* r:20) Payload:<music21.note.Note D>>
        <ElementNode: Start:2.0 <0.20...> Indices:(l:9 *9* r:11) Payload:<music21.note.Note E>>
            ...
        <ElementNode: Start:7.0 <0.20...> Indices:(l:15 *17* r:20)
                Payload:<music21.note.Note C>>
        <ElementNode: Start:End <0.-5...> Indices:(l:18 *18* r:20)
                Payload:<music21.bar.Barline type=final>>
        <ElementNode: Start:End <0.-5...> Indices:(l:19 *19* r:20)
                Payload:<music21.bar.Barline type=final>>
        N)r   rt   )r    r8   r"   s     r   rs   zElementTree.iterNodes  s!     J !#AG $s   c                    || j                  |      }| j                  |      }||j                  |ur,t        |       D ]  \  }}||u s|c S  t	        | d| d      |j
                  S )a  
        Gets index of `element` in tree. position could be none.

        If the element is in the original score, then it should be very fast (O(log n))

        >>> score = tree.examples.makeExampleScore()
        >>> scoreFlat = score.flatten()
        >>> n = scoreFlat.notes[-1]

        >>> flatTree = scoreFlat.asTree()
        >>> flatTree.index(n)
        17

        If it's not in the original stream, then it should be slower than doing
        it on a stream (O (n log n)).

        >>> scoreTree = score.asTree(flatten=True)
        >>> n = score.flatten().notes[-1]
        >>> scoreTree.index(n)
        17

        And if it's nowhere at all, you get a ValueError!

        >>> scoreTree.index(note.Note('F-'))
        Traceback (most recent call last):
        ValueError: <music21.note.Note F-> not in Tree at position
            SortTuple(atEnd=0, offset=0.0, priority=0, ...).
        z not in Tree at position .)r   r%   r&   r]   
ValueErrorr   )r    r'   r   r
   r6   r8   s         r   r   zElementTree.index  s    < 88AH%%h/<4<<w6!$1<H ( y(A(1MNN'''r   c                J    |D cg c]  }| j                  |       c}S c c}w )z
        takes a list of elements and returns a list of positions.

        In an ElementTree, this will be a list of .sortTuple() calls.

        In an OffsetTree, this will be a list of .offset calls

        )r   )r    r!   r   s      r   _getPositionsFromElementsz%ElementTree._getPositionsFromElements  s)     AII"11"5IIIs    c                   | j                         }| j                  }||}d}n&|}t        j                  |      rt	        |d      r|g}t        j                  |      st        |t        t        f      s|g}|| j                  |      }t        |      D ]  \  }}||   }| j                  ||        | j                  ||       y)a  
        Inserts elements or `Timespans` into this tree.

        >>> n = note.Note()
        >>> ot = tree.trees.OffsetTree()
        >>> ot
        <OffsetTree {0} (-inf to inf)>
        >>> ot.insert(10.0, n)
        >>> ot
        <OffsetTree {1} (10.0 to 11.0)>

        >>> n2 = note.Note('D')
        >>> n2.offset = 20
        >>> n3 = note.Note('E')
        >>> n3.offset = 5
        >>> ot.insert([n2, n3])
        >>> ot
        <OffsetTree {3} (5.0 to 21.0)>
        NrD   )rK   rL   r   
isListLikerM   r4   r~   	frozensetr   r]   _insertCorer|   )	r    positionsOrElementsr!   rz   r{   	positionsr6   r   rQ   s	            r   r   zElementTree.insert  s    ( --/*HI+I$$Y/79k3R&K	!!(+"8c9-=> zH66x@Ix(EArA,CS"% ) 	/>:r   c                V    | j                  |       | j                  |      }||_        y)
        Inserts a single element at an offset, creating new nodes as necessary,
        but does not updateIndices or updateEndTimes or updateParents
        N)createNodeAtPositionr%   r&   r    r   r   r
   s       r   r   zElementTree._insertCore  s)    
 	!!(+%%h/r   c                V    fd| j                    | j                         S t        S )a!  
        Gets the latest position in this tree.

        Keep as a property, because a similar property exists on streams.

        >>> score = corpus.parse('bwv66.6')
        >>> tsTree = score.asTimespans(classList=(note.Note,))
        >>> tsTree.highestPosition()
        35.0
        c                X    | j                    | j                         S | j                  S r   )r   r   r
   r   s    r   r   z,ElementTree.highestPosition.<locals>.recurse'  s&    *t//}}$r   r   NEGATIVE_INFINITYr    r   s    @r   highestPositionzElementTree.highestPosition  s)    	% ==$4==))$$r   c                V    fd| j                    | j                         S t        S )a7  
        Gets the earliest position in this tree.

        >>> score = tree.examples.makeExampleScore()
        >>> elTree = score.asTree()
        >>> elTree.lowestPosition().shortRepr()
        '0.0 <0.-20...>'

        >>> tsTree = score.asTimespans()
        >>> tsTree.lowestPosition()
        0.0
        c                X    | j                    | j                         S | j                  S r   )r   r   r   s    r   r   z+ElementTree.lowestPosition.<locals>.recurse?  s&    ~~)t~~..== r   r   r   s    @r   rK   zElementTree.lowestPosition2  s)    	!
 ==$4==))$$r   c                @    t        j                  | j                        S )aJ  
        the original stream. (stored as a weakref but returned unwrapped)

        >>> example = tree.examples.makeExampleScore()
        >>> eTree = example.asTree()
        >>> eTree.source is example
        True

        >>> s = stream.Stream()
        >>> eTree.source = s
        >>> eTree.source is s
        True
        )r   unwrapWeakrefr   r>   s    r   r   zElementTree.sourceJ  s     ##DLL11r   c                8    t        j                  |      | _        y r   )r   wrapWeakrefr   r.   s     r   r   zElementTree.source[  s     ))$/r   c                R    | j                   | j                   j                  S t        S )a  
        Gets the latest stop position in this element-tree.

        This is cast as a property so that it can be used like a TimeSpan in a TimeSpanTree

        >>> score = corpus.parse('bwv66.6')
        >>> tsTree = score.asTree()
        >>> tsTree.endTime
        36.0

        Returns infinity if no elements exist:

        >>> et = tree.trees.ElementTree()
        >>> et.endTime
        inf
        )r   endTimeHighINFINITYr>   s    r   rL   zElementTree.endTime`  s#    $ ==$==,,,r   )NN)NNNr   )%r   r   r   __doc____annotations__
nodeModuleElementNoder   	__slots__r   r,   r0   r9   r?   rB   rU   rd   rp   rt   r|   ry   r   r   r   r2   rs   r   r   r   r   r   rK   propertyr   setterrL   __classcell__)r"   s   @r   r   r   ,   s    1f *) &&II
%N">7@,"6H(.%`&P6P"&**.	)[1zJLX&P'(R	J*;X%,%0 2 2  ]]0 0  r   r   c                      e Zd ZU dZdZded<   ej                  Zd Z	d Z
d Zed        Zd	 Zd
 Zed        Zd Zd Zd Zd Zd ZddZd Zd ZddZd Zd Zy)
OffsetTreez
    A tree representation where positions are offsets in the score
    and each node has a payload which is a list of elements at
    that offset (unsorted by sort order).
    r   znodeModule.OffsetNode | Noner   c                    	 |j                   }| j                  |      }||v ryy# t        $ r}t        d      |d}~ww xY w)a  
        Is true when the ElementTree contains the object within it;

        TRUE IF and ONLY if the
        .offset of the element matches the position in the tree -- thus it is very fast!

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True, groupOffsets=True)

        >>> score.flatten()[5] in scoreTree
        True

        Note that this way of finding an item won't work because the offset is different
        from the flat offset:

        >>> n = score.parts[0].measure(2).notes[1]
        >>> n
        <music21.note.Note F>
        >>> n.offset
        1.0
        >>> n in scoreTree
        False
        z7element must be a Music21Object, i.e., must have offsetNTF)offsetAttributeErrorr   elementsStartingAt)r    r'   r   ae
candidatess        r   r,   zOffsetTree.__contains__  sU    0	^^F
 ,,V4
j   	&I	s   % 	?:?c                   fddfdt        |t              rg| j                  t        |dk  r| j                  j                  |z   }|dk  s| j                  j                  |k  rt         | j                  |      S t        |t
              rQ| j                  g S |j                  | j                  j                        }|d   |d   }} | j                  ||      S t        d|       )a\  
        Gets elements by integer index or slice.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True, groupOffsets=True)

        >>> scoreTree[0]
        <music21.instrument.Instrument 'PartA: : '>

        >>> scoreTree[-1]
        <music21.bar.Barline type=final>

        >>> scoreTree[2:5]
        [<music21.clef.BassClef>, <music21.clef.BassClef>, <music21.meter.TimeSignature 2/4>]

        >>> scoreTree[-6:-3]
        [<music21.note.Note A>, <music21.note.Note B>, <music21.note.Note D#>]

        >>> scoreTree[-100:-200]
        []
        c                <   | j                   |cxk  r| j                  k  rn n| j                  || j                   z
     S | j                  r"|| j                   k  r | j                  |      S | j                  r#| j                  |k  r | j                  |      S yy)zE
            Return the payload element at a given index
            N)payloadElementsStartIndexpayloadElementsStopIndexr&   r   r   r   s     r   r   z.OffsetTree.__getitem__.<locals>.recurseByIndex  s     --V9V9VV||ED,J,J$JKKED,J,J$J%dnne<<T%B%Be%K%doou== &Lr   c                   g }| |S || j                   k  r/| j                  r#|j                   | j                  ||             || j                  k  rW| j                   |k  rH|| j                   z
  }t	        |d      }|| j                   z
  }|j                  | j
                  ||        | j                  |k  r/| j                  r#|j                   | j                  ||             |S )zf
            Return a slice of the payload elements (plural) where start <= index < stop.
            r   )r   r   rk   r   maxr&   r   )r
   r[   rZ   rm   
indexStart	indexStopr   s         r   r   z.OffsetTree.__getitem__.<locals>.recurseBySlice  s     F|t555$..nT^^UDIJt4449W9WZ^9^"T%C%CC
 Q/
 4#A#AA	dll:i@A,,4nT__eTJKMr   r   r   r   )r
   znodeModule.OffsetNoder   r   s        @@r   r9   zOffsetTree.__getitem__  s    ,		>	$ a}}$  1uMM::Q>1u>>!C  !$--335!}}$	ii F FGG&-aj'!*K!$--jIIFqcJKKr   c              #  `   K   | j                         D ]  }|j                  D ]  }|   yw)au  
        Iterates through all the nodes in the offset tree and returns each thing
        in the payload.

        Not an especially efficient way of using this beautiful tree object.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True, groupOffsets=True)
        >>> for x in scoreTree:
        ...     print(x)
        PartA: :
        PartB: :
        <music21.clef.BassClef>
        <music21.clef.BassClef>
        <music21.meter.TimeSignature 2/4>
        <music21.meter.TimeSignature 2/4>
        <music21.note.Note C>
        <music21.note.Note C#>
        ...

        Nrr   )r    r
   r   s      r   rt   zOffsetTree.__iter__$  s,     , NN$Dll # %s   ,.c                H    |j                   | j                  j                  z   S )z
        Use so that both OffsetTrees, which have elements which do not have a .endTime, and
        TimespanTrees, which have element that have an .endTime but not a duration, can
        use most of the same code.
        )r   durationquarterLength)r   r
   s     r   elementEndTimezOffsetTree.elementEndTime?  s     }}r{{8888r   c                    |j                   S r   )r   r   s     r   r   z'OffsetTree.getPositionFromElementUnsafeI  s     yyr   c                    | j                         }| j                  }|t        k(  rd}| j                  ||       | j	                  |d       y)zJ
        Add an element to the end, making certain speed savings.
        r   N)r{   )rK   rL   r   r   r|   )r    r   rz   rL   s       r   rh   zOffsetTree.appendT  sK     --/,,hG"%/$?r   c                (    | j                         dd S )z
        Payload sorting is done the old-fashioned way, because
        the number of elements at a single offset should be few enough that
        it is not a problem
        r   N)r$   )rn   s    r   _insertCorePayloadSortKeyz$OffsetTree._insertCorePayloadSortKey_  s     {{}QR  r   c                    | j                  |       | j                  |      }|j                  j                  |       |j                  j	                  | j
                         y)r   )keyN)r   r%   r&   rh   sortr   r   s       r   r   zOffsetTree._insertCoreh  sO    
 	!!(+%%h/Bd<<=r   c                     t        |              }|j                  t        |              | j                  |_        | j                  j                         |_        |S )a  
        Creates a new tree with the same payload as this tree.

        This is analogous to `dict.copy()`.

        Much, much faster than creating a new tree; creating one
        with 3600 items took 500ms.  Creating the tree the first time
        was 40 seconds, so about an 80x speedup.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTimespans()
        >>> newTree = scoreTree.copy()
        >>> newTree
        <TimespanTree {20} (0.0 to 8.0) <music21.stream.Score exampleScore>>

        >>> scoreTree[16]
        <PitchedTimespan (6.0 to 8.0) <music21.note.Note D#>>
        >>> newTree[16]
        <PitchedTimespan (6.0 to 8.0) <music21.note.Note D#>>

        >>> scoreTree[16] is newTree[16]
        True
        )r<   r   r5   r   r   copy)r    newTrees     r   r   zOffsetTree.copys  sH    2 $t*,tDz""..335r   c                   g }| j                  |      }|gt        |j                  t              r&|j	                  |j                         t        |      S |j                  |j                  |j                         t        |      S )a  
        Finds elements or timespans in this tree which start at `position`.

        >>> score = corpus.parse('bwv66.6')
        >>> scoreTree = score.asTimespans()
        >>> for timespan in scoreTree.elementsStartingAt(0.5):
        ...     timespan
        ...
        <PitchedTimespan (0.5 to 1.0) <music21.note.Note B>>
        <PitchedTimespan (0.5 to 1.0) <music21.note.Note B>>
        <PitchedTimespan (0.5 to 1.0) <music21.note.Note G#>>
        )r%   r4   r&   r5   rk   rh   tuple)r    r   resultsr
   s       r   r   zOffsetTree.elementsStartingAt  so     %%h/$,,-t||, W~ )t||,W~r   c                P      fd  j                         }t        |      S )a  
        Finds elements in this OffsetTree which stop at `offset`.  Elements are ordered
        according to (start) offset.

        >>> score = corpus.parse('bwv66.6')
        >>> scoreTree = score.asTree(flatten=True, groupOffsets=True)
        >>> for el in scoreTree.elementsStoppingAt(0.5):
        ...     el
        <music21.note.Note C#>
        <music21.note.Note A>
        <music21.note.Note A>

        Works also on timespans for TimespanTrees:

        >>> scoreTree = score.asTimespans()
        >>> for el in scoreTree.elementsStoppingAt(0.5):
        ...     el
        <PitchedTimespan (0.0 to 0.5) <music21.note.Note C#>>
        <PitchedTimespan (0.0 to 0.5) <music21.note.Note A>>
        <PitchedTimespan (0.0 to 0.5) <music21.note.Note A>>
        c                z   g }| | j                   cxk  r| j                  k  rn |S | j                  !|j                   | j                               | j                  D ])  }j                  ||       k(  s|j                  |       + | j                  !|j                   | j                               |S r   )
endTimeLowr   r   rk   r&   r   rh   r   r
   rm   r   r   r   r    s      r   r   z.OffsetTree.elementsStoppingAt.<locals>.recurse  s    F??f@0@0@@ M ~~1gdnn&=>"ll..r48FB"MM"- + 2gdoo&>?Mr   r   r   r    r   r   r   s   `` @r   elementsStoppingAtzOffsetTree.elementsStoppingAt  s"    ,	 $--(W~r   c                P      fd  j                         }t        |      S )a=  
        Finds elements in this ElementTree which overlap `offset`.

        >>> score = corpus.parse('bwv66.6')
        >>> scoreTree = score.asTree(flatten=True, groupOffsets=True)
        >>> for el in scoreTree.elementsOverlappingOffset(0.5):
        ...     el
        ...
        <music21.note.Note E>

        Works with Timespans in TimespanTrees as well.

        >>> scoreTree = score.asTimespans()
        >>> for el in scoreTree.elementsOverlappingOffset(0.5):
        ...     el
        ...
        <PitchedTimespan (0.0 to 1.0) <music21.note.Note E>>
        c                   g }| | j                   cxk  r| j                  k  rn n||j                   | j                               | j                  D ])  }j                  ||       k  s|j                  |       + |j                   | j                               |S | j                   k  r!|j                   | j                               |S r   )r   r   rk   r   r&   r   rh   r   r   s      r   r   z5OffsetTree.elementsOverlappingOffset.<locals>.recurse  s    F==6<D,<,<<MM'$.."9: #ll!D$7$7D$AA"MM"- + MM'$//":; M t}},MM'$.."9:Mr   r   r   s   `` @r   elementsOverlappingOffsetz$OffsetTree.elementsOverlappingOffset  s"    &	 $--(W~r   Nc                   | j                         }| j                  }t        |d      r|g}|t        j                  |      s|g}|"t        |      t        |      k7  rt        d      t        |      D ]9  \  }}|| j                  |||          | j                  ||j                         ; |r| j                  ||       yy)a  
        Removes `elements` which can be Music21Objects or Timespans
        (a single one or a list) from this Tree.

        Much safer (for non-timespans) if a list of offsets is used, but it is optional.

        If runUpdate is False then the tree will be left with incorrect indices and
        endTimes; but it can speed up operations where an element is going to be removed
        and then immediately replaced: i.e., where the position of an element has changed.
        r   Nz9Number of elements and number of offsets must be the same)rK   rL   rM   r   r   rO   r   r]   r   r   r|   )r    r!   offsets	runUpdaterz   r{   r6   r   s           r   removeElementszOffsetTree.removeElements  s     --/8X& zHv'8'8'AiG3x=CL#@&KM M x(EAr"--b'!*=--b"))<	 ) o~> r   c                D    fdt         | j                              S )at  
        Gets all unique offsets of all timespans in this offset-tree.

        >>> score = corpus.parse('bwv66.6')
        >>> tsTree = score.asTimespans()
        >>> for offset in tsTree.allOffsets()[:10]:
        ...     offset
        ...
        0.0
        0.5
        1.0
        2.0
        3.0
        4.0
        5.0
        5.5
        6.0
        6.5
        c                V   g }| | j                   !|j                   | j                                | j                  }t        |t              r|j                  |j                         n|j                  |       | j                  !|j                   | j                               |S r   )r   rk   r   r4   r   rh   r   r   )r
   rm   rQ   r   s      r   r   z&OffsetTree.allOffsets.<locals>.recurse'  s    F>>-MM'$.."9:mmc9-MM#**-MM#&??.MM'$//":;Mr   )r   r   r   s    @r   
allOffsetszOffsetTree.allOffsets  s    (	 WT]]+,,r   c                V    fdt        t         | j                                    S )a  
        Gets all unique offsets (both starting and stopping) of all elements/timespans
        in this offset-tree.

        >>> score = corpus.parse('bwv66.6')
        >>> scoreTree = score.asTimespans()
        >>> for offset in scoreTree.allTimePoints()[:10]:
        ...     offset
        ...
        0.0
        0.5
        1.0
        2.0
        3.0
        4.0
        5.0
        5.5
        6.0
        6.5
        c                H   t               }| | j                  !|j                   | j                               |j                  | j                         |j                  | j                                | j                  !|j                   | j                               |S r   )r~   r   r   r   r   payloadEndTimesr   )r
   rm   r   s     r   r   z)OffsetTree.allTimePoints.<locals>.recurseK  sx    UF>>-MM'$.."9:

4==)d2245??.MM'$//":;Mr   )r   sortedr   r   s    @r   allTimePointszOffsetTree.allTimePoints6  s#    *		 VGDMM2344r   c                    |du r| j                         n| j                         }g }|D ]N  }| j                  |      }|s|du r|j                  |       -|j                  || j	                  |      i       P |S )a  
        Gets all time-points where some element is starting
        (or if includeStopPoints is True, where some element is starting or stopping)
        while some other element is still continuing onward.

        >>> score = corpus.parse('bwv66.6')
        >>> scoreOffsetTree = score.asTree(flatten=True, groupOffsets=True)
        >>> scoreOffsetTree.overlapTimePoints()
        [0.5, 5.5, 6.5, 10.5, 13.5, 14.5, 15.5...]

        if returnVerticality is True, then a mapping of time point to elements is returned.
        How cool is that?

        >>> otp = scoreOffsetTree.overlapTimePoints(returnVerticality=True)
        >>> otp[0]
        {0.5: <music21.tree.verticality.Verticality 0.5 {G#3 B3 E4 B4}>}

        F)r  r  r  rh   getVerticalityAt)r    includeStopPointsreturnVerticalitycheckPointsoverlapscpoverlappingElementss          r   overlapTimePointszOffsetTree.overlapTimePointsW  s    & ,=+Edoo'4K]K]K_B"&"@"@"D& E)#T%:%:2%> ?@  r   c                    ddl m} | j                  |      }| j                  |      }| j	                  |      } ||||||       }|S )aI  
        Gets the verticality in this offset-tree which starts at `offset`.

        >>> bach = corpus.parse('bwv66.6')
        >>> scoreTree = bach.asTimespans()
        >>> scoreTree.getVerticalityAt(2.5)
        <music21.tree.verticality.Verticality 2.5 {G#3 B3 E4 B4}>

        Verticalities outside the range still return a Verticality, but it might be empty:

        >>> scoreTree.getVerticalityAt(2000)
        <music21.tree.verticality.Verticality 2000 {}>

        Test that it still works if the tree is empty:

        >>> scoreTree = bach.asTimespans(classList=(instrument.Tuba,))
        >>> scoreTree
        <TimespanTree {0} (-inf to inf) <music21.stream.Score ...>>
        >>> scoreTree.getVerticalityAt(5.0)
        <music21.tree.verticality.Verticality 5.0 {}>

        Returns a verticality.Verticality object.
        r   )Verticality)overlapTimespansstartTimespansr   stopTimespanstimespanTree)music21.tree.verticalityr  r   r   r  )r    r   r  r  r  r  verticalitys          r   r  zOffsetTree.getVerticalityAtv  sY    0 	9008//799&A!-)'
 r   c                    i }| j                         D ]/  }|j                  }t        |      dkD  s|dd ||j                  <   1 |S )a  
        Creates a dictionary of offsets that have more than one element starting at that time,
        where the keys are offset times and the values are lists of elements at that moment.

        >>> score = tree.examples.makeExampleScore()
        >>> scoreTree = score.asTree(flatten=True, groupOffsets=True)
        >>> scoreTree
        <OffsetTree {20} (0.0 to 8.0) <music21.stream.Score exampleScore>>

        >>> sd = scoreTree.simultaneityDict()
        >>> len(sd)
        5
        >>> list(sorted(sd.keys()))
        [0.0, 2.0, 4.0, 6.0, 8.0]
        >>> sd[0.0]
        [<music21.instrument.Instrument 'PartA: : '>,
         <music21.instrument.Instrument 'PartB: : '>,
         <music21.clef.BassClef>,
         <music21.clef.BassClef>,
         <music21.meter.TimeSignature 2/4>,
         <music21.meter.TimeSignature 2/4>,
         <music21.note.Note C>,
         <music21.note.Note C#>]
        >>> sd[2.0]
        [<music21.note.Note E>, <music21.note.Note G#>]
        r   N)rs   r&   rO   r   )r    simultaneityDictr
   r+   s       r   r   zOffsetTree.simultaneityDict  sJ    6 NN$DB2w{24Q% / %  r   )NT)FF)r   r   r   r   r   r   r   
OffsetNoder   r,   r9   rt   staticmethodr   r   rh   r   r   r   r   r   r  r  r  r  r  r  r   r   r   r   r   r   x  s    
 I )(%%I"HBLt6 9 9		@ ! !	>@,$L#J?>!-F5B>%N  r   r   c                      e Zd Zd Zd Zy)Testc                   ddl m} ddl m} t               }|j	                         }t        d      D ]8  }|j                         }d|j                  _        |j                  |dz  |       : |D ]  }|j                  |        | j                  t        |      j                  d             |d   }| j                  |j                  ||j                               d	       |j!                  d
      }| j#                  |       y)zq
        test that get position after works with
        an offset when the tree is built on SortTuples.
        r   notestreamd          @r   z<ElementTree {100} (0.0 <0.20c   g      @N)music21r'  r)  r   Streamr^   Noter   r   r   
assertTrueri   
startswithassertEqualr   r$   getPositionAfterassertIsNotNone)	r    r'  r)  etr(   r6   r8   n2st3s	            r   testGetPositionAfterOffsetzTest.testGetPositionAfterOffset  s    
 	!"]MMOsA		A'*AJJ$HHQUA 
 AIIaL R++,KLMrU"blln5r:!!#&S!r   c                   ddl m} ddl m} ddl m} |j	                         }|j                  d      }d|j                  _        |j                  d|       |j                  d      }d|j                  _        |j                  d	|       |j                  d
      }d|j                  _        |j                  d|       |j                  d      }d|j                  _        |j                  d|       |j                  d      }	|	j                  d      }
| j                  t        |
      d       | j                  |
D cg c]  }|j                   c}g d       t        d      D ]"  }|j                  d|j                                $ t        d      D ]%  }|j                  d|z   |j                                ' |j                  d      }	|	j                  d      }
| j                  t        |
      d       | j                  |
D cg c]  }|j                   c}g d       |j!                  d      }|j                  dd      }|j                  d      }| j                  t        |      d       | j                  |d   j                  d       | j                  |d	   j                  d       | j                  |d   j                  d       yc c}w c c}w )z
        this was reporting:

        <music21.note.Note G#>
        <music21.note.Note C#>
        <music21.note.Note A>
        <music21.note.Note A>

        G# was coming from an incorrect activeSite.  activeSite should not be used!
        r   )corpusr(  r&  Ag      @Br+  r   Cg      ?r   A#g      @g      ?T)groupOffsets   )r<  r?  r=  r>        
   zbwv66.6)flattenr@     zC#N)r.  r;  r)  r'  r/  r0  r   r   r   asTreer   r3  rO   namer^   Restparse)r    r;  r)  r'  r(   n0n1r7  n3ststListr8   r6   score	scoreTreeelementLists                   r   testElementsStoppingAtzTest.testElementsStoppingAt  sN    	#" MMOYYs^$'!	BYYs^$'!	BYYs^$'!	BYYt_$'!	bXX4X(&&s+Va(&1&Q!&&&1.	0 rAHHQ		$ rAHHR!VTYY[) XX4X(&&s+Va(&1&Q!&&&1.	0 Y'LLDLA	2237[)1-Q,,d3Q,,c2Q,,c2) 2 2s    KKN)r   r   r   r9  rS  r   r   r   r$  r$    s    "j43r   r$  __main__)r   
__future__r   mathr   unittestr   r.  r   r   r   music21.sortingr   music21.treer	   r
   r   EnvironmentenvironLocalr   r   TreeExceptionr   AVLTreer   r   TestCaser$  
_DOC_ORDERr   mainTestr   r   r   <module>ra     s   
 #        %  +&{&&|4D 
	<55 	H$,, HXE	  E	 Xk38 k3T 
 zGT r   