
    rh                       S r SSKJr  SSKJr  SSKrSSKrSSKrSSK	J
r
  SSK	Jr  SSK	Jr  SSKJr  SS	KJr  SS
KJr  \R&                  " S5      r\r\* r " S S\R.                  5      r " S S\R2                  5      r " S S\5      r " S S\R8                  5      r\\4r\S:X  a  SSK	r	\	R@                  " \5        gg)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                      \ rS rSrSrg)ElementTreeException(    N)__name__
__module____qualname____firstlineno____static_attributes__r       L/home/james-whalen/.local/lib/python3.13/site-packages/music21/tree/trees.pyr   r   (   s    r   r   c                  6  ^  \ rS rSr% SrS\S'   \R                  rSr	S!U 4S jjr
S rS rS	 rS
 rS rS rS rS rS rS"S jrS#S jrS rS rS rS rU 4S jrS#S jrS rS#S jrS rS rS r \!S 5       r"\"RF                  S 5       r"\!S 5       r$S r%U =r&$ )$ElementTree.   az  
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U ]  5         [        R                  " 5       U l        S U l        U(       a  Ub  U R                  U5        X l        g N)super__init__weakrefWeakSetr   r   insertsource)selfelementsr#   	__class__s      r   r   ElementTree.__init__l   s=    "??,,KK!r   c                    U R                   nUR                  U5      nU R                  U5      nUb  UR                  UL a  gU  H	  nXQL d  M	    g   g)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.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__ElementTree.__contains__v   s_    . KK **1- //?%%%0 B}  r   c                    XL $ )z
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__ElementTree.__eq__   s     |r   c                     U R                  U5      nUc  U$ [        U[        5      (       d  UR                  $ U Vs/ s H  o3R                  PM     sn$ ! [         a     gf = fs  snf )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.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__ElementTree.__getitem__   sn    h	!003N !!!ND11!)))'56~!II~66  		 7s   A A%
A"!A"c                @    [        [        U 5      [        U 5      45      $ r   )hashtypeidr$   s    r   __hash__ElementTree.__hash__   s    T$ZD*++r   c                J    U R                   c  gU R                   R                  $ )a  
Gets the length of the ElementTree, i.e., the number of elements enclosed.
This is a very very fast O(1).

>>> score = tree.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   subtreeElementsStopIndexrF   s    r   __len__ElementTree.__len__   s"    @ == }}555r   c           	     x   U R                   nU R                  5       nU R                  n[        US5      (       a  UR	                  5       n[        US5      (       a  UR	                  5       n[        U 5      R                  nS[        [        U 5      5      -   S-   nSU SU SU SU S3	nUb	  USU< 3-  nUS	-  nU$ )
N	shortRepr{}< z (z to )>)	r#   lowestPositionendTimehasattrrN   rD   r   strlen)r$   oposrV   	classNamelenEnclosedmsgs          r   __repr__ElementTree.__repr__  s    KK!!#,,3$$--/C7K(('')GJ''	CD	N*S0)Ak]"SEgYa@=Qqe9Cs

r   c           	     d   [        U[        5      (       a4  U R                  U5      nUc  S[        U 5       3n[	        U5      eX#l        g[        U[        5      (       a  [        U[        5      (       d  SU SU S3n[	        U5      eUR                  UR                  -
  UR                  -  nU[        U5      :w  a!  U SU SU S[        U5       3n[	        U5      e[        [        UR                  UR                  UR                  5      5       H  u  pgX&   X'   M     gS	U 3n[	        U5      e)
ae  
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.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 )r;   intr9   rY   	TypeErrorr+   slicer<   stopstartstep	enumeraterange)r$   r=   newr?   messagesliceLenj	sliceIters           r   __setitem__ElementTree.__setitem__)  s!   : a##A&Ay4SYK@((I5!!c4((s"4SEI(((AFF2H3s8#C28*E#FWX[\_X`Wab(( )%*H I"%& !J =QC@GG$$r   c                    / nUR                  [        U 5      5        U  HB  n[        U5      R                  5       nU Vs/ s H  nSU-   PM
     nnUR	                  U5        MD     SR                  U5      nU$ s  snf )a3  
Print the whole contents of the tree.

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

>>> score = tree.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reprrX   
splitlinesextendjoin)r$   resultx	subResults       r   __str__ElementTree.__str__Z  ss    > d4j!AA))+I+459a9I5MM)$  6" 6s   A8c              #  V   #    U R                  5        H  nUR                  v   M     g7f)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.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__ElementTree.__iter__  s"     , NN$D,, %s   ')c                    U R                   b4  U R                   R                  5         U R                   R                  5         U R                  5       U:w  d  U R                  U:w  a  U R                  XS9  gg)z
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updateEndTimesrU   rV   _updateParents)r$   initialPositioninitialEndTimer   s       r   _updateNodesElementTree._updateNodes  sa     ==$MM'')MM((*!_4<<>1O 2r   c                    Uc
  [        5       nU R                   H?  nUb  X2;   a  M  UR                  U5        UR                  nUR	                  X5        [
        e   g)zT
Tells all parents that the position of this tree has
changed.

Not currently used.
N)setr   addoffset_removeElementAtPositionNotImplementedError)r$   oldPositionr   parentparentPositions        r   r   ElementTree._updateParents  sY     ! UN&&F~!9v&#]]N++D>%% 'r   c                r   U R                  U5      nUc  g[        UR                  [        5      (       aN  XR                  ;   a  UR                  R	                  U5        UR                  (       d  U R                  U5        ggUR                  UL a  SUl        UR                  c  U R                  U5        gg)z
removes an element or ElementTree from a position
(either its current .offset or its oldPosition) without updating
the indices, endTimes, etc.
N)r*   r;   r+   r<   remove
removeNode)r$   r,   positionr
   s       r   r   $ElementTree._removeElementAtPosition  s     %%h/<dllD)),,&##G,<<)   ||w&#||#) $r   c                8    UR                  U R                  5      $ z
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   getPositionFromElementUnsafe(ElementTree.getPositionFromElementUnsafe  s     ||DKK((r   c                N   ^^ SUU4S jjmU R                   mT" US5      U l        g)a4  
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                   > [        U 5      nUS:X  a  gUS-  nX   nT" US   US   5      nX-   Ul        Xl        X-   Ul        T" U SU U5      Ul        T" XS-   S X-   S-   5      Ul        UR                  5         U$ )z
Divide and conquer.
r   N      )rY   payloadElementIndexsubtreeElementsStartIndexrJ   	leftChild
rightChildupdate)subListOfTuplesglobalStartOffsetlenLmidpointmidtupler?   	NodeClassrecurses         r   r   3ElementTree.populateFromSortedList.<locals>.recurse,  s     'DqyqyH&0H(1+x{3A$5$@A!*;'):)AA&!/)8"<"35AK"?a<=#A#4#?!#CEALHHJHr   r   N)returnzcore.AVLNode | None)	nodeClassr   )r$   listOfTuplesr   r   s     @@r   populateFromSortedList"ElementTree.populateFromSortedList  s'    L	 	( NN	a0r   c                  ^^ U4S jmU4S jm[        U[        5      (       ak  U R                  c  [        eUS:  a  U R                  R                  U-   nUS:  d  U R                  R                  U::  a  [        eT" U R                  U5      $ [        U[
        5      (       aP  U R                  c  / $ UR                  U R                  R                  5      nUS   US   pCT" U R                  X45      $ [        SU 35      e)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.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                   > U R                   U:X  a  U $ U R                  (       a"  XR                   :  a  T" U R                  U5      $ U R                  (       a$  U R                   U::  a  T" U R                  U5      $ gg)z*
Return the node element at a given index
N)r   r   r   r
   indexrecurseByIndexs     r   r   2ElementTree.getNodeByIndex.<locals>.recurseByIndexd  sh     ''50E,D,D$D%dnne<<T%=%=%F%doou== &Gr   c                t  > / nU c  U$ XR                   :  a3  U R                  (       a"  UR                  T" U R                  X5      5        XR                   s=::  a  U:  a  O  OUR                  U 5        U R                   U:  a3  U R                  (       a"  UR                  T" U R                  X5      5        U$ )zW
Return a slice of the nodes (plural) whose indices are between start <= index < stop.
)r   r   rw   rt   r   )r
   rf   re   ry   recurseBySlices       r   r   2ElementTree.getNodeByIndex.<locals>.recurseBySliceo  s     F|///DNNnT^^UIJ00747d#''$.4??nT__eJKMr   r   r   (Indices must be integers or slices, got r;   rb   r   r:   rJ   rd   indicesrc   r$   r=   r   outer_start
outer_stopr   r   s        @@r   r9   ElementTree.getNodeByIndexC  s    B		>	 a}}$  1uMM::Q>1u>>!C  !$--335!!}}$	ii F FGG&-aj'!*!$--IIFqcJKKr   c              #  @   >#    [         TU ]  5        H  nUv   M	     g7f)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.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   r   )r$   r?   r&   s     r   r   ElementTree.iterNodes  s      J !#AG $s   c                    Uc  U R                  U5      nU R                  U5      nUb  UR                  ULa-  [        U 5       H  u  pEXQL d  M  Us  $    [	        U SU S35      eUR
                  $ )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.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+   rh   
ValueErrorr   )r$   r,   r   r
   r=   r?   s         r   r   ElementTree.index  s{    < 88AH%%h/<4<<w6!$<H ( y(A(1MNN'''r   c                N    U Vs/ s H  o R                  U5      PM     sn$ s  snf )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   _getPositionsFromElements%ElementTree._getPositionsFromElements  s'     AII"11"5IIIs   "c                   U R                  5       nU R                  nUc  UnSnO1Un[        R                  " U5      (       a  [	        US5      (       a  U/n[        R                  " U5      (       d  [        U[        [        45      (       d  U/nUc  U R                  U5      n[        U5       H  u  pgXV   nU R                  X5        M     U R                  X45        g)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)>
NrN   )rU   rV   r   
isListLikerW   r;   r   	frozensetr   rh   _insertCorer   )	r$   positionsOrElementsr%   r   r   	positionsr=   r   r[   s	            r   r"   ElementTree.insert  s    ( --/*HI+I$$Y//79k3R3R&K	!!(++"8c9-=>> zH66x@Ix(EA,CS% ) 	/:r   c                T    U R                  U5        U R                  U5      nX#l        g)
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   ElementTree._insertCore  s'    
 	!!(+%%h/r   c                Z   ^ U4S jmU R                   b  T" U R                   5      $ [        $ )z
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                Z   > U R                   b  T" U R                   5      $ U R                  $ r   )r   r   r
   r   s    r   r   ,ElementTree.highestPosition.<locals>.recurse+  s&    *t//}}$r   r   NEGATIVE_INFINITYr$   r   s    @r   highestPositionElementTree.highestPosition   s)    	% ==$4==))$$r   c                Z   ^ U4S jmU R                   b  T" U R                   5      $ [        $ )z
Gets the earliest position in this tree.

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

>>> tsTree = score.asTimespans()
>>> tsTree.lowestPosition()
0.0
c                Z   > U R                   b  T" U R                   5      $ U R                  $ r   )r   r   r   s    r   r   +ElementTree.lowestPosition.<locals>.recurseC  s&    ~~)t~~..== r   r   r   s    @r   rU   ElementTree.lowestPosition6  s)    	!
 ==$4==))$$r   c                B    [         R                  " U R                  5      $ )z
the original stream. (stored as a weakref but returned unwrapped)

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

>>> s = stream.Stream()
>>> eTree.source = s
>>> eTree.source is s
True
)r   unwrapWeakrefr   rF   s    r   r#   ElementTree.sourceN  s     ##DLL11r   c                :    [         R                  " U5      U l        g r   )r   wrapWeakrefr   r4   s     r   r#   r   _  s     ))$/r   c                T    U R                   b  U R                   R                  $ [        $ )aA  
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INFINITYrF   s    r   rV   ElementTree.endTimed  s#    $ ==$==,,,r   )r   r   r   r#   )NN)NNNr   )'r   r   r   r   __doc____annotations__
nodeModuleElementNoder   	__slots__r   r1   r6   r@   rG   rK   r_   ro   r|   r   r   r   r   r   r   r9   r   r   r   r"   r   r   rU   propertyr#   setterrV   r   __classcell__)r&   s   @r   r   r   .   s    1f *) &&II
%N">7@,"6H(/%b&P6P"&,*.	)[1zJLX&P'(R	J*;X%,%0 2 2  ]]0 0  r   r   c                      \ rS rSr% SrSrS\S'   \R                  r	S r
S rS r\S	 5       rS
 rS r\S 5       rS rS rS rS rS rSS jrS rS rSS jrS rS rSrg)
OffsetTreei|  z
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                ~     UR                   nU R                  U5      nX;   a  gg! [         a    [        S5      ef = f)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.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 offsetTF)r   AttributeErrorr   elementsStartingAt)r$   r,   r   
candidatess       r   r1   OffsetTree.__contains__  sN    0	b^^F ,,V4
   	b&'`aa	bs   & <c                  ^^ U4S jmSU4S jjm[        U[        5      (       ak  U R                  c  [        eUS:  a  U R                  R                  U-   nUS:  d  U R                  R                  U::  a  [        eT" U R                  U5      $ [        U[
        5      (       aP  U R                  c  / $ UR                  U R                  R                  5      nUS   US   pCT" U R                  X45      $ [        SU 35      e)a  
Gets elements by integer index or slice.

>>> score = tree.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                T  > U R                   Us=::  a  U R                  :  a  O  OU R                  XR                   -
     $ U R                  (       a"  XR                   :  a  T" U R                  U5      $ U R                  (       a$  U R                  U::  a  T" U R                  U5      $ gg)z-
Return the payload element at a given index
N)payloadElementsStartIndexpayloadElementsStopIndexr+   r   r   r   s     r   r   .OffsetTree.__getitem__.<locals>.recurseByIndex  s     --V9V9VV||E,J,J$JKKE,J,J$J%dnne<<T%B%Be%K%doou== &Lr   c                  > / nU c  U$ XR                   :  a3  U R                  (       a"  UR                  T" U R                  X5      5        XR                  :  aU  U R                   U:  aE  XR                   -
  n[	        US5      nX R                   -
  nUR                  U R
                  XE 5        U R                  U::  a3  U R                  (       a"  UR                  T" U R                  X5      5        U$ )zN
Return a slice of the payload elements (plural) where start <= index < stop.
r   )r  r   rw   r  maxr+   r   )r
   rf   re   ry   
indexStart	indexStopr   s         r   r   .OffsetTree.__getitem__.<locals>.recurseBySlice  s     F|555$..nT^^UIJ4449W9WZ^9^"%C%CC
 Q/
 #A#AA	dll:@A,,4nT__eJKMr   r   r   r   )r
   znodeModule.OffsetNoder   r   s        @@r   r@   OffsetTree.__getitem__  s    ,		>	$ a}}$  1uMM::Q>1u>>!C  !$--335!!}}$	ii F FGG&-aj'!*!$--IIFqcJKKr   c              #  h   #    U R                  5        H  nUR                   H  nUv   M	     M     g7f)a  
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.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#>
...

Nr   )r$   r
   r   s      r   r   OffsetTree.__iter__&  s+     , NN$Dll # %s   02c                H    UR                   U R                  R                  -   $ )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   elementEndTimeOffsetTree.elementEndTimeA  s     }}r{{8888r   c                    UR                   $ r   )r   r   s     r   r   'OffsetTree.getPositionFromElementUnsafeK  s     yyr   c                    U R                  5       nU R                  nU[        :X  a  SnU R                  X15        U R	                  USS9  g)z:
Add an element to the end, making certain speed savings.
r   N)r   )rU   rV   r   r   r   )r$   r   r   rV   s       r   rt   OffsetTree.appendV  sI     --/,,hG%/$?r   c                (    U R                  5       S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)   )rz   s    r   _insertCorePayloadSortKey$OffsetTree._insertCorePayloadSortKeya  s     {{}QR  r   c                    U R                  U5        U R                  U5      nUR                  R                  U5        UR                  R	                  U R
                  S9  g)r   )keyN)r   r*   r+   rt   sortr  r   s       r   r   OffsetTree._insertCorej  sO    
 	!!(+%%h/Bd<<=r   c                    [        U 5      " 5       nUR                  [        U 5      5        U R                  Ul        U R                  R                  5       Ul        U$ )am  
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.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
)rD   r"   r<   r#   r   copy)r$   newTrees     r   r  OffsetTree.copyu  sF    2 t*,tDz""..335r   c                
   / nU R                  U5      nUbc  [        UR                  [        5      (       a  UR	                  UR                  5        O(UR                  b  UR                  UR                  5        [        U5      $ )az  
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*   r;   r+   r<   rw   rt   tuple)r$   r   resultsr
   s       r   r   OffsetTree.elementsStartingAt  sd     %%h/$,,--t||,)t||,W~r   c                R   ^ ^^ UUU 4S jmT" T R                   5      n[        U5      $ )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                  > / nU b  U R                   Ts=::  a  U R                  ::  a  O  U$ U R                  b!  UR                  T" U R                  5      5        U R                   H+  nTR                  X 5      T:X  d  M  UR                  U5        M-     U R                  b!  UR                  T" U R                  5      5        U$ r   )
endTimeLowr   r   rw   r+   r  rt   r   r
   ry   r   r   r   r$   s      r   r   .OffsetTree.elementsStoppingAt.<locals>.recurse  s    F??f@0@0@@ M ~~1gdnn&=>"ll..r8FB"MM"- + 2gdoo&>?Mr   r   r#  r$   r   r$  r   s   `` @r   elementsStoppingAtOffsetTree.elementsStoppingAt  s"    ,	 $--(W~r   c                R   ^ ^^ UUU 4S jmT" T R                   5      n[        U5      $ )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                  > / nU b  U R                   Ts=:  a  U R                  :  a  O  OUR                  T" U R                  5      5        U R                   H+  nTTR                  X 5      :  d  M  UR                  U5        M-     UR                  T" U R                  5      5        U$ TU R                   ::  a!  UR                  T" U R                  5      5        U$ r   )r   r   rw   r   r+   r  rt   r   r)  s      r   r   5OffsetTree.elementsOverlappingOffset.<locals>.recurse  s    F==6<D,<,<<MM'$.."9: #ll!D$7$7$AA"MM"- + MM'$//":; M t}},MM'$.."9:Mr   r+  r,  s   `` @r   elementsOverlappingOffset$OffsetTree.elementsOverlappingOffset  s"    &	 $--(W~r   Nc                   U R                  5       nU R                  n[        US5      (       a  U/nUb  [        R                  " U5      (       d  U/nUb#  [        U5      [        U5      :w  a  [        S5      e[        U5       H9  u  pgUb  U R                  XrU   5        M  U R                  XwR                  5        M;     U(       a  U R                  XE5        gg)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)rU   rV   rW   r   r   rY   r   rh   r   r   r   )r$   r%   offsets	runUpdater   r   r=   r   s           r   removeElementsOffsetTree.removeElements  s     --/8X&& zHv'8'8'A'AiG3x=CL#@&KM M x(EA"--b!*=--b))<	 ) o> r   c                F   ^ U4S jm[        T" U R                  5      5      $ )z
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                f  > / nU b  U R                   b!  UR                  T" U R                   5      5        U R                  n[        U[        5      (       a  UR                  UR                  5        OUR                  U5        U R                  b!  UR                  T" U R                  5      5        U$ r   )r   rw   r   r;   r   rt   r   r   )r
   ry   r[   r   s      r   r   &OffsetTree.allOffsets.<locals>.recurse)  s    F>>-MM'$.."9:mmc9--MM#**-MM#&??.MM'$//":;Mr   )r#  r   r   s    @r   
allOffsetsOffsetTree.allOffsets  s    (	 WT]]+,,r   c                X   ^ U4S jm[        [        T" U R                  5      5      5      $ )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                N  > [        5       nU b  U R                  b!  UR                  T" U R                  5      5        UR                  U R                  5        UR                  U R                  5       5        U R                  b!  UR                  T" U R                  5      5        U$ r   )r   r   r   r   r   payloadEndTimesr   )r
   ry   r   s     r   r   )OffsetTree.allTimePoints.<locals>.recurseM  sx    UF>>-MM'$.."9:

4==)d2245??.MM'$//":;Mr   )r#  sortedr   r   s    @r   allTimePointsOffsetTree.allTimePoints8  s#    *		 VGDMM2344r   c                   USL a  U R                  5       OU R                  5       n/ nU HV  nU R                  U5      nU(       d  M  USL a  UR                  U5        M5  UR                  XPR	                  U5      05        MX     U$ )am  
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<  rC  r2  rt   getVerticalityAt)r$   includeStopPointsreturnVerticalitycheckPointsoverlapscpoverlappingElementss          r   overlapTimePointsOffsetTree.overlapTimePointsY  s}    & ,=+Edoo'4K]K]K_B"&"@"@"D& E)#%:%:2%> ?@  r   c                    SSK Jn  U R                  U5      nU R                  U5      nU R	                  U5      nU" UUUUU S9nU$ )a  
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.verticalityrP  r   r-  r2  )r$   r   rP  rR  rS  rQ  verticalitys          r   rF  OffsetTree.getVerticalityAtx  sY    0 	9008//799&A!-)'
 r   c                    0 nU R                  5        H1  nUR                  n[        U5      S:  d  M   USS XR                  '   M3     U$ )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.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)r   r+   rY   r   )r$   simultaneityDictr
   r0   s       r   rY  OffsetTree.simultaneityDict  sH    6 NN$DB2w{24Q% / %  r   )NT)FF)r   r   r   r   r   r   r   r   
OffsetNoder   r1   r@   r   staticmethodr  r   rt   r  r   r  r   r-  r2  r7  r<  rC  rM  rF  rY  r   r   r   r   r   r   |  s    
 I )(%%I DBLt6 9 9		@ ! !	>@,$L#J?>!-F5B>%N  r   r   c                       \ rS rSrS rS rSrg)Testi  c                   SSK Jn  SSK Jn  [        5       nUR	                  5       n[        S5       H9  nUR                  5       nSUR                  l        UR                  US-  U5        M;     U H  nUR                  U5        M     U R                  [        U5      R                  S5      5        US   nU R                  UR                  XwR                  5       5      S	5        UR!                  S
5      nU R#                  U5        g)zY
test that get position after works with
an offset when the tree is built on SortTuples.
r   streamnoted          @r   z<ElementTree {100} (0.0 <0.20c   g      @N)music21ra  rc  r   Streamri   Noter  r  r"   
assertTrueru   
startswithassertEqualr   r)   getPositionAfterassertIsNotNone)	r$   ra  rc  etr-   r=   r?   n2st3s	            r   testGetPositionAfterOffsetTest.testGetPositionAfterOffset  s    
 	# ]MMOsA		A'*AJJ$HHQUA 
 AIIaL R++,KLMrU"lln5r:!!#&S!r   c                   SSK Jn  SSK Jn  SSK Jn  UR	                  5       nUR                  S5      nSUR                  l        UR                  SU5        UR                  S5      nSUR                  l        UR                  S	U5        UR                  S
5      nSUR                  l        UR                  SU5        UR                  S5      nSUR                  l        UR                  SU5        UR                  SS9n	U	R                  S5      n
U R                  [        U
5      S5        U R                  U
 Vs/ s H  oR                  PM     sn/ SQ5        [        S5       H#  nUR                  SUR                  5       5        M%     [        S5       H&  nUR                  SU-   UR                  5       5        M(     UR                  SS9n	U	R                  S5      n
U R                  [        U
5      S5        U R                  U
 Vs/ s H  oR                  PM     sn/ SQ5        UR!                  S5      nUR                  SSS9nUR                  S5      nU R                  [        U5      S5        U R                  US   R                  S5        U R                  US	   R                  S5        U R                  US   R                  S5        gs  snf s  snf )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`  rb  Ag      @Bre  r   Cg      ?r   A#g      @g      ?T)groupOffsets   )rw  rz  rx  ry        
   zbwv66.6)flattenr{     zC#N)rh  rv  ra  rc  ri  rj  r  r  r"   asTreer-  rm  rY   nameri   Restparse)r$   rv  ra  rc  r-   n0n1rq  n3ststListr?   r=   score	scoreTreeelementLists                   r   testElementsStoppingAtTest.testElementsStoppingAt  sJ    	#" 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r   N)r   r   r   r   rs  r  r   r   r   r   r^  r^    s    "j43r   r^  __main__)!r   
__future__r   mathr   typingtunittestr    rh  r   r   r   music21.sortingr   music21.treer	   r
   r   EnvironmentenvironLocalr   r   TreeExceptionr   AVLTreer   r   TestCaser^  
_DOC_ORDERr   mainTestr   r   r   <module>r     s   
 #         %  +&&|4D 
	<55 	J$,, J\C	  C	 Tk38 k3T 
 zT r   