
    rh                       S r SSKJr  SSKJrJr  SSKrSSK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  \	R&                  (       a  SS
KJr  \R,                  " S5      r " S S\R0                  5      r " S S\R4                  5      r " S S\
R8                  5      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)	GeneratorIterableN)common)environment)exceptions21)spans)treesVerticalitySequenceztree.timespanTreec                      \ rS rSrSrg)TimespanTreeException+    N)__name__
__module____qualname____firstlineno____static_attributes__r       S/home/james-whalen/.local/lib/python3.13/site-packages/music21/tree/timespanTree.pyr   r   +   s    r   r   c                  8   \ rS rSrSrSr\S 5       r\S 5       rS r	\
S 5       rSS	 jrSS
 jr S   SS jjr S   SS jjrS rS r S   SS jjr S SSS.       S!S jjjrS rS r\S 5       rS rS r\
S 5       r\R4                  S 5       rSrg)"TimespanTree0   a  
A TimespanTree is a data structure for efficiently slicing a score for pitches, or,
like all :class:`~music21.tree.trees.OffsetTree` objects, for searching large scores
quickly by time.

While you can construct an TimespanTree by hand, inserting timespans one at
a time, the common use-case is to construct the TimespanTree from an entire
score at once:

>>> bach = corpus.parse('bwv66.6')
>>> scoreTree = tree.fromStream.asTimespans(bach, flatten=True,
...                                         classList=(note.Note, chord.Chord))

From this representation, we can get what is happening at any given moment as a
:class:`~music21.tree.verticality.Verticality` object.

>>> print(scoreTree.getVerticalityAt(17.0))
<music21.tree.verticality.Verticality 17.0 {F#3 C#4 A4}>

The equivalent call from the stream itself is:

    `bach.asTrees(flatten=True, asTimespans=True, classList=(note.Note, chord.Chord))`

All offsets are assumed to be relative to the score's source if flatten is True

Example: How many moments in Bach are consonant and how many are dissonant:

>>> totalConsonances = 0
>>> totalDissonances = 0
>>> for v in scoreTree.iterateVerticalities():
...     if v.toChord().isConsonant():
...        totalConsonances += 1
...     else:
...        totalDissonances += 1
>>> (totalConsonances, totalDissonances)
(34, 17)

So 1/3 of the vertical moments in Bach are dissonant!  But is this an
accurate perception? Let's sum up the total consonant duration vs.
dissonant duration.

Since verticality objects do not know their end times, we can iterate pairwise
to figure out the length.  We add "padEnd=True" to include a dummy verticality
at the end so that it includes the last object:

>>> totalConsonanceDuration = 0
>>> totalDissonanceDuration = 0
>>> iterator = scoreTree.iterateVerticalitiesNwise(n=2, padEnd=True)
>>> for verticality1, verticality2 in iterator:
...     offset1 = verticality1.offset
...     offset2 = verticality2.offset
...     quarterLength = offset2 - offset1
...     if verticality1.toChord().isConsonant():
...        totalConsonanceDuration += quarterLength
...     else:
...        totalDissonanceDuration += quarterLength
>>> (totalConsonanceDuration, totalDissonanceDuration)
(26.5, 9.5)

Example: Remove neighbor tones from the Bach chorale.  (It's actually quite viscous
in its pruning.)

Here in Alto, measure 7, there's a neighbor tone E#.

>>> bach.parts['#Alto'].measure(7).show('text')
{0.0} <music21.note.Note F#>
{0.5} <music21.note.Note E#>
{1.0} <music21.note.Note F#>
{1.5} <music21.note.Note F#>
{2.0} <music21.note.Note C#>

We'll get rid of it and a lot of other neighbor tones.

>>> for verticalities in scoreTree.iterateVerticalitiesNwise(n=3):
...     horizontalities = scoreTree.unwrapVerticalities(verticalities)
...     for unused_part, horizontality in horizontalities.items():
...         if horizontality.hasNeighborTone:
...             merged = horizontality[0].new(
...                endTime=horizontality[2].endTime,
...             )  # merged is a new PitchedTimespan
...             scoreTree.removeTimespan(horizontality[0])
...             scoreTree.removeTimespan(horizontality[1])
...             scoreTree.removeTimespan(horizontality[2])
...             scoreTree.insert(merged)


>>> #_DOCS_SHOW newBach = tree.toStream.partwise(scoreTree, templateStream=bach)
>>> #_DOCS_SHOW newBach.parts['#Alto'].measure(7).show('text')
{0.0} <music21.chord.Chord F#4>
{1.5} <music21.chord.Chord F#3>
{2.0} <music21.chord.Chord C#4>

The second F# is an octave lower, so it wouldn't get merged even if
adjacent notes were fused together (which they're not).

..  note::

    TimespanTree is an implementation of an extended AVL tree. AVL
    trees are a type of binary tree, like Red-Black trees. AVL trees are
    very efficient at insertion when the objects being inserted are already
    sorted - which is usually the case with data extracted from a score.
    TimespanTree is an extended AVL tree because each node in the
    tree keeps track of not just the start offsets of PitchedTimespans
    stored at that node, but also the earliest and latest stop offset of
    all PitchedTimespans stores at both that node and all nodes which are
    children of that node. This lets us quickly located PitchedTimespans
    which overlap offsets or which are contained within ranges of offsets.
    This also means that the contents of a TimespanTree are always
    sorted.

OMIT_FROM_DOCS


TODO: Doc examples for all functions, including privates.
r   c                    U R                   $ NendTimexs    r   _insertCorePayloadSortKey&TimespanTree._insertCorePayloadSortKey   s    yyr   c                    U 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   )elunused_nodes     r   elementEndTimeTimespanTree.elementEndTime   s     zzr   c                    UR                   nU R                  U5      nUb  XR                  ;  a  [        U SU S35      eUR                  R	                  U5      UR
                  -   nU$ )a#  
Gets index of a TimeSpan in a TimespanTree.

Since Timespans do not have .sites, there is only one offset to deal with

>>> tsList = [(0, 2), (0, 9), (1, 1), (2, 3), (3, 4),
...           (4, 9), (5, 6), (5, 8), (6, 8), (7, 7)]
>>> ts = [tree.spans.Timespan(x, y) for x, y in tsList]
>>> tsTree = tree.timespanTree.TimespanTree()
>>> tsTree.insert(ts)

>>> for timespan in ts:
...     print("%r %s" % (timespan, tsTree.index(timespan)))
...
<Timespan 0.0 2.0> 0
<Timespan 0.0 9.0> 1
<Timespan 1.0 1.0> 2
<Timespan 2.0 3.0> 3
<Timespan 3.0 4.0> 4
<Timespan 4.0 9.0> 5
<Timespan 5.0 6.0> 6
<Timespan 5.0 8.0> 7
<Timespan 6.0 8.0> 8
<Timespan 7.0 7.0> 9

>>> tsTree.index(tree.spans.Timespan(-100, 100))
Traceback (most recent call last):
ValueError: <Timespan -100.0 100.0> not in Tree at offset -100.0.
z not in Tree at offset .)offsetgetNodeByPositionpayload
ValueErrorindexpayloadElementsStartIndex)selfspanr*   noder.   s        r   r.   TimespanTree.index   sh    < %%f-<4||3v%<VHAFGG""4(4+I+IIr   c                "    U R                  5       $ )z
this is just for mimicking elements as streams.

* Changed in v7: this was always meant to be a property, but was
  incorrectly a method earlier.
)lowestPositionr0   s    r   r*   TimespanTree.offset   s     ""$$r   Nc                (    U R                  XU5        g)z.
this will eventually be different from above
NremoveElementsr0   elementsoffsets	runUpdates       r   removeTimespanListTimespanTree.removeTimespanList        	Hy9r   c                (    U R                  XU5        g)z/
this will eventually be different from above.
Nr9   r;   s       r   removeTimespanTimespanTree.removeTimespan   rA   r   c                n   SSK Jn  Uc  UR                  4n[        U[        R
                  5      (       d  SU< S3n[        U5      eU R                  UR                  5      nUbP  UR                  nUc  gUR                   H*  nUR                  U5      UR                  U5      L d  M(  Us  $    Ub  MO  gg)a  
Finds next element timespan in the same stream class as `PitchedTimespan`.

Default classList is (stream.Part,)

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans(classList=(note.Note,))
>>> timespan = scoreTree[0]
>>> timespan
<PitchedTimespan (0.0 to 0.5) <music21.note.Note C#>>

>>> timespan.part
<music21.stream.Part Soprano>

>>> timespan = scoreTree.findNextPitchedTimespanInSameStreamByClass(timespan)
>>> timespan
<PitchedTimespan (0.5 to 1.0) <music21.note.Note B>>

>>> timespan.part
<music21.stream.Part Soprano>

>>> timespan = scoreTree.findNextPitchedTimespanInSameStreamByClass(timespan)
>>> timespan
<PitchedTimespan (1.0 to 2.0) <music21.note.Note A>>

>>> timespan.part
<music21.stream.Part Soprano>
r   streamNPitchedTimespan , must be an PitchedTimespan)music21rG   Part
isinstancer	   PitchedTimespanr   getVerticalityAtr*   nextVerticalitystartTimespansgetParentageByClass)r0   pitchedTimespan	classListrG   messageverticalitynextPitchedTimespans          r   *findNextPitchedTimespanInSameStreamByClass7TimespanTree.findNextPitchedTimespanInSameStreamByClass   s    B 	#I/5+@+@AA((;;WXG'00++O,B,BC%%55K"'2'A'A#';;IF';;IFG.. (B	 %r   c                n   SSK Jn  Uc  UR                  4n[        U[        R
                  5      (       d  SU< S3n[        U5      eU R                  UR                  5      nUbP  UR                  nUc  gUR                   H*  nUR                  U5      UR                  U5      L d  M(  Us  $    Ub  MO  gg)a  
Finds next element timespan in the same Part/Measure, etc. (specify in classList) as
the `pitchedTimespan`.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans(classList=(note.Note,))
>>> timespan = scoreTree[-1]
>>> timespan
<PitchedTimespan (35.0 to 36.0) <music21.note.Note F#>>

>>> timespan.part
<music21.stream.Part Bass>

>>> timespan = scoreTree.findPreviousPitchedTimespanInSameStreamByClass(timespan)
>>> timespan
<PitchedTimespan (34.0 to 35.0) <music21.note.Note B>>

>>> timespan.part
<music21.stream.Part Bass>

>>> timespan = scoreTree.findPreviousPitchedTimespanInSameStreamByClass(timespan)
>>> timespan
<PitchedTimespan (33.0 to 34.0) <music21.note.Note D>>

>>> timespan.part
<music21.stream.Part Bass>
r   rF   NrH   rI   )rJ   rG   rK   rL   r	   rM   r   rN   r*   previousVerticalityrP   rQ   )r0   rR   rS   rG   rT   rU   previousPitchedTimespans          r   .findPreviousPitchedTimespanInSameStreamByClass;TimespanTree.findPreviousPitchedTimespanInSameStreamByClass'  s    @ 	#I/5+@+@AA((;;WXG'00++O,B,BC%%99K"+6+E+E'+??	J';;IFG22 ,F	 %r   c                b    U R                  U5      nUR                  (       d  UR                  nU$ )a  
Gets the :class:`~music21.tree.verticality.Verticality`
in this TimeSpanTree which starts at `offset`.

If the found Verticality has no start timespans, the function returns
the next previous verticality with start timespans.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans()
>>> scoreTree.getVerticalityAtOrBefore(0.125)
<music21.tree.verticality.Verticality 0.0 {A3 E4 C#5}>

>>> scoreTree.getVerticalityAtOrBefore(0.0)
<music21.tree.verticality.Verticality 0.0 {A3 E4 C#5}>
)rN   rP   rZ   )r0   r*   rU   s      r   getVerticalityAtOrBefore%TimespanTree.getVerticalityAtOrBeforeW  s.      ++F3))%99Kr   c              #    #    U R                  5       n [        U5      nUR                  5       R	                  5       (       d1   [        U5      nUR                  5       R	                  5       (       d  M1  U/nU HX  nUR                  U5        UR                  5       R	                  5       (       d  M9  [        U5      S:  a  [        U5      v   U/nMZ     g! [         a     gf = f! [         a     gf = f7f)aU  
Iterates consonant-bounded verticality subsequences in this
offset-tree.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans()
>>> for subsequence in scoreTree.iterateConsonanceBoundedVerticalities():
...     print('Subsequence:')
...     for verticality in subsequence:
...         verticalityChord = verticality.toChord()
...         print(f'\t[{verticality.measureNumber}] '
...               + f'{verticality}: {verticalityChord.isConsonant()}')
...
Subsequence:
    [2] <music21.tree.verticality.Verticality 6.0 {E3 E4 G#4 B4}>: True
    [2] <music21.tree.verticality.Verticality 6.5 {E3 D4 G#4 B4}>: False
    [2] <music21.tree.verticality.Verticality 7.0 {A2 C#4 E4 A4}>: True
Subsequence:
    [3] <music21.tree.verticality.Verticality 9.0 {F#3 C#4 F#4 A4}>: True
    [3] <music21.tree.verticality.Verticality 9.5 {B2 D4 G#4 B4}>: False
    [3] <music21.tree.verticality.Verticality 10.0 {C#3 C#4 E#4 G#4}>: True
Subsequence:
    [3] <music21.tree.verticality.Verticality 10.0 {C#3 C#4 E#4 G#4}>: True
    [3] <music21.tree.verticality.Verticality 10.5 {C#3 B3 E#4 G#4}>: False
    [3] <music21.tree.verticality.Verticality 11.0 {F#2 A3 C#4 F#4}>: True
Subsequence:
    [3] <music21.tree.verticality.Verticality 12.0 {F#3 C#4 F#4 A4}>: True
    [4] <music21.tree.verticality.Verticality 13.0 {G#3 B3 F#4 B4}>: False
    [4] <music21.tree.verticality.Verticality 13.5 {F#3 B3 F#4 B4}>: False
    [4] <music21.tree.verticality.Verticality 14.0 {G#3 B3 E4 B4}>: True
Subsequence:
    [4] <music21.tree.verticality.Verticality 14.0 {G#3 B3 E4 B4}>: True
    [4] <music21.tree.verticality.Verticality 14.5 {A3 B3 E4 B4}>: False
    [4] <music21.tree.verticality.Verticality 15.0 {B3 D#4 F#4}>: True
Subsequence:
    [4] <music21.tree.verticality.Verticality 15.0 {B3 D#4 F#4}>: True
    [4] <music21.tree.verticality.Verticality 15.5 {B2 A3 D#4 F#4}>: False
    [4] <music21.tree.verticality.Verticality 16.0 {C#3 G#3 C#4 E4}>: True
Subsequence:
    [5] <music21.tree.verticality.Verticality 17.5 {F#3 D4 F#4 A4}>: True
    [5] <music21.tree.verticality.Verticality 18.0 {G#3 C#4 E4 B4}>: False
    [5] <music21.tree.verticality.Verticality 18.5 {G#3 B3 E4 B4}>: True
Subsequence:
    [6] <music21.tree.verticality.Verticality 24.0 {F#3 C#4 F#4 A4}>: True
    [7] <music21.tree.verticality.Verticality 25.0 {B2 D4 F#4 G#4}>: False
    [7] <music21.tree.verticality.Verticality 25.5 {C#3 C#4 E#4 G#4}>: True
Subsequence:
    [7] <music21.tree.verticality.Verticality 25.5 {C#3 C#4 E#4 G#4}>: True
    [7] <music21.tree.verticality.Verticality 26.0 {D3 C#4 F#4}>: False
    [7] <music21.tree.verticality.Verticality 26.5 {D3 F#3 B3 F#4}>: True
Subsequence:
    [8] <music21.tree.verticality.Verticality 29.0 {A#2 F#3 C#4 F#4}>: True
    [8] <music21.tree.verticality.Verticality 29.5 {A#2 F#3 D4 F#4}>: False
    [8] <music21.tree.verticality.Verticality 30.0 {A#2 C#4 E4 F#4}>: False
    [8] <music21.tree.verticality.Verticality 31.0 {B2 C#4 E4 F#4}>: False
    [8] <music21.tree.verticality.Verticality 32.0 {C#3 B3 D4 F#4}>: False
    [8] <music21.tree.verticality.Verticality 32.5 {C#3 A#3 C#4 F#4}>: False
    [9] <music21.tree.verticality.Verticality 33.0 {D3 B3 F#4}>: True
Subsequence:
    [9] <music21.tree.verticality.Verticality 33.0 {D3 B3 F#4}>: True
    [9] <music21.tree.verticality.Verticality 33.5 {D3 B3 C#4 F#4}>: False
    [9] <music21.tree.verticality.Verticality 34.0 {B2 B3 D4 F#4}>: True
Subsequence:
    [9] <music21.tree.verticality.Verticality 34.0 {B2 B3 D4 F#4}>: True
    [9] <music21.tree.verticality.Verticality 34.5 {B2 B3 D4 E#4}>: False
    [9] <music21.tree.verticality.Verticality 35.0 {F#3 A#3 C#4 F#4}>: True
N   )iterateVerticalitiesnextStopIterationtoChordisConsonantappendlentuple)r0   iteratorstartingVerticalityverticalityBufferrU   s        r   %iterateConsonanceBoundedVerticalities2TimespanTree.iterateConsonanceBoundedVerticalitiesl  s     J ,,.	"&x. &--/;;==&*8n# &--/;;== 11#K$$[1""$0022()A- 122%0M! $  		 ! sW   C5C #C5C% #C53:C51$C5
C"C5!C""C5%
C2/C51C22C5Fc              #  D  #    U(       aK  U R                  5       nU R                  U5      nUv   UR                  nUb  Uv   UR                  nUb  M  ggU R                  5       nU R                  U5      nUv   UR                  nUb  Uv   UR                  nUb  M  gg7f)a  
Iterates all vertical moments in this TimespanTree, represented as
:class:`~music21.tree.verticality.Verticality` objects.

..  note:: The TimespanTree can be mutated while its verticalities are
    iterated over. Each verticality holds a reference back to the
    TimespanTree and will ask for the start-offset after (or before) its
    own start offset in order to determine the next verticality to
    yield. If you mutate the tree by adding or deleting timespans, the
    next verticality will reflect those changes.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans(classList=(note.Note,))
>>> iterator = scoreTree.iterateVerticalities()
>>> for _ in range(10):
...     next(iterator)
...
<music21.tree.verticality.Verticality 0.0 {A3 E4 C#5}>
<music21.tree.verticality.Verticality 0.5 {G#3 B3 E4 B4}>
<music21.tree.verticality.Verticality 1.0 {F#3 C#4 F#4 A4}>
<music21.tree.verticality.Verticality 2.0 {G#3 B3 E4 B4}>
<music21.tree.verticality.Verticality 3.0 {A3 E4 C#5}>
<music21.tree.verticality.Verticality 4.0 {G#3 B3 E4 E5}>
<music21.tree.verticality.Verticality 5.0 {A3 E4 C#5}>
<music21.tree.verticality.Verticality 5.5 {C#3 E4 A4 C#5}>
<music21.tree.verticality.Verticality 6.0 {E3 E4 G#4 B4}>
<music21.tree.verticality.Verticality 6.5 {E3 D4 G#4 B4}>

Verticalities can also be iterated in reverse:

>>> iterator = scoreTree.iterateVerticalities(reverse=True)
>>> for _ in range(10):
...     next(iterator)
...
<music21.tree.verticality.Verticality 35.0 {F#3 A#3 C#4 F#4}>
<music21.tree.verticality.Verticality 34.5 {B2 B3 D4 E#4}>
<music21.tree.verticality.Verticality 34.0 {B2 B3 D4 F#4}>
<music21.tree.verticality.Verticality 33.5 {D3 B3 C#4 F#4}>
<music21.tree.verticality.Verticality 33.0 {D3 B3 F#4}>
<music21.tree.verticality.Verticality 32.5 {C#3 A#3 C#4 F#4}>
<music21.tree.verticality.Verticality 32.0 {C#3 B3 D4 F#4}>
<music21.tree.verticality.Verticality 31.0 {B2 C#4 E4 F#4}>
<music21.tree.verticality.Verticality 30.0 {A#2 C#4 E4 F#4}>
<music21.tree.verticality.Verticality 29.5 {A#2 F#3 D4 F#4}>
N)highestPositionrN   rZ   r5   rO   )r0   reverser*   rU   s       r   rc   !TimespanTree.iterateVerticalities  s     b ))+F//7K%99K)!!)== ) ((*F//7K%55K)!!)99 )s   AB A	B B )rr   padEndc             #  ~  #    SSK JnJn  [        U5      nUS::  a  SnUSU 3-  n[	        U5      eU" U R
                  U S9nU(       a
  U/US-
  -  nO/ n[        R                  " [        R                  " U R                  US9U5      UU5       H)  n	U(       d  U" U	5      v   M  U" [        U	5      5      v   M+     g7f)	a	  
Iterates :class:`~music21.tree.verticality.Verticality` objects in groups of length `n`.

..  note:: The TimespanTree can be mutated while its verticalities are
    iterated over. Each verticality holds a reference back to the
    TimespanTree and will ask for the start-offset after (or before) its
    own start offset in order to determine the next verticality to
    yield. If you mutate the tree by adding or deleting timespans, the
    next verticality will reflect those changes.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans(classList=(note.Note,))
>>> iterator = scoreTree.iterateVerticalitiesNwise(n=2)
>>> for _ in range(4):
...     print(next(iterator))
...
<music21.tree.verticality.VerticalitySequence [
    (0.0 {A3 E4 C#5}),
    (0.5 {G#3 B3 E4 B4})
    ]>
<music21.tree.verticality.VerticalitySequence [
    (0.5 {G#3 B3 E4 B4}),
    (1.0 {F#3 C#4 F#4 A4})
    ]>
<music21.tree.verticality.VerticalitySequence [
    (1.0 {F#3 C#4 F#4 A4}),
    (2.0 {G#3 B3 E4 B4})
    ]>
<music21.tree.verticality.VerticalitySequence [
    (2.0 {G#3 B3 E4 B4}),
    (3.0 {A3 E4 C#5})
    ]>

Grouped verticalities can also be iterated in reverse, but note that the
groups within each iteration are still ordered from earliest to last.

>>> iterator = scoreTree.iterateVerticalitiesNwise(n=2, reverse=True)
>>> for _ in range(4):
...     print(next(iterator))
...
<music21.tree.verticality.VerticalitySequence [
    (34.5 {B2 B3 D4 E#4}),
    (35.0 {F#3 A#3 C#4 F#4})
    ]>
<music21.tree.verticality.VerticalitySequence [
    (34.0 {B2 B3 D4 F#4}),
    (34.5 {B2 B3 D4 E#4})
    ]>
<music21.tree.verticality.VerticalitySequence [
    (33.5 {D3 B3 C#4 F#4}),
    (34.0 {B2 B3 D4 F#4})
    ]>
<music21.tree.verticality.VerticalitySequence [
    (33.0 {D3 B3 F#4}),
    (33.5 {D3 B3 C#4 F#4})
    ]>

When iterating with `n > 1` and `padEnd=True` will put sentinel
Verticalities in the last VerticalitySequences that occur at the
`endTime` of the tree, with no elements:

>>> iterator = scoreTree.iterateVerticalitiesNwise(n=3, padEnd=True)
>>> for v in iterator:
...     pass
>>> v
<music21.tree.verticality.VerticalitySequence [
    (35.0 {F#3 A#3 C#4 F#4}),
    (36.0 {}),
    (36.0 {})
    ]>


* Changed in v8: added padEnd.  Streams with fewer than n elements
    also return an empty sentinel entry.
r   )r   Verticalityz4The number of verticalities in the group must be at zleast one. Got )timespanTree   )rr   N)music21.tree.verticalityr   rv   intr   r   more_itertoolswindowed	itertoolschainrc   reversed)
r0   nrr   rt   r   rv   rT   sentinelVerticalityendingverticalitiess
             r   iterateVerticalitiesNwise&TimespanTree.iterateVerticalitiesNwise  s     \ 	NF6LG,,G'00)$,,TJ)*a!e4FF+44OOD55g5FO
M
 )-88)(=*ABB
s   B;B=c                    [        U[        5      (       d  U/nU HY  nU R                  U5      nU(       d  M  U H6  nU R                  U5        UR	                  U5      nU R                  U5        M8     M[     g)ai  
Splits all timespans in this TimespanTree at `offsets`, operating in
place.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans()
>>> scoreTree.elementsStartingAt(0.1)
()

>>> for timespan in scoreTree.elementsOverlappingOffset(0.1):
...     print("%r, %s" % (timespan, timespan.part.id))
...
<PitchedTimespan (0.0 to 0.5) <music21.note.Note C#>>, Soprano
<PitchedTimespan (0.0 to 0.5) <music21.note.Note A>>, Tenor
<PitchedTimespan (0.0 to 0.5) <music21.note.Note A>>, Bass
<PitchedTimespan (0.0 to 1.0) <music21.note.Note E>>, Alto

Note that the Alto is last in both of these because currently the sorting
is done according to the endTime -- potentially to be changed soon.

>>> scoreTree.splitAt(0.1)
>>> for timespan in scoreTree.elementsStartingAt(0.1):
...     print("%r, %s" % (timespan, timespan.part.id))
...
<PitchedTimespan (0.1 to 0.5) <music21.note.Note C#>>, Soprano
<PitchedTimespan (0.1 to 0.5) <music21.note.Note A>>, Tenor
<PitchedTimespan (0.1 to 0.5) <music21.note.Note A>>, Bass
<PitchedTimespan (0.1 to 1.0) <music21.note.Note E>>, Alto

>>> scoreTree.elementsOverlappingOffset(0.1)
()
N)rL   r   elementsOverlappingOffsetrC   splitAtinsert)r0   r=   r*   overlapsoverlapshardss         r   r   TimespanTree.splitAt  sk    B '8,,iGF55f=H###G, 0F# $	 r   c                    0 nU R                  5        H  n[        5       X'   M     U  H"  nXR                     nUR                  U5        M$     U$ )a.  
Returns a dictionary of TimespanTrees where each entry
is indexed by a Part object (TODO: Don't use mutable objects as hash keys!)
and each key is a TimeSpan tree containing only element timespans belonging
to that part.

Used by reduceChords.  May disappear at any time without a deprecation
notice.
)allPartsr   partr   )r0   partwiseTimespanTreesr   timespanpartwiseTimespanTrees        r   toPartwiseTimespanTrees$TimespanTree.toPartwiseTimespanTrees  sR     !#MMOD*6.!' $H#8#G  ''1  %$r   c                B    SSK Jn  U" U 5      nUR                  5       nU$ )a  
Unwraps a sequence of `Verticality` objects into a dictionary of
`Part`:`Horizontality` key/value pairs.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans(classList=(note.Note,))
>>> iterator = scoreTree.iterateVerticalitiesNwise()
>>> verticalities = next(iterator)
>>> unwrapped = scoreTree.unwrapVerticalities(verticalities)
>>> for part in sorted(unwrapped, key=lambda x: x.partName):
...     print(part)
...     horizontality = unwrapped[part]
...     for timespan in horizontality:
...         print('\t%r' % timespan)
...
<music21.stream.Part Alto>
    <PitchedTimespan (0.0 to 1.0) <music21.note.Note E>>
    <PitchedTimespan (1.0 to 2.0) <music21.note.Note F#>>
<music21.stream.Part Bass>
    <PitchedTimespan (0.0 to 0.5) <music21.note.Note A>>
    <PitchedTimespan (0.5 to 1.0) <music21.note.Note G#>>
    <PitchedTimespan (1.0 to 2.0) <music21.note.Note F#>>
<music21.stream.Part Soprano>
    <PitchedTimespan (0.0 to 0.5) <music21.note.Note C#>>
    <PitchedTimespan (0.5 to 1.0) <music21.note.Note B>>
    <PitchedTimespan (1.0 to 2.0) <music21.note.Note A>>
<music21.stream.Part Tenor>
    <PitchedTimespan (0.0 to 0.5) <music21.note.Note A>>
    <PitchedTimespan (0.5 to 1.0) <music21.note.Note B>>
    <PitchedTimespan (1.0 to 2.0) <music21.note.Note C#>>
r   r   )ry   r   unwrap)r   r   sequence	unwrappeds       r   unwrapVerticalities TimespanTree.unwrapVerticalities  s%    D 	A&}5OO%	r   c                x    [        5       nU  H  nUR                  UR                  5        M      [        US S9nU$ )Nc                6    U R                  5       R                  $ r   )getInstrumentpartIdr   s    r   <lambda>'TimespanTree.allParts.<locals>.<lambda>  s    AOO,=,D,Dr   key)setaddr   sorted)r0   partsr   s      r   r   TimespanTree.allParts  s5    HIIhmm$ u"DEr   c                    SnU R                  5        H>  n[        UR                  5      [        UR                  5      -   nUc  UnM5  X:  d  M<  UnM@     U$ )a  
The maximum number of timespans overlapping at any given moment in this
timespan collection.

>>> score = corpus.parse('bwv66.6')
>>> scoreTree = score.asTimespans(classList=(note.Note,))
>>> scoreTree.maximumOverlap()
4

Returns None if there is no verticality here.
N)rc   ri   rP   overlapTimespans)r0   r   vdegreeOfOverlaps       r   maximumOverlapTimespanTree.maximumOverlap  sX     **,A!!"2"23c!:L:L6MMO)*) - r   c                B    [         R                  " U R                  5      $ )z
defined so a TimespanTree can be used like an PitchedTimespan

TODO: Look at subclassing or at least deriving from a common base.
)r   unwrapWeakref_sourcer6   s    r   elementTimespanTree.element   s     ##DLL11r   c                :    [         R                  " U5      U l        g r   )r   wrapWeakrefr   )r0   exprs     r   r   r   )  s    ))$/r   )r   )NTr   )rR   zspans.PitchedTimespanreturnzspans.PitchedTimespan | None)F)rr   boolr   z=Generator['music21.tree.verticality.Verticality', None, None])   )r   rz   rr   r   rt   r   r   z*Generator[VerticalitySequence, None, None])r   r   r   r   __doc__	__slots__staticmethodr!   r&   r.   propertyr*   r?   rC   rW   r\   r_   rn   rc   r   r   r   r   r   r   r   setterr   r   r   r   r   r   0   sY   rf I   #J % %:: //.// 
&	//h .3..3 
&	.3`*W2v @:@: 
G@:F eC16ueCeC*.eC@DeC	3eCz*$X%$ $ $P\ 2 2 ^^0 0r   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  SSK Jn  UR	                  5       nUR                  SUR                  S5      5        UR                  SUR                  S5      5        UR                  5       nUR                  S5      nUR                  nU R                  [        U5      S5        g )	Nr   rF   r   )noteCzF#4g        rx   )rJ   rG   r   r   Streamr   KeyNoteasTimespansrN   pitchSetassertEqualri   )r0   rG   r   r   s	scoreTreer   pss           r   testGetVerticalityAtWithKey Test.testGetVerticalityAtWithKey0  s{    " MMO	CGGCL!	DIIe$%MMO	&&s+ZZR!$r   c           
     B   [        S5       GH  n[        [        S5      5      n[        [        S5      5      n[        R                  " U5        [        R                  " U5        / n[	        X#5       HV  u  pVXV::  a'  UR                  [        R                  " XV5      5        M1  UR                  [        R                  " Xe5      5        MX     [        5       n[        U5       GHB  u  pUR                  U	5        [        [        US US-    S S95      n
[        U5      n[        S U
 5       5      n[        S U
 5       5      nU R                  UU
XU
45        U R                  UR                  R                   [        S U
 5       5      5        U R                  UR                  R"                  [        S	 U
 5       5      5        U R                  UR%                  5       U5        U R                  UR&                  U5        [	        X5       H  u  pU R                  X5        M     GME     [        R                  " U5        U(       d  GM;  UR)                  5       n	[        US
 S9n
UR+                  U	5        [        U5      nU R                  UU
XU
45        UR                  b  [        S U
 5       5      n[        S U
 5       5      nU R                  UR                  R                   [        S U
 5       5      5        U R                  UR                  R"                  [        S U
 5       5      5        U R                  UR%                  5       U5        U R                  UR&                  U5        [	        X5       H  u  pU R                  X5        M     U(       a  GMT  GM     g )Nd      rx   c                2    U R                   U R                  4$ r   r*   r   r   s    r   r   'Test.testTimespanTree.<locals>.<lambda>M  s    AHHaiiCXr   r   c              3  8   #    U  H  oR                   v   M     g 7fr   r*   .0r    s     r   	<genexpr>(Test.testTimespanTree.<locals>.<genexpr>O  s     %O8N1hh8N   c              3  8   #    U  H  oR                   v   M     g 7fr   r   r   s     r   r   r   P       $O8N1YY8Nr   c              3  8   #    U  H  oR                   v   M     g 7fr   r   r   s     r   r   r   V  r   r   c              3  8   #    U  H  oR                   v   M     g 7fr   r   r   s     r   r   r   X  r   r   c                2    U R                   U R                  4$ r   r   r   s    r   r   r   b  s    qxx>Sr   c              3  8   #    U  H  oR                   v   M     g 7fr   r   r   s     r   r   r   i  s     )S<Rq((<Rr   c              3  8   #    U  H  oR                   v   M     g 7fr   r   r   s     r   r   r   j       (S<Rq<Rr   c              3  8   #    U  H  oR                   v   M     g 7fr   r   r   s     r   r   r   l  r   r   c              3  8   #    U  H  oR                   v   M     g 7fr   r   r   s     r   r   r   n  r   r   )rangelistrandomshuffleziprh   r	   Timespanr   	enumerater   r   minmaxr   rootNode
endTimeLowendTimeHighr5   r   poprC   )r0   attemptstartsstopstssstartstoptsTreeir   currentTimespansInListcurrentTimespansInTreecurrentPositioncurrentEndTimeinListinTrees                   r   testTimespanTreeTest.testTimespanTree<  s   SzG%)_FrOENN6"NN5!C"61=JJu~~e:;JJu~~d:;	  2
 "^F(~h')-fS!a%[9X/Z *[&)-f&"%%O8N%O"O!$$O8N$O!O  !7!7")CY!Z\   !;!;!$$O8N$O!OQ  !<!<!$$O8N$O!OQ  !6!6!8/J  @&)*@&YNF$$V4 'Z#  .( NN3#779)/4S*U&%%h/)-f&  !7!7")CY!Z\ ??.&))S<R)S&SO%((S<R(S%SN$$V__%?%?%((S<R(S%SU$$V__%@%@%((S<R(S%SU$$V%:%:%<oN$$V^^^D*-.D*]((8 +^% #E "r   r   N)r   r   r   r   r   r  r   r   r   r   r   r   .  s    
%69r   r   __main__) r   
__future__r   collections.abcr   r   r}   r   typingtunittestr{   rJ   r   r   r   music21.treer	   r
   TYPE_CHECKINGry   r   EnvironmentenvironLocalTreeExceptionr   
OffsetTreer   TestCaser   r   mainTestr   r   r   <module>r     s   
 # /            ??< &&':;	L66 	
{05## {0|D98 D9P zT r   