
    3jx                       d Z ddlmZ ddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlm Z  ddlm!Z! 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jR                  rddl*Z* ejV                  d      Z,dd iZ-g d!Z. G d" d#ej^                        Z0 G d$ d%e jb                        Z2 G d& d'e2      Z3 G d( d)e jb                        Z4 G d* d+e4      Z5 G d, d-e4      Z6 G d. d/e4      Z7 G d0 d1e4      Z8 G d2 d3e jb                        Z9 G d4 d5e jb                        Z: G d6 d7e:      Z; G d8 d9e:      Z< G d: d;e:      Z= G d< d=e jb                        Z> G d> d?e jb                        Z? G d@ dAe jb                        Z@dPdBZA	 dQ	 	 	 	 	 dRdCZBdSdDZC G dE dFej                        ZE G dG dHej                        ZF G dI dJej                        ZG G dK dLej                        ZH G dM dNej                        ZJeKdOk(  rddlZ ej                  eJ       yy)Ta
  
music21.humdrum.spineParser is a collection of utilities for changing
native humdrum code into music21 streams.  Most music21 users will
simply want to call:

>>> #_DOCS_SHOW myFile = converter.parse('myFile.krn')
>>> #_DOCS_SHOW myFile.show()

The methods in here are documented for developers wishing to expand
music21's ability to parse humdrum.

SpineParsing consists of several steps.

* The data file is read in and all events are sliced horizontally (EventCollections)
    and vertically (Protospines)
* Protospines are parsed into HumdrumSpines by following Spine Path Indicators
    (:samp:`*^` and :samp:`*v` especially)
    Protospines that separate become new Protospines with their parentSpine indicated.  Protospines
    that merge again then followed by the same Protospine as before.  This will cause problems if
    a voice re-merges with another staff, but in practice I have not
    seen a .krn file that does this and
    should be avoided in any case.
* HumdrumSpines are reclassed according to their exclusive definition.
    :samp:`**kern` becomes KernSpines, etc.
* All reclassed HumdrumSpines are filled with music21 objects in their .stream property.
    Measures are put into the spine but are empty containers.  The resulting
    HumdrumSpine.stream objects
    look like `Stream.flatten(retainContainers=True)` versions in many ways.
* For HumdrumSpines with parent spines their .stream contents are then
    inserted into their parent spines with
    voice tagged as a music21 Group property.
* Lyrics and Dynamics are placed into their corresponding HumdrumSpine.stream objects.
* Stream elements are moved into their measures within a Stream.
* Measures are searched for elements with voice groups and Voice objects are created.

* Changed in v10: flag attributes `isSpineLine, isComment, isGlobal, isReference` have been
    removed from HumdrumLine and all subclasses. `isinstance(...)` is a bit slower than
    checking these, but adds correct typing.  Nothing is stored with weakrefs.  `.iterIndex`
    and hand roled iterator/generators are gone now (could've gone when Python 2.4 became
    the minimum version).  `HumdrumDataCollection.parsePositionInStream` is gone (was
    duplicating `numLines`); `HumdrumDataCollection.fileLength` is now the read-only
    property `numLines` (= `len(self.dataStream)`); `HumdrumLine.position` and
    `SpineEvent.position` were both renamed to `lineNumber` and now hold the 1-based
    source line number (was eventList index for SpineEvent),
    advancing on blank lines too.  Blank lines now produce `BlankLine` HumdrumLine
    entries rather than being skipped, so `eventList[lineNumber - 1]` always
    resolves to the line at that source position.
    )annotationsN)opFrac)OffsetQL)articulations)bar)base)chord)clef)common)dynamics)duration)environment)exceptions21)expressions)
instrument)key)note)meter)metadata)roman)prebase)stream)tempo)tie)GraceDuration)
harmParser)instrumentszhumdrum.spineParserJRPF)z*+*-*^*v*x*c                      e Zd ZdZy)HumdrumExceptionzB
    General Exception class for problems relating to Humdrum
    N)__name__
__module____qualname____doc__     H/DATA/.local/lib/python3.12/site-packages/music21/humdrum/spineParser.pyr%   r%   j   s     	r+   r%   c                      e Zd ZdZddZedd       ZddZddZ	 d	 	 	 ddZ	ddZ
	 d	 	 	 dd	Z	 	 dd
Z	 	 d	 	 	 	 	 ddZddZdddZy)HumdrumDataCollectiona  
    .. note:: Most users should not need to be here.  Just run `converter.parse('file.krn')`
        and it will give you a stream.Score instead.
        Intermediate users who want to get into the guts of Humdrum are still
        probably better off running humdrum.parseFile("filename")
        which returns a humdrum.SpineCollection directly.

    A HumdrumDataCollection takes in a mandatory list where each element
    is a line of humdrum data.  Together this list represents a collection
    of spines.  Essentially it's the contents of a humdrum file.

    Usually you will probably want to use HumdrumFile which can read
    in a file directly.  This class exists in case you have your Humdrum
    data in another format (database, from the web, etc.) and already
    have it as a string.

    LIMITATIONS:
    (1) Spines cannot change definition (\*\*exclusive interpretations) mid-spine.

        So if you start off with \*\*kern, the rest of the spine needs to be
        \*\*kern (actually, the first exclusive interpretation for a spine is
        used throughout).

        Note that, even though changing exclusive interpretations mid-spine
        seems to be legal by the humdrum definition, it looks like none of the
        conventional humdrum parsing tools allow for changing
        definitions mid-spine, so I don't think this limitation is a problem.
        (Craig Stuart Sapp confirmed this to me.)

        The Aarden/Miller Palestrina dataset uses `\*-` followed by `\*\*kern`
        at the changes of sections thus some parsing of multiple exclusive
        interpretations in a protospine may be necessary.  But none change definition.

    (2) Split spines are assumed to be voices in a single spine staff.
    c                    g | _         d| _        g | _        g | _        d | _        t        |t              r|j                         }|| _        t        j                         | _	        y Nr   )	eventList	maxSpinesprotoSpineseventCollectionsspineCollection
isinstancestr
splitlines
dataStreamr   Score)selfr9   s     r,   __init__zHumdrumDataCollection.__init__   sV    ,.-/7959j#&#..0J%/ 17r+   c                ,    t        | j                        S )zR
        The number of lines in `self.dataStream`, including blank lines.
        )lenr9   r;   s    r,   numLineszHumdrumDataCollection.numLines   s    
 4??##r+   c                    | j                   st        d      | j                  | j                         \  }}|r|| j                  |      S | j	                  | j                         S )a  
        Parse `self.dataStream` into music21 objects, returning the resulting
        :class:`~music21.stream.Score` (or :class:`~music21.stream.Opus`
        for multipart files like the Palestrina dataset).

        The parsed stream is also stored on `self.stream`.
        +Need a list of lines (dataStream) to parse!)r9   r%   determineIfDataStreamIsOpusparseOpusDataCollectionsparseNonOpus)r;   hasOpusdataCollectionss      r,   parsezHumdrumDataCollection.parse   s^     "#PQQ#'#C#CDOO#T 200AA$$T__55r+   c                ,   t        j                         }|| _         d| _        | j                  |       | j	                          | j                         | _        | j                  j                          | j                          | j                  D ])  }dt        |j                        z   |j                   _
        + | j                  D ]:  }|j                  |j                  dk(  s |j                  |j                          < | j                          |S )z
        The main parse function for non-opus data collections.

        Populates `self.stream` (a :class:`~music21.stream.Score`) and returns it.
        r   spine_kern)r   r:   r2   parseEventListFromDataStream#parseProtoSpinesAndEventCollectionscreateHumdrumSpinesr5   createMusic21StreamsinsertGlobalEventsr7   idparentSpine	spineTypeinsertparseMetadata)r;   r9   score	thisSpines       r,   rE   z"HumdrumDataCollection.parseNonOpus   s      	))*5002#779113!--I"*S->">I .--I$$,1D1D1NY--. . 	r+   Nc                   || j                   }|t        d      g }g }t        |      D ]e  \  }}|j                         }t	        j
                  d|      r|j                  |       >t	        j
                  d|      sU|j                  |       g t        |      dk  ry|d   |d   kD  rn|j                  t        |             g }t        t        |            D ]|  }|dk(  r||   }|j                  |d|d	z           %|t        |      d	z
  k(  r ||d	z
     d	z   }|j                  ||d        V||d	z
     d	z   }||   d	z   }	|j                  |||	        ~ t        |      d	kD  rd
|fS t        d      )a  
        Some Humdrum files contain multiple pieces in one file
        which are better represented as :class:`~music21.stream.Opus`
        file containing multiple scores.

        This method examines that dataStream (or `self.dataStream`) and
        if it only has a single piece then it returns (False, None).

        If it has multiple pieces, it returns True and a list of dataStreams.

        >>> from pprint import pprint as pp

        >>> mps = humdrum.testFiles.multipartSanctus
        >>> hdc = humdrum.spineParser.HumdrumDataCollection(mps)
        >>> (hasOpus, dataCollections) = hdc.determineIfDataStreamIsOpus()
        >>> hasOpus
        True
        >>> pp(dataCollections)
        [['!!!COM: Palestrina, Giovanni Perluigi da',
          '**kern\t**kern\t**kern\t**kern',
          '*Ibass\t*Itenor\t*Icalto\t*Icant',
          '!Bassus\t!Tenor\t!Altus\t!Cantus',
          '*clefF4\t*clefGv2\t*clefG2\t*clefG2',
          '*M4/2\t*M4/2\t*M4/2\t*M4/2',
          '=1\t=1\t=1\t=1',
          '0r\t0r\t1g\t1r',
          '.\t.\t1a\t1cc',
          '=2\t=2\t=2\t=2',
          '0r\t0r\t1g\t1dd',
          '.\t.\t1r\t1cc',
          '*-\t*-\t*-\t*-'],
         ['!! Pleni',
          '**kern\t**kern\t**kern',
          '*Ibass\t*Itenor\t*Icalto',
          '*clefF4\t*clefGv2\t*clefG2',
          '*M4/2\t*M4/2\t*M4/2',
          '=3\t=3\t=3',
          '1G\t1r\t0r',
          '1A\t1c\t.',
          '=4\t=4\t=4',
          '1B\t1d\t1r',
          '1c\t1e\t1g',
          '*-\t*-\t*-'],
         ['!! Hosanna',
          '**kern\t**kern\t**kern\t**kern',
          '*Ibass\t*Itenor\t*Icalto\t*Icant',
          '*clefF4\t*clefGv2\t*clefG2\t*clefG2',
          '*M3/2\t*M3/2\t*M3/2\t*M3/2',
          '=5\t=5\t=5\t=5',
          '1r\t1r\t1g\t1r',
          '2r\t2r\t[2a\t[2cc',
          '=5\t=5\t=5\t=5',
          '1r\t1r\t2a]\t2cc]',
          '.\t.\t2f\t1dd',
          '2r\t2r\t2g\t.',
          '*-\t*-\t*-\t*-']]
        NzdataStream cannot be Nonez^(\*-\t)*\*-$z^(\*\*\w+\t)*\*\*\w+$   )FNr      TzMalformed humdrum data: possibly multiple **tags without closing information. Or a *tandem tag accidentally encoded as a **spine tag.)
r9   	TypeError	enumeraterstripresearchappendr>   ranger%   )
r;   r9   startIndices
endIndicesilinerG   endPos
startIndexendIndexs
             r,   rC   z1HumdrumDataCollection.determineIfDataStreamIsOpus   s   | J788
 ,GAt;;=Dyy)40!!!$3T:##A& - |q  b>L,, c*o.s:'AAv#A&&z+6A:'>?c*o))'A.2
&&z*+'>? (A.2
%a=1,&&z*X'FG ( !#/**";< <r+   c                   t        j                         }t        |      D ][  \  }}t        |      }|j	                         }dt        |dz         z   |_        |dz   |j                  _        |j                  |       ] |rBt        j                  |j                  d   j                        |_        d|j                  _        || _         |S )a  
        Take a dataCollection from `determineIfDataStreamIsOpus`
        and set `self.stream` to be an Opus instead.

        >>> mps = humdrum.testFiles.multipartSanctus
        >>> hdc = humdrum.spineParser.HumdrumDataCollection(mps)
        >>> (hasOpus, dataCollections) = hdc.determineIfDataStreamIsOpus()
        >>> if hasOpus is True:
        ...     op = hdc.parseOpusDataCollections(dataCollections)
        ...     print(len(op.scores))
        ...     for sc in op.scores:
        ...        print(sc)
        3
        <music21.stream.Score section_1>
        <music21.stream.Score section_2>
        <music21.stream.Score section_3>
        section_r[   r   )r   Opusr]   r.   rH   r7   rQ   r   numberra   copydeepcopyscores)r;   rG   opusre   dchdcscs          r,   rD   z.HumdrumDataCollection.parseOpusDataCollectionsF  s    & {{}/EAr'+CBQU+BE!"QBKKKKO 0  MM$++a.*A*ABDM#$DMM r+   c                z   || j                   }|t        d      g | _        d}|D ]  }|dz  }|j                         }|dk(  r%| j                  j	                  t        |             Ct        j                  d|      r&| j                  j	                  t        ||             t        j                  d|      r&| j                  j	                  t        ||             t        ||      }t        | j                  |j                        | _        | j                  j	                  |       	 | j                  S )a  
        Sets `self.eventList` from a dataStream (that is, a
        list of lines).  It sets `self.maxSpines` to the
        largest number of spine events found on any line
        in the file.

        The difference between the dataStream and `self.eventList`
        are the following:

            * Blank lines are skipped.
            * !!! lines become :class:`~music21.humdrum.spineParser.GlobalReferenceLine` objects
            * !! lines become :class:`~music21.humdrum.spineParser.GlobalCommentLine` objects
            * all other lines become :class:`~music21.humdrum.spineParser.SpineLine` objects

        Returns eventList in addition to setting it as `self.eventList`.

        >>> eventString = ('!!! COM: Beethoven, Ludwig van\n'
        ...                '!! Not really a piece by Beethoven\n'
        ...                '**kern\t**dynam\n'
        ...                'C4\tpp\n'
        ...                'D8\t.\n')
        >>> hdc = humdrum.spineParser.HumdrumDataCollection(eventString)
        >>> hdc.maxSpines = 2
        >>> eList = hdc.parseEventListFromDataStream()
        >>> eList is hdc.eventList
        True
        >>> for e in eList:
        ...     print(e)
        <music21.humdrum.spineParser.GlobalReferenceLine COM: 'Beethoven, Ludwig van'>
        <music21.humdrum.spineParser.GlobalCommentLine 'Not really a piece by Beethoven'>
        <music21.humdrum.spineParser.SpineLine line 3 (2 spines)>
        <music21.humdrum.spineParser.SpineLine line 4 (2 spines)>
        <music21.humdrum.spineParser.SpineLine line 5 (2 spines)>
        >>> print(eList[0].value)
        Beethoven, Ludwig van

        Print line number 4 (which is eList[3] in zero indexed)

        >>> print(eList[3].spineData)
        ['C4', 'pp']
        rB   r   r[    z!!!!!)r9   r%   r1   r^   ra   	BlankLiner_   matchGlobalReferenceLineGlobalCommentLine	SpineLinemaxr2   	numSpines)r;   r9   
lineNumberrf   thisLines        r,   rL   z2HumdrumDataCollection.parseEventListFromDataStreamh  s   Z J!&'TUU
D!OJ;;=Drz %%i
&;<&$'%%&9*d&KL%&%%&7
D&IJ$Z6!$T^^X5G5G!H%%h/  ~~r+   c           	          j                   s j                          g }g d fd}t         j                         }t         j                        D ]  }g }t        |      D ]\  }|dk(  r=j                  t         j                   j                   |   j                               |j                   |||             ^ |j                  t        |              | _	         _
        |fS )aj  
        Run after
        :meth:`~music21.humdrum.spineParser.HumdrumDataCollection.parseEventListFromDataStream()`
        to take `self.eventList` and slice it horizontally
        to get `self.eventCollections`, which is a list of
        EventCollection objects, or things that happen simultaneously.

        And, more importantly, this method slices `self.eventList`
        vertically to get `self.protoSpines` which is a list
        of ProtoSpines, that is a vertical slice of everything that
        happens in a column, regardless of spine-path indicators.

        EventCollection objects store global events. ProtoSpines do not.

        So `self.eventCollections` and `self.protoSpines` can each be
        thought of as a two-dimensional sheet of cells, but where
        the first index of the former is the vertical index in
        the dataStream and the first index of the latter is the
        horizontal index in the dataStream.  The contents of
        each cell is a SpineEvent object or None (if there's no
        data at that point).  Even '.' (continuation events) get
        translated into SpineEvent objects.

        Calls :meth:`~music21.humdrum.spineParser.parseEventListFromDataStream`
        if it hasn't already been called.

        Returns a tuple of protoSpines and eventCollections in addition to
        setting it in the calling object.

        >>> eventString = ('!!!COM: Beethoven, Ludwig van\n'
        ...                '!! Not really a piece by Beethoven\n'
        ...                '**kern\t**dynam\n'
        ...                'C4\tpp\n'
        ...                'D8\t.\n')
        >>> hdc = humdrum.spineParser.HumdrumDataCollection(eventString)
        >>> hdc.maxSpines = 2
        >>> protoSpines, eventCollections = hdc.parseProtoSpinesAndEventCollections()
        >>> protoSpines is hdc.protoSpines
        True
        >>> eventCollections is hdc.eventCollections
        True

        Looking at individual slices is unlikely to tell you much:

        >>> for thisSlice in eventCollections:
        ...    print(thisSlice)
        <music21.humdrum.spineParser.EventCollection line 1, 2 events, 2 spines>
        <music21.humdrum.spineParser.EventCollection line 2, 2 events, 2 spines>
        <music21.humdrum.spineParser.EventCollection line 3, 2 events, 2 spines>
        <music21.humdrum.spineParser.EventCollection line 4, 2 events, 2 spines>
        <music21.humdrum.spineParser.EventCollection line 5, 2 events, 2 spines>

        >>> for thisSlice in protoSpines:
        ...    print(thisSlice)
        <music21.humdrum.spineParser.ProtoSpine 5 events>
        <music21.humdrum.spineParser.ProtoSpine 5 events>

        But looking at the individual slices is revealing:

        >>> eventCollections[4].getAllOccurring()
        [<music21.humdrum.spineParser.SpineEvent D8>, <music21.humdrum.spineParser.SpineEvent pp>]

        >>> for protoEvent in protoSpines[0]:
        ...    print(repr(protoEvent))
        None
        None
        <music21.humdrum.spineParser.SpineEvent **kern>
        <music21.humdrum.spineParser.SpineEvent C4>
        <music21.humdrum.spineParser.SpineEvent D8>
        c                   |    }	j                   |    }t        |t              rt        |j                        |kD  rt        |j                  |   |j                        }||_        |j                  t        v rd|_
        |j                  ||       |j                  dk(  rG| dkD  rB| dz
     j                  |   }|+| dz
     j                  |      }||j                  ||       |S t        |t              s|dk(  r|j                  |       t        d|j                        }||_        |j                  ||       y)z
            Process the (i, j) cell.  Mutates `returnEventCollections[i]`
            and returns the SpineEvent to record in the protoSpine, or
            None if there's no event at this cell.
            T.r   r[   Nrv   )r1   r6   r|   r>   	spineData
SpineEventr   protoSpineIdcontentsspinePathIndicatorsspinePathDataaddSpineEventeventsgetSpineOccurringaddLastSpineEventaddGlobalEvent)
re   jthisEventCollectioncurrentLine	thisEvent	lastEventoccurringEventplaceholderreturnEventCollectionsr;   s
           r,   processEventForOneCellzYHumdrumDataCollection.parseProtoSpinesAndEventCollections.<locals>.processEventForOneCell   s@    #9";..+K+y1c+:O:O6PST6T&{'<'<Q'?AWAWX	)*	&%%)<<8<'5#11!Y?%%,Q 6q1u = D DQ GI ,)?A)F)X)XYZ)[)5/AA!^T   k95!q& $22;?$R)?)?@K'(K$--a=r+   r   r   )re   intr   r   returnSpineEvent | None)r1   rL   r>   rb   r2   ra   EventCollectionr   
ProtoSpiner3   r4   )r;   returnProtoSpinesr   	numEventsr   protoSpineEventListre   r   s   `      @r,   rM   z9HumdrumDataCollection.parseProtoSpinesAndEventCollections  s    R ~~--/ /18:!	F '	t~~&A9;9%6*11'37>>!3D3O3OQR $**+A!Q+GH & $$Z0C%DE ' - 6!#9::r+   c                   ||| j                   }| j                  }t        |      }t        j                  d       }t               }t        t        |            D ]  }||   }|j                  }t        |      D ]\  }	||	   j                  |   }
|
||	   }||j                         }||_
        |||	<   |j                  |
       |j                  |
_        ^ |j                  st        j                  d       }d}d}t        |      D ]:  }	||	   j                  |   }
||	   }|
||j                  |       1|
4|
j                  dk(  r||_        K|
j                  dk(  r|j                  t"        j$                        }|dz   |_
        ||_        d|_        |j                  t"        j$                        }|dz   |_
        ||_        ||_        |j*                  j                  |       |j*                  j                  |       ||f|j,                  |<   |j                  |       |j                  |       5|
j                  d	k(  r|du r$|j&                  |j&                  }nd}||_        l||_        |j&                  |j                  |j&                         nN|dur|j                  |       n8|j                  t"        j.                        }||_
        |j                  |       d}|
j                  d
k(  r.|du r|}|j                  |       |j                  |       d}*|j                  |       = |durt1        d| d|j2                   d      |} |S )a  
        Takes the data from the object's protoSpines and eventCollections
        and returns a :class:`~music21.humdrum.spineParser.SpineCollection`
        object that contains HumdrumSpine() objects.

        A HumdrumSpine object differs from a ProtoSpine in that it follows
        spinePathData -- a ProtoSpine records all data in a given tab
        position, and thus might consist of data from several
        spines that move around.  HumdrumSpines are smart enough not to
        have this limitation.

        When we check for spinePathData we look for the following spine
        path indicators (from HumdrumDoc)::

            *+    add a new spine (to the right of the current spine)
            *-    terminate a current spine
            *^    split a spine (into two)
            *v    join (two or more) spines into one
            *x    exchange the position of two spines
            *     do nothing
        c                      y Nr*   r*   r+   r,   <lambda>z;HumdrumDataCollection.createHumdrumSpines.<locals>.<lambda>T      dr+   c                      y r   r*   r*   r+   r,   r   z;HumdrumDataCollection.createHumdrumSpines.<locals>.<lambda>v  r   r+   Fr   r    )streamClassr[   Tr!   r"   z<ProtoSpine found with unpaired exchange instruction at line z [])r3   r4   r>   r   defaultlistSpineCollectionrb   r   r1   addSpineinsertPointra   rQ   r   r   r   endingPointr   VoicerR   isFirstVoicechildSpineschildSpineInsertPointsPartr%   r   )r;   r3   r4   r2   currentSpineListr5   re   r   r   r   r   currentSpinenewSpineListmergerActiveexchangeActive	newSpine1	newSpine2ss                     r,   rN   z)HumdrumDataCollection.createHumdrumSpines3  s   4 "2":**K#44$	 "--l;)+ s+,-A"21"5,77J9%'N44Q7	$/2' $3#;#;#=L/9L,*6$Q'##I.)5	&! && '44 "--l;L !L"N9%'N44Q7	/2$)A ''5&%%-/9L,''4/ / 8 8V\\ 8 RI,6NI),8I)-1I* / 8 8V\\ 8 RI,6NI),8I)/9L, ,,33I> ,,33I>GPR[F\L77
C ''	2 ''	2''4/ $u,'33?+7+C+CL+/L3=0 4>0'33?(//0H0HI)5(//= !0 8 8V[[ 8 QA,6AM(//2',''4/%.)5 %++L9$++N;). ''5K &N U*& (22<R@S@Z@Z?[[\(^ _ _+] .` r+   c                b   | j                   }|t        d      |j                         }| j                  }t	        |      }d}g }g }t        |      D ]  \  }}	t        |	t        t        f      r|dz  }d}
d}t        |dz   |      D ]+  }||v s||   d   }
||   d   d   j                  dz
  |z   } n t        |	t              r!t        |	j                  |	j                        }nt        |	j                        }||_
        |
|j                  |       |
|f}|j                  |       d} |D ]!  \  }}| j                   j#                  ||       # |r| j                   j%                          |D ]  }| j                   j'                  |        |r| j                   j%                          yy)aK  
        Insert the Global Events (GlobalReferenceLines and GlobalCommentLines) into an appropriate
        place in the outer Stream.

        Run after `self.spineCollection.createMusic21Streams()`.
        Is run automatically by `self.parse()`.
        uses `self.spineCollection.getOffsetsAndPrioritiesByLineNumber()`
        Nzrcannot insert global events: no spineCollection. Call parse() (or createHumdrumSpines() and parseMusic21()) first.r   r[   (   )r5   r%   #getOffsetsAndPrioritiesByLineNumberr1   r>   r]   r6   rz   r{   rb   priorityGlobalReferencecodevalueGlobalCommentra   r   
coreInsertcoreElementsChanged
coreAppend)r;   r5   lineNumberDictr1   maxEventListnumberOfGlobalEventsInARow
insertList
appendListre   eventinsertOffsetinsertPriorityr   elinsertTupleoffsets                   r,   rP   z(HumdrumDataCollection.insertGlobalEvents  s    ..""TU U )LLNNN	9~%&"KM
:<
!),HAu%"57H!IJ*a/*.2!"q1ul3AN*'5a'8';*8*;A*>q*A*J*J,.+/,F+G  4 e%89 )U[[AB&u{{3B,'%%b)#/"4K%%k2 ./*9 -< %JFBKK""62. % KK++-BKK""2&  KK++- r+   c                    || j                   }t        j                         }||_        g }|t           D ]$  }|j	                  |       |j                  |       & |r|j                  |d       yy)z8
        Create a metadata object for the file.
        NT)recurse)r   r   Metadatar   updateMetadatara   remove)r;   r   md
grToRemovegrs        r,   rU   z#HumdrumDataCollection.parseMetadata#  sq     9A 
,.
O$Bb!b! % HHZH. r+   )r9   zstr | list[str]r   None)r   r   )r   stream.Score | stream.Opus)r9   z	list[str]r   zstream.Scorer   )r9   list[str] | Noner   z#tuple[bool, list[list[str]] | None])rG   zlist[list[str]]r   zstream.Opus)r9   r   r   zlist[HumdrumLine])r   z.tuple[list[ProtoSpine], list[EventCollection]])NN)r3   zlist[ProtoSpine] | Noner4   zlist[EventCollection] | Noner   r   r   r   )r   zstream.Stream | Noner   r   )r&   r'   r(   r)   r<   propertyr@   rH   rE   rC   rD   rL   rM   rN   rP   rU   r*   r+   r,   r.   r.   q   s    "H?  $ $6$: &*j<"j< 
+j<X H &*D"D 
DLC;	7C;N .27;U*U 5U 
	Un=.r/r+   r.   c                  6     e Zd ZdZd fdZdddZddZ xZS )	HumdrumFilez|
    A HumdrumFile is a HumdrumDataCollection which takes
    as a mandatory argument a filename to be opened and read.
    c                2    t         |   g        || _        y r   )superr<   filename)r;   r   	__class__s     r,   r<   zHumdrumFile.__init__;  s    *2r+   c                    || j                   }t        |d      5 }| j                  |       d d d        y # 1 sw Y   y xY w)Nzlatin-1)encoding)r   openparseFileHandle)r;   r   humFHs      r,   parseFilenamezHumdrumFile.parseFilename?  s7    }}H(Y/5  ' 0//s	   7A c                d    g }|D ]  }|j                  |        || _        | j                         S )z
        Read all lines from `fileHandle` into ``self.dataStream``, then call
        :meth:`parse` and return its result (a :class:`~music21.stream.Score`
        or :class:`~music21.stream.Opus`).
        )ra   r9   rH   )r;   
fileHandlespineDataCollectionrf   s       r,   r   zHumdrumFile.parseFileHandleG  s5     *,D&&t, -zz|r+   )r   zstr | pathlib.Pathr   r   r   )r   zstr | pathlib.Path | Noner   r   )r   zt.Iterable[str]r   r   )r&   r'   r(   r)   r<   r   r   __classcell__r   s   @r,   r   r   5  s    
3(
r+   r   c                  <    e Zd ZU dZdZded<   dZded<   dZded<   y	)
HumdrumLinea  
    HumdrumLine is a dummy class for subclassing
    :class:`~music21.humdrum.spineParser.SpineLine`,
    :class:`~music21.humdrum.spineParser.GlobalCommentLine`, and
    :class:`~music21.humdrum.spineParser.GlobalReferenceLine` classes
    all of which represent one horizontal line of
    text in a :class:`~music21.humdrum.spineParser.HumdrumDataCollection`
    that is aware of its
    position in the file.

    See the documentation for the specific classes mentioned above
    for more details.
    r   r   r   rv   r7   r   r~   N)r&   r'   r(   r)   r   __annotations__r   r~   r*   r+   r,   r   r   T  s'     JHcIsr+   r   c                  "    e Zd ZdZdddZddZy)r|   a%  
    A SpineLine is any horizontal line of a Humdrum file that
    contains one or more spine elements (separated by tabs)
    and not Global elements.

    Takes in a 1-based line number in the file and a string of contents.

    >>> hsl = humdrum.spineParser.SpineLine(
    ...         lineNumber=7, contents='C4\t!local comment\t*M[4/4]\t.\n')
    >>> hsl
    <music21.humdrum.spineParser.SpineLine line 7 (4 spines)>
    >>> hsl.lineNumber
    7
    >>> hsl.numSpines
    4
    >>> hsl.spineData
    ['C4', '!local comment', '*M[4/4]', '.']
    c                    || _         |j                         }t        j                  d|      }t	        |      | _        || _        || _        y )Nz	+)r   r^   r_   splitr>   r~   r   r   )r;   r   r   
returnLists       r,   r<   zSpineLine.__init__z  s>    $??$XXeX.
Z $.r+   c                <    d| j                    d| j                   dS )Nline z (z spines))r   r~   r?   s    r,   _reprInternalzSpineLine._reprInternal  s!    t'r$..)9BBr+   Nr   rv   r   r   r   r7   r   r   r   r7   r&   r'   r(   r)   r<   r   r*   r+   r,   r|   r|   g  s    $/Cr+   r|   c                  "    e Zd ZdZdddZddZy)rz   a  
    A GlobalReferenceLine is a type of HumdrumLine that contains
    information/metadata about the humdrum document.

    In humdrum it is represented by three exclamation points
    followed by non-whitespace followed by a colon.  Examples::

        !!!COM: Stravinsky, Igor Fyodorovich
        !!!CDT: 1882/6/17/-1971/4/6
        !!!ODT: 1911//-1913//; 1947//
        !!!OPT@@RUS: Vesna svyashchennaya
        !!!OPT@FRE: Le sacre du printemps

    The GlobalReferenceLine object takes two inputs::

        lineNumber   1-based line number in the humdrum file
        contents     string of contents

    And stores them as three attributes::

        lineNumber: as above
        code:       non-whitespace code (usually three letters)
        value:      its value

    >>> gr = humdrum.spineParser.GlobalReferenceLine(
    ...        lineNumber=20, contents='!!!COM: Stravinsky, Igor Fyodorovich\n')
    >>> gr
    <music21.humdrum.spineParser.GlobalReferenceLine COM: 'Stravinsky, Igor Fyodorovich'>
    >>> gr.lineNumber
    20
    >>> gr.code
    'COM'
    >>> gr.value
    'Stravinsky, Igor Fyodorovich'

    TODO: add parsing of three-digit Kern comment codes into fuller metadata
    TODO: parse ``@``/``@@`` language tags here (e.g. ``!!!OPT@@RUS:``, ``!!!OPT@FRE:``)
    and propagate language/isPrimary so that GlobalReference.updateMetadata
    can attach ``metadata.Text(value, language=...)`` instead of bare strings.
    c                   || _         t        j                  dd|      }	 |j                  dd      \  }}|j	                         }|t        d| d      	 || _        || _        || _	        y # t        $ r t        d| d      w xY w)N^!!!+rv   :r[   zSGlobalReferenceLine (!!!) found without a code listed; this is probably a problem!  )
r   r_   subr   stripr%   
IndexErrorr   r   r   )r;   r   r   	noExclaimr   r   s         r,   r<   zGlobalReferenceLine.__init__  s    $FF8R2		O%OOC3MT5KKME|& (NNVZWX(Z [ [  !	
  	O" $BBJ1$N O O	Os   6A- -Bc                8    | j                    d| j                  S )N: r   r   r?   s    r,   r   z!GlobalReferenceLine._reprInternal  s    ))Btzzn--r+   N)r   z!!! NUL: Noner   r   r   r*   r+   r,   rz   rz     s    'P ".r+   rz   c                  2    e Zd ZU dZdZded<   dd	dZd
dZy)r{   av  
    A GlobalCommentLine is a humdrum comment that pertains to all spines
    In humdrum it is represented by two exclamation points (and usually one space)

    The GlobalComment object takes two inputs and stores them as attributes::

        lineNumber (1-based line number in the humdrum file)
        contents   (string of contents)
        value      (contents minus !!)

    The constructor can be passed (lineNumber, contents); if contents begins with
    bangs, they are removed along with up to one space directly afterwards.

    >>> com1 = humdrum.spineParser.GlobalCommentLine(
    ...          lineNumber=4, contents='!! this comment is global')
    >>> com1
    <music21.humdrum.spineParser.GlobalCommentLine 'this comment is global'>
    >>> com1.lineNumber
    4
    >>> com1.contents
    '!! this comment is global'
    >>> com1.value
    'this comment is global'
    rv   r7   r   c                \    || _         t        j                  dd|      }|| _        || _        y )N^!!+\s?rv   )r   r_   r  r   r   )r;   r   r   r   s       r,   r<   zGlobalCommentLine.__init__  s)    $z2x0 
r+   c                ,    t        | j                        S r   )reprr   r?   s    r,   r   zGlobalCommentLine._reprInternal  s    DJJr+   Nr   r   r   )r&   r'   r(   r)   r   r   r<   r   r*   r+   r,   r{   r{     s    0 E3O r+   r{   c                  "    e Zd ZdZdddZddZy)rx   a*  
    A blank line in a humdrum source.  Humdrum forbids blank lines, but
    they appear in the wild.  Storing them as BlankLine objects keeps
    `eventList` aligned with the source: `eventList[lineNumber - 1]` is
    always the HumdrumLine at that 1-based source line.

    Treated as a global event by `parseProtoSpinesAndEventCollections`
    (no SpineEvent is created at this line for any spine).

    >>> b = humdrum.spineParser.BlankLine(lineNumber=12)
    >>> b
    <music21.humdrum.spineParser.BlankLine line 12>
    >>> b.lineNumber
    12
    c                     || _         d| _        y Nrv   )r   r   )r;   r   s     r,   r<   zBlankLine.__init__  s    $r+   c                     d| j                    S )Nr   r   r?   s    r,   r   zBlankLine._reprInternal  s    t'((r+   N)r   )r   r   r   r   r   r   r*   r+   r,   rx   rx     s    )r+   rx   c                  *    e Zd ZdZdddZddZd	dZy)
r   aS  
    A ProtoSpine is a collection of events arranged vertically.
    It differs from a HumdrumSpine in that spine paths are not followed.
    So ProtoSpine(1) would be everything in the 2nd column
    of a Humdrum file regardless of whether the 2nd column
    was at some point an independent Spine
    or if it later became a split from the first spine.

    See :meth:`~music21.humdrum.spineParser.parseProtoSpinesAndEventCollections`
    for more details on how ProtoSpine objects are created.

    * Changed in v10: ProtoSpines now iterate over their eventLists and are ProtoM21Objects.
    Nc                    |g }|| _         y r   )r1   )r;   r1   s     r,   r<   zProtoSpine.__init__  s    I09r+   c                ,    t        | j                        S r   iterr1   r?   s    r,   __iter__zProtoSpine.__iter__      DNN##r+   c                2    t        | j                         dS )Nz events)r>   r1   r?   s    r,   r   zProtoSpine._reprInternal  s    dnn%&g..r+   r   )r1   zlist[SpineEvent | None] | Noner   r   )r   zt.Iterator[SpineEvent | None]r   )r&   r'   r(   r)   r<   r  r   r*   r+   r,   r   r     s    :
$/r+   r   c                      e Zd ZdZej
                  ddej                  df	 	 	 	 	 	 	 	 	 dd       ZddZ	ddZ
ddZddZdd	Zdd
ZdddZ eee      ZddZddZy)HumdrumSpineaL  
    A HumdrumSpine is a representation of a generic HumdrumSpine
    regardless of \*\*definition after spine path indicators have
    been simplified.

    A subclass of HumdrumSpine should be defined for each \*\*type. Those
    subclasses cannot redefine `__init__()`

    A HumdrumSpine is a collection of events arranged vertically that have a
    connection to each other.
    Each HumdrumSpine MUST have an id (numeric or string) attached to it.

    >>> SE = humdrum.spineParser.SpineEvent
    >>> spineEvents = [SE('**kern'), SE('c,4'), SE('d#8')]
    >>> spine1Id = 5
    >>> spine1 = humdrum.spineParser.HumdrumSpine(spine1Id, spineEvents)
    >>> spine1.insertPoint = 5
    >>> spine1.endingPoint = 6
    >>> spine1.parentSpine = 3  # spine 3 is the previous spine leading to this one
    >>> spine1.childSpines = [7, 8]  # the spine ends by being split into spines 7 and 8

    A spine knows the SpineCollection it belongs to:

    >>> spineCollection1 = humdrum.spineParser.SpineCollection()
    >>> spine1.parentSpineCollection = spineCollection1

    The spineType property searches the EventList or parentSpine to
    figure out the spineType.

    >>> spine1.spineType
    'kern'

    Spines can be iterated through:

    >>> for e in spine1:
    ...    print(e)
    **kern
    c,4
    d#8

    If you'd eventually like this spine to be converted to a class
    other than :class:`~music21.stream.Stream`, pass its classname in
    as the streamClass argument:

    >>> spine2 = humdrum.spineParser.HumdrumSpine(streamClass=stream.Part)
    >>> spine2.stream
    <music21.stream.Part ...>
    r   Nc                *   || _         |g }|D ]	  }||_         || _         |       | _        d| _        d| _        d | _        d | _        d| _        g | _	        i | _
        d| _        d| _        d| _        |
t               }|| _        d| _        d| _        y )Nr   Frv   )rQ   spineIdr1   r   r   r   rR   newSpineisLastSpiner   r   parsedmeasuresMovedinsertionsDoner   parentSpineCollection
_spineTyper   )r;   r  r1   r   r#  r   s         r,   r<   zHumdrumSpine.__init__P  s     IE#EM  ,5%0] ! !.2+/!&/1KM#!#($) ( %4$5!6K"!"'r+   c                "   dt        | j                        z   }| j                  r(|dt        | j                  j                        z   dz   z  }| j                  r6|dz  }| j                  D ]  }|t        |j                        dz   z  } |dz  }|S )Nr  z [child of: r   z [parent of: r  z ])r7   rQ   rR   r   )r;   representationr   s      r,   r   zHumdrumSpine._reprInternalu  s    DGG,ns43C3C3F3F/GG#MMNo-N%%#add)c/1 &d"Nr+   c                :    | j                   j                  |       y)z+
        add an item to this Spine
        N)r1   ra   )r;   r   s     r,   ra   zHumdrumSpine.append  s     	e$r+   c                ,    t        | j                        S r   r  r?   s    r,   r  zHumdrumSpine.__iter__  r  r+   c                    | j                   r| j                   S | j                  D ]H  }t        j                  d|j                        }|s&|j                  d      | _         | j                   c S  y)Nz\*\*(.*)r[   rv   )r$  r1   r_   ry   r   group)r;   r   m1s      r,   _getLocalSpineTypezHumdrumSpine._getLocalSpineType  sX    ????"I+y'9'9:B"$((1+&	 (
 r+   c                8    | j                   }|y|j                  S r  )rR   rS   )r;   rR   s     r,   _getParentSpineTypez HumdrumSpine._getParentSpineType  s"    &&$$$r+   c                    | j                   r| j                   S | j                         }|r	|| _         |S | j                         }|r	|| _         |S t        dt	        | j
                        z         )zH
        searches the current and parent spineType for a search
        z0Could not determine spineType for spine with id )r$  r,  r.  r%   r7   rQ   )r;   sts     r,   _getSpineTypezHumdrumSpine._getSpineType  st     ????"$$& DOI%%' DOI  68;DGG E F 	Fr+   c                    || _         y r   )r$  )r;   newSpineTypes     r,   _setSpineTypezHumdrumSpine._setSpineType  s	    &r+   c                X   |j                         }t        j                         }d|_        d}d}d}|D ]  }t	        |t        j                        rK|dk7  s|r!|j                          |j                  |       |}|j                  }|j                  }|dk(  sed}h|dk7  s|j                  j                  dk7  r |j                  |j                  |z
  |       |j                  |        |j                          |j                          |r|j                  |       |j                  t        j                        }|r|d   }	|sd|	_        |j                  d      }
|
D ]O  }t	        |t        j                        rd|j                  v r-|	j!                  d|       |j#                  |       Q |	j$                  }|h|	j                  j                  |j&                  j                  k  r;t)        |j&                  j                  |	j                  j                  z
        |	_        |S )a  
        Takes a parsed stream and moves the elements inside the
        measures.  Works with pickup measures, etc. Does not
        automatically create ties, etc.

        Why not just use Stream.makeMeasures()? because
        humdrum measures contain extra information about barlines
        etc. and pickups are explicitly defined.

        >>> s1 = stream.Stream()
        >>> s1.append(meter.TimeSignature('2/4'))
        >>> m1 = stream.Measure()
        >>> m1.number = 1
        >>> s1.append(m1)
        >>> s1.append(note.Note('C4', type='quarter'))
        >>> m2 = stream.Measure()
        >>> m2.number = 2
        >>> s1.append(m2)
        >>> s1.append(note.Note('D4', type='half'))
        >>> s1.show('text')
        {0.0} <music21.stream.Measure 1 offset=0.0>
        <BLANKLINE>
        {0.0} <music21.meter.TimeSignature 2/4>
        {0.0} <music21.note.Note C>
        {1.0} <music21.stream.Measure 2 offset=1.0>
        <BLANKLINE>
        {1.0} <music21.note.Note D>

        >>> hds = humdrum.spineParser.HumdrumSpine()
        >>> s2 = hds.moveElementsIntoMeasures(s1)
        >>> s2.show('text')
        {0.0} <music21.stream.Measure 1 offset=0.0>
            {0.0} <music21.meter.TimeSignature 2/4>
            {0.0} <music21.note.Note C>
        {1.0} <music21.stream.Measure 2 offset=1.0>
            {0.0} <music21.note.Note D>

        The first measure is correctly identified as a pickup!

        >>> s2.measure(1).paddingLeft
        1.0
        r           Fr[   T
MiscTandem)r   r   Measurerm   r6   r   r   r   r   quarterLengthr   ra   getElementsByClassgetElementsByOffsetStreamclassesrT   r   timeSignaturebarDurationr   paddingLeft)r;   streamIn	streamOutcurrentMeasurecurrentMeasureNumbercurrentMeasureOffsethasMeasureOner   measureElementsr+  beginningStuffm1TimeSignatures               r,   moveElementsIntoMeasuresz%HumdrumSpine.moveElementsIntoMeasures  s   X &&(	) ! ),B"fnn-'1,"668((8!#')yy$')yy$'1,$(M'1,0I0IQ0N"--bii:N.NPRS ((,# & 	**,%%'^, $66v~~F #B 	&::1=N$b&--0!RZZ/IIa$$$R( % !..O*;;,,/J/J/X/XX%+O,G,G,U,U.0kk.G.G-H &IBN r+   c                   | j                   j                  }t        d      }| j                  D ]  }t	        |j
                        }d}|dk(  rnw|j                  d      r|t        vr^t        |      }nR|j                  d      rt        ||      }|}n2|j                  d      rt        |      }nt        j                  |      }||j                  ||<   | j                  j                  |        | j                  j                          y)z
        Dummy method that pushes all these objects to HumdrumSpine.stream
        as ElementWrappers.  Should be overridden in
        specific Spine subclasses.
        =0Nr   r#   =!)r#  humdrumLineNumbershdStringToMeasurer1   r7   r   
startswithr   r7  SpineCommentr   ElementWrapperr   r   r   r   )r;   rO  lastContainerr   eventC
thisObjects         r,   rH   zHumdrumSpine.parse  s     "77JJ)$/^^E(F26J}""3'!44!+F!3J""3' 1&- H*
""3')&1
!007
%161A1A":.&&z2' $( 	'')r+   )
r  r   r1   zlist[SpineEvent] | Noner   type[stream.Stream]r#  zSpineCollection | Noner   r   r   )r   r   r   r   )r   zt.Iterator[SpineEvent]rv   )r3  r7   r   r   )rA  stream.Streamr   rY  r   )r&   r'   r(   r)   tfinalr   r<  r<   r   ra   r  r,  r.  r1  r4  r   rS   rJ  rH   r*   r+   r,   r  r    s    /` WW +/+1==6:"("( )"( )	"(
  4"( 
"( "(H	%$%F"' 6I_B*r+   r  c                  v    e Zd ZU dZded<   ded<   ded<   ded	<   d
ed<   d
ed<   ddZddZddZddZddZ	y)	KernSpinea  
    A KernSpine is a type of humdrum spine with the \*\*kern
    attribute set and thus events are processed as if they
    are kern notes.

    Instances are not constructed directly; `reclassSpines` reassigns
    `__class__` from `HumdrumSpine` to `KernSpine` once the spine's
    exclusive interpretation is known.  All KernSpine-specific state
    is initialized at the top of `parse()`.

    * Changed in v10: `currentTupletDuration` / `desiredTupletDuration`
        renamed to `currentTupletQL` / `desiredTupletQL`.
    stream.Measure | NonerT  boolinTupletznote.GeneralNote | NonelastNoter   currentBeamNumbersr   currentTupletQLdesiredTupletQLc                   | j                   j                  }t        d      | _        d| _        d | _        d| _        d| _        d| _        | j                  D ]  }	 |j                  }d }|dk(  rn|j                  d      rt        |      }||}n|j                  d      r(t        || j                        | _        | j                  }nU|j                  d      rt        |      }|j                  d	k7  r*|}n'd
|v r| j                  |      }n| j!                  |      }|;|j"                  ||<   |j"                  |_        | j&                  j)                  |        | j&                  j9                          y # t*        $ rv}dd l}t.        j1                  d|j                  d|j"                   d|j2                   d|        |j5                         }	t.        j7                  d|	        Y d }~d }~ww xY w)NrL  Fr   r6  r   r#   rM  rN  rv   r  zError in parsing event (z
) at line z for spine r  zTraceback for the exception: 
)r#  rO  rP  rT  r`  ra  rb  rc  rd  r1   r   rQ  kernTandemToObjectrR  commentprocessChordEventprocessNoteEventr   r   r   r   	Exception	tracebackenvironLocalwarnr  
format_exc
printDebugr   )
r;   rO  r   rU  rV  
tempObjectspineCommentObjerk  tbs
             r,   rH   zKernSpine.parseF  s   !77JJ.t4"#""^^E%P6:
S=&&s+!3F!;J!-%/
&&s+):64CUCU)VD&!%!3!3J&&s+&26&:O&.."4%4
F]!%!7!7!?J!%!6!6v!>J)5:5E5E&z2 +0*:*:J'KK**:6= $T 	'')  P !!.u~~.@ A$//0 1!!&r!6
 ))+''*I"(NOOPs   D E99	G8A+G33G8c                n    t        |      }| j                  |       | j                  |       || _        |S )z
        similar to hdStringToNote, this method processes a string representing a single
        note, but stores information about current beam and tuplet state.
        )hdStringToNotesetBeamsForNotesetTupletTypeForNotera  )r;   rU  	eventNotes      r,   ri  zKernSpine.processNoteEvent|  s7    
 #6*	Y'!!),!r+   c                h   |j                         }g }|D ]9  }t        |      }t        |t        j                        s)|j                  |       ; t        j                  ||d   j                        }|d   j                  |_	        | j                  |       | j                  |       || _        |S )z
        Process a single chord event

        Like processNoteEvent, stores information about current beam and tuplet state.
        rZ   )beamsr   )r   ru  r6   r   Notera   r	   Chordrz  r   rv  rw  ra  )r;   rU  notesToProcess
chordNotesnoteToProcessthisNote
eventChords          r,   rh  zKernSpine.processChordEvent  s      &(
+M%m4H(DII.!!(+ , [[:b>3G3GH
(m44
Z(!!*-"r+   c                   t        |d      sy| j                  dk7  rL|j                  j                  s6t	        | j                        D ]  }|j                  j                  d        y|j                  j                  ro|j                  j                  d   j                  dk(  rd| _        y|j                  j                  D ]'  }|j                  dk7  s| xj                  dz  c_        ) yy)z
        sets the beams for a Note (or Chord) given self.currentBeamNumbers
        and updates self.currentBeamNumbers based on stop beams.

        Safe enough to use on elements such as rests that don't have beam info.
        rz  Nr   continuestopr[   )hasattrrb  rz  	beamsListrb   ra   type)r;   nunused_counterthisBeams       r,   rv  zKernSpine.setBeamsForNote  s     q'"""a'0A0A"'(?(?"@z* #AWWww  #((F2*+' ! 1 1H}}.//14/ !2	 r+   c                   |j                   }|j                   j                  }| j                  sQ|rOd| _        |d   j                         | _        |j
                  | _        d|j                   j                  d   _        y | j                  rM|sKd| _        d| _        d| _        | j                  )d| j                  j                   j                  d   _        y y | j                  r~t        | j                  |j
                  z         | _        | j                  | j                  k\  r=| j                  | j                  z  dk(  r d|d   _        d| _        d| _        d| _        y y y y )NTr   startFr6  r  )
r   tupletsr`  totalTupletLengthrd  r9  rc  r  ra  r   )r;   r  nDurnTupletss       r,   rw  zKernSpine.setTupletTypeForNote  s7   zz::%%}} DM#+A;#@#@#BD #'#5#5D )0AJJq!&]]8!DM#&D #&D }}(9?&&..q16 )]]#)$*>*>ASAS*S#TD  $$(<(<<,,t/C/CCqH#)  %'*$'*$	 I = r+   Nr   )rU  r7   r   note.GeneralNote)rU  r7   r   zchord.Chord)r  r  r   r   )
r&   r'   r(   r)   r   rH   ri  rh  rv  rw  r*   r+   r,   r]  r]  0  sF     '&N##3*l,5*+r+   r]  c                      e Zd ZdZddZy)
DynamSpinez
    A DynamSpine is a type of humdrum spine with the \*\*dynam
    attribute set and thus events are processed as if they
    are dynamics.
    c                   | j                   j                  }d }| j                  D ]X  }|j                  }d }|dk(  rn|j	                  d      r|t
        vrt        |      }n|j	                  d      r9|+|j                          | j                  j                  |       t        |      }n|j	                  d      rt        |      }|j                  dk7  rd|}na|j	                  d      rt        j                         }n;|j	                  d      rt        j                         }nt        j                   |      }||j"                  ||<   || j                  j                  |       H|j                  |       [ |+|j                          | j                  j                  |       | j                  j                          y )Nr   r#   rM  rN  rv   <>)r#  rO  r1   r   rQ  r   r7  r   r   r   rP  rR  rg  r   
Diminuendo	CrescendoDynamicr   )r;   rO  thisContainerr   rU  rV  rq  s          r,   rH   zDynamSpine.parse  s   !77JJ-1^^E^^F26J}""3'!44!+F!3J""3' ,!557KK**=9 1& 9""3'".v"6"**b0!0J""3'%002
""3'%//1
%--f5
%161A1A":. (KK**:6!,,Z8? $D $--/KK""=1'')r+   Nr   r&   r'   r(   r)   rH   r*   r+   r,   r  r    s    
(*r+   r  c                      e Zd ZdZddZy)	HarmSpinea  
    A HarmSpine is a type of humdrum spine with the \*\*harm
    attribute set and thus events are processed as if they
    are harmonic analysis annotations in the "harm" syntax.

    The harm roman numeral annotations are parsed using
    a superset of the original \*\*harm Humdrum representation, written
    for python and extending the syntax based on other projects like the
    RomanText and the MuseScore roman numeral notations.
    c                f   | j                   j                  }t        d      }t        j                  d      }| j
                  D ]Q  }|j                  }d }|dk(  rn|j                  d      rC|t        v r2|j                  d      r|dd }t        j                  |      }|}nt        |      }n|j                  d      rt        ||      }|}n|j                  d	      rt        |      }nj|j                  }t        j                  |      }	t        j                  |	|t        j                   j"                  t        j                   j$                  
      }||j&                  ||<   |j&                  |_        | j*                  j-                  |       T | j*                  j/                          y )NrL  Cr   r#   r   r[   rZ   rM  rN  )
sixthMinorseventhMinor)r#  rO  rP  r   Keyr1   r   rQ  r   endswithr7  rR  r   convertHarmToRomanr   RomanNumeralMinor67DefaultFLATSHARPr   r   r   r   r   )
r;   rO  rT  
currentKeyr   rU  rV  	keyStringharmStrromanStrs
             r,   rH   zHarmSpine.parse  sr   !77JJ)$/WWS\
^^E^^F26J}""3'00??3' &qI!$!3J!+J ",F!3J""3' 1&- H*
""3')&1
..%88A"//$3388!&!5!5!;!;	
 %161A1A":.&+&6&6
#&&z2E $F 	'')r+   Nr   r  r*   r+   r,   r  r    s    	'*r+   r  c                  4    e Zd ZdZdddZd	dZd	dZd
ddZy)r   a  
    A SpineEvent is an event in a HumdrumSpine or ProtoSpine.

    It's .contents property contains the contents of the spine, or
    it could be '.', in which case it means that a
    particular event appears after the last event in a different spine.
    It could also be "None" indicating that there is no event at all
    at this moment in the humdrum file.  Happens if no ProtoSpine exists
    at this point in the file in this tab position.

    Should be initialized with its contents and 1-based source line number.

    These attributes are optional but likely to be very helpful::

        lineNumber -- 1-based source line number in the humdrum file
        protoSpineId -- ProtoSpine id (0 to N)
        spineId -- id of HumdrumSpine actually attached to (after SpinePaths are parsed)

    The `toNote()` method converts the contents into a music21 note as
    if it's kern -- useful to have in all spine types.

    >>> se1 = humdrum.spineParser.SpineEvent('EEE-8')
    >>> se1.lineNumber = 40
    >>> se1.contents
    'EEE-8'
    >>> se1
    <music21.humdrum.spineParser.SpineEvent EEE-8>
    >>> n = se1.toNote()
    >>> n
    <music21.note.Note E->
    c                <    || _         || _        d| _        d | _        y r0   )r   r   r   r  )r;   r   r   s      r,   r<   zSpineEvent.__init__Y  s    %)!"!%r+   c                    | j                   S r   r   r?   s    r,   r   zSpineEvent._reprInternal_      }}r+   c                    | j                   S r   r  r?   s    r,   __str__zSpineEvent.__str__b  r  r+   Nc                F    |t        | j                        S t        |      S )aP  
        parse the object as a \*\*kern note and return a
        :class:`~music21.note.Note` object (or Rest, or Chord)

        >>> se = humdrum.spineParser.SpineEvent('DD#4')
        >>> n = se.toNote()
        >>> n
        <music21.note.Note D#>
        >>> n.octave
        2
        >>> n.duration.type
        'quarter'
        )ru  r   )r;   convertStrings     r,   toNotezSpineEvent.toNotee  s$      !$--00!-00r+   )rv   r   )r   r7   r   r   r   r   r   r   )r  
str | Noner   r  )r&   r'   r(   r)   r<   r   r  r  r*   r+   r,   r   r   9  s    >&1r+   r   c                      e Zd ZdZddZddZej                  fddZddZ	ddZ
ddZddZdd	Zdd
Z	 	 	 	 	 	 	 	 ddZddZ	 	 ddZddZddZddZddZy)r   a  
    A SpineCollection is a set of HumdrumSpines with relationships to each
    other and where their position attributes indicate
    simultaneous onsets.

    When you iterate over a SpineCollection, it goes from right to
    left, since that's the order that humdrum expects.
    c                n    g | _         d| _        d| _        d | _        t	        j
                         | _        y )Nr   F)spines
nextFreeIdspineReclassDoner  weakrefWeakKeyDictionaryrO  r?   s    r,   r<   zSpineCollection.__init__  s5    *, &++/ %%' 	r+   c                ,    t        | j                        S )zK
        Iterates spines right-to-left, the order humdrum expects.
        )reversedr  r?   s    r,   r  zSpineCollection.__iter__  s     $$r+   c                    t        | j                  ||       | _        | j                  j	                  | j                         | xj                  dz  c_        | j                  S )a  
        creates a new spine in the collection and returns it.

        By default, the underlying music21 class of the spine is
        :class:`~music21.stream.Part`.  This can be overridden
        by passing in a different streamClass.

        Automatically sets the id of the Spine.

        >>> hsc = humdrum.spineParser.SpineCollection()
        >>> newSpine = hsc.addSpine()
        >>> newSpine.id
        0
        >>> newSpine.stream
        <music21.stream.Part ...>
        >>> newSpine2 = hsc.addSpine(streamClass=stream.Stream)
        >>> newSpine2.id
        1
        >>> newSpine2
        <music21.humdrum.spineParser.HumdrumSpine: 1>
        >>> newSpine2.stream
        <music21.stream.Stream ...>
        )r   r#  r[   )r  r  r  r  ra   )r;   r   s     r,   r   zSpineCollection.addSpine  sM    0 %OO#"&

 	4==)1}}r+   c                :    | j                   j                  |       y)z~
        appendSpine(spine) -- appends an already existing HumdrumSpine
        to the SpineCollection.  Returns void
        N)r  ra   )r;   spines     r,   appendSpinezSpineCollection.appendSpine  s    
 	5!r+   c                `    | j                   D ]  }|j                  |k(  s|c S  t        d      )z
        returns the HumdrumSpine with the given id.

        raises a HumdrumException if the spine with a given id is not found
        z#Could not find a Spine with that ID)r  rQ   r%   )r;   r  rW   s      r,   getSpineByIdzSpineCollection.getSpineById  s2     I||w&   % DEEr+   c                    | j                   D ].  }|j                  |k(  s| j                   j                  |        y t        dt               )az  
        Deletes a spine from the SpineCollection (after inserting, integrating, etc.)

        >>> hsc = humdrum.spineParser.SpineCollection()
        >>> newSpine = hsc.addSpine()
        >>> newSpine.id
        0
        >>> newSpine2 = hsc.addSpine()
        >>> newSpine2.id
        1
        >>> hsc.spines
        [<music21.humdrum.spineParser.HumdrumSpine: 0>,
         <music21.humdrum.spineParser.HumdrumSpine: 1>]
        >>> hsc.removeSpineById(newSpine.id)
        >>> hsc.spines
        [<music21.humdrum.spineParser.HumdrumSpine: 1>]

        raises a HumdrumException if the spine with a given id is not found
        Nz$Could not find a Spine with that ID )r  rQ   r   r%   )r;   r  r   s      r,   removeSpineByIdzSpineCollection.removeSpineById  sG    ( Attw""1%  !EbTJKKr+   c                    | j                          | j                          | j                          | j                          | j	                          | j                          | j                          y)aC  
        Create Music21 Stream objects from spineCollections by running:

            self.reclassSpines()
            self.parseMusic21()
            self.performInsertions()
            self.moveObjectsToMeasures()
            self.attachNonKernEvents()
            self.makeVoices()
            self.assignIds()
        N)reclassSpinesparseMusic21performInsertionsmoveObjectsToMeasuresattachNonKernEvents
makeVoices	assignIdsr?   s    r,   rO   z$SpineCollection.createMusic21Streams  sT     	 ""$  "r+   c                   ddi}i }| j                   D ]  }|j                  }|j                  t        j                        }|sd}n|d   j
                  }||vr|||<   d||<   |S||_        [|!|dxx   dz  cc<   t        |d         |_        ~||   dk(  r"||   }t        |j                        dz   |_        ||xx   dz  cc<   |dz   t        ||         z   |_         y)a  
        Assign an ID based on the instrument, or just a string of a number
        if there is no instrument.

        >>> hsc = humdrum.spineParser.SpineCollection()
        >>> newSpineDefault = hsc.addSpine()
        >>> newSpineDefault2 = hsc.addSpine()
        >>> newSpineOboe1 = hsc.addSpine()
        >>> newSpineOboe2 = hsc.addSpine()
        >>> newSpineTrumpet = hsc.addSpine()
        >>> newSpineOboe1.stream.append(instrument.Oboe())
        >>> newSpineOboe2.stream.append(instrument.Oboe())
        >>> newSpineTrumpet.stream.append(instrument.Trumpet())
        >>> hsc.assignIds()
        >>> for sp in hsc.spines:
        ...     print(sp.stream.id)
        1
        2
        Oboe-1
        Oboe-2
        Trumpet
        Nr   r[   z-1-)r  r   r:  r   
InstrumentinstrumentNamerQ   r7   )r;   usedIdsfirstStreamForEachInstrumentrW   spineStreaminstrumentsStreamspineInstrumentmyFirstStreams           r,   r  zSpineCollection.assignIds  s   . )-ayFH$I#**K + > >z?T?T U$"&"3A"6"E"Eg-@K,_=+,(".%4KN ("!$WT]!3?+q0$@$QM'*=+;+;'<t'CM$(A-(!03!6W_=U9V!V+ %r+   c                *   | j                   D ]  }|j                  |j                  s|j                  j	                         }t        |j                        }d}|j                  D ]u  }| j                  j                  |      }|E|D ]1  }||kD  s||k  r| j                  |||       |j                  |       3 |}| j                  |= |j                  |       w |j                          ||_        |D ]  }| j                  |||         y)z
        Take a parsed spineCollection as Music21Objects and take
        sub-spines and put them in their proper location.
        NrZ   )r  rR   r   r   r   sortedr   rO  getperformSpineInsertionr   r   r   )r;   rW   	newStreaminsertPointslastLineNumberr   r   re   s           r,   r  z!SpineCollection.performInsertions%  s   
 I$$0(( "((224I!)"B"BCLN&&!4488<
)))A-a$229iK$++A. * &0N//3$$R( ' ))+(I
 "**9iC "= %r+   c                   |j                          |j                  }|j                  |   }d}|D ]  }|dz  }dt        |      z   }|j                  D ]c  }	|j
                  st        |	t        j                        r*|	j                  j                  |       |j                  ||	j                  z   |	       e  |j                          y)zx
        Insert all the spines into newStream that should be
        inserted into thisSpine at insertionPoint.
        r   r[   voiceN)r   highestTimer   r7   r   r   r6   r8  groupsra   r   r   )
r;   rW   r  insertionPoint
startPointchildrenToInsertvoiceNumberinsertSpinevoiceStrinsertEls
             r,   r  z%SpineCollection.performSpineInsertionN  s     	%%'**
$;;NK+K1K[!11H'.."//Jx4XOO**84((hoo)ExP /	 , 	%%'r+   c                    | j                   D ]S  }|j                  dk(  rt        |_        |j                  dk(  rt        |_        9|j                  dk(  sIt
        |_        U d| _        y)z
        Changes the classes of HumdrumSpines to more specific types
        (KernSpine, DynamicSpine)
        according to their spineType (e.g., \*\*kern, \*\*dynam)
        rK   dynamharmTN)r  rS   r]  r   r  r  r  r;   rW   s     r,   r  zSpineCollection.reclassSpinesi  s^     I""f,&/	#$$/&0	#$$.&/	# % !%r+   c                   i }| j                   D ]z  }|j                  |j                  j                         D ]N  }| j                  j                  |      }|!||vr|j                  |gf||<   8||   d   j                  |       P | |S )a$  
        Iterates through the spines by location
        and records the offset and priority for each element in the spines.

        Returns a dictionary keyed by humdrum line number whose values are
        two-element tuples: (music21 offset, list of Music21Objects at that line).
        r[   )r  rR   r   flattenrO  r  r   ra   )r;   r   rW   r   poss        r,   r   z3SpineCollection.getOffsetsAndPrioritiesByLineNumberx  s     PRI$$,#**224B1155b9C{ .0/1yy2$.?s+&s+A.55b9 5 % r+   c                   t        j                         }| j                  D ]  }|j                  |j	                  |j
                        |_        |j
                  j                  t
        j                        D ]=  }|j                  |       |j                  d      }|D ]  }|j                  |        ? d|_         y)z
        run moveElementsIntoMeasures for each HumdrumSpine
        that is not a sub-spine.

        Also fixes up the tuplets using duration.TupletFixer
        NT)incorporateGroupings)r   TupletFixerr  rR   rJ  r   r:  r8  	setStreamfindTupletGroupsfixBrokenTupletDurationr!  )r;   tfrW   mtupletGroupstgs         r,   r  z%SpineCollection.moveObjectsToMeasures  s     !!#I$$,#,#E#EiFVFV#W	  #))<<V^^LALLO#%#6#6D#6#QL*2226 + M +/	' %r+   c           	        i }| j                   D ]  }|j                  |j                  dk7  r |j                  j	                  t
              D ]F  }|j                  j                  d      st        |j                  dd       }|j                  ||<      | j                   D ]  }|j                  |j                  dk(  r!g }i }|j                  t
           D ]U  }|j                  j                  d      s|j                  dd }|j                  d      D cg c]  }t        |       }} n |j                  dk(  r|j                  t        j                     D ]%  }	| j                  j                  |	      }
|
!|	||
<   ' |D ]_  }||   }|j                         D ]E  }|j                  |vr	 |j                   j#                  |j$                  ||j                            G a J|j                  dk(  r|j                  t*        j,                     D ]%  }| j                  j                  |      }|!|||<   ' |D ]_  }||   }|j                         D ]E  }|j                  |vr	 |j                   j#                  |j$                  ||j                            G a |j                  dv s|j                  t.        j0                     D ]/  }| j                  j                  |      }|!|j2                  ||<   1 |D ]  }||   }d	}|j                         j	                  t4        j6                        D ]6  }|j                  |v s||j                     }|j8                  |_        |d
z  }8 |rs|svt<        j?                  d| d|j@                   d         yc c}w # t&        j(                  $ r Y $w xY w# t&        j(                  $ r Y w xY w)a  
        move :samp:`**dynam` and :samp:`**lyrics/**text` information to the appropriate staff.

        Assumes that :samp:`*staff` is consistent through the spine.

        TODO: misaligned events (a `**dynam` or `**harm` whose source line has '.'
        in the kern column) are silently dropped because the matcher only accepts
        exact :samp:`el.priority == event.lineNumber`.  Desired: when no kern note
        sits on the same line, attach to the stream at the offset of the most
        recently-sounding kern note (ideal: between current and next note's
        offsets).  Lyrics/text continue to attach to notes only.
        See `humdrum.tests.Test.testDynamAttachedMisaligned` /
        `testHarmAttachedMisaligned`.
        NrK   z*staff   /r  r  )lyricstextr   r[   zNo notes/rests on staff z* matched any lyric/text events from spine r   )!r  rR   rS   r   r:  r7  tandemrQ  r   r   r   r  rO  r  r   r   
activeSiterT   r   r   StreamExceptionr   r  r   rS  objr   GeneralNoter   lyricrl  rm  rQ   )r;   kernStreamsrW   r  	staffInfostavesAppliedToprioritiesToSearchstaffInfoStrxdynamic
dynamicPos
applyStaffapplyStreamr   r  harmPoswrapper
wrapperPosmatchedwrappedEvents                       r,   r  z#SpineCollection.attachNonKernEvents  s    13I$$0""f,#**==jI}}//9ab 12	)2)9)9I& J % I$$0""f,)+O@B#**:6==++H5#)==#4L7C7I7I#7N&O7N!s1v7NO&O	 7
 ""g-(//0@0@AG!%!8!8!<!<W!EJ!-9@*:6  B #2J"-j"9K)113;;.@@$!MM001CBKK1PR	 4 #2 $$.%,,U-?-?@D"5599$?G*6:*73 A #2J"-j"9K)113;;.@@$!MM001CBKK1PR	 4 #2 $$(::(//0C0CDG!%!8!8!<!<W!EJ!-9@*:6  E #2J"-j"9KG)113FFtGWGWX;;*<<+=bkk+JL'3'<'<BH#qLG	 Y
 #'9$))6zl C<<ELL>LM #2m % 'P  ,;; ! !$  ,;; ! !s*   N,63N103O1O	O	O"	!O"	c                d   | j                   D ]  }|j                  dk7  s|j                   |j                  }|j	                  t        j
                        D ]M  }d}d}|D ]   }d|j                  v sd}|j                  } n |s0t        d      D cg c]  }d }}|j                  }	|	D ]  }|j                  }
|
r|
d   j                  d      s&|
d   }t        |d	         }||   }|4t        j                         }|||<   |j                  j                  |       t        j                  r|J |j                  }|j!                  |       |j#                  ||z
  |        |D ]'  }||j%                          |j#                  ||       ) |j%                          P  yc c}w )
z
        make voices for each kernSpine -- why not just run
        stream.makeVoices() ? because we have more information
        here that lets us make voices more intelligently

        Should be done after measures have been made.
        rK   NFr   voice1T
   r     )r  rS   rR   r   r:  r8  r  r   rb   elementsrQ  r   r   ra   rZ  TYPE_CHECKINGr   r   r   )r;   rW   
thisStreamr   	hasVoiceslowestVoiceOffsetmElre   voicesrG  	mElGroups	voiceNamer  	voicePart	mElOffsets                  r,   r  zSpineCollection.makeVoices  s    I""f,	0E0E0Q"))J 33FNNC!	$%!C3::-$(	,/JJ)	 
 !AFr2KA42K"$++*C #

I$IaL,C,CG,L  )!I"%il"3K &{ 3I ($*LLN	.7{+!((//	:(444 #

IIIcN((5F)FL% +( "(I ,!557&7C	 "(
 &&(M D	 % 3Ls   	F-c                F    | j                   D ]  }|j                           y)zl
        runs spine.parse() for each Spine.
        thus populating the spine.stream for each Spine
        N)r  rH   r  s     r,   r  zSpineCollection.parseMusic219  s    
 IOO %r+   Nr   )r   zt.Iterator[HumdrumSpine])r   rW  r   r  )r  r  r   r   )r  r   r   r  )r  r   r   r   )rW   r  r  rY  r  r   r   r   )r   z4dict[int, tuple[OffsetQL, list[base.Music21Object]]])r&   r'   r(   r)   r<   r  r   r   r   r  r  r  rO   r  r  r  r  r   r  r  r  r  r*   r+   r,   r   r   {  s    
% ;A++ B"	FL4(.W`$DR(( !( 	(
 
(6%	=./,]M~2)jr+   r   c                  R    e Zd ZdZdddZddZddZddZddZddZ	ddZ
dd	Zy
)r   a6  
    An EventCollection holds every event that appears on a single source line
    of a humdrum file -- one cell per spine, in their `events` array.

    If a spine's cell on this line is '.' or a comment (no new event), use
    `lastEvents[spineNum]` to retrieve the previous event still sounding.
    `getSpineOccurring` returns either the current event or the last event
    that's still active.

    Theses events should happen at the same time (offset)
    but they are not necessarily the only events to happen at that same time.
    E.g. a clef change and the note that follows it on the next line take place at
    the same musical time but live in different EventCollections.

    These objects normally get created by
    :meth:`~music21.humdrum.spineParser.HumdrumDataCollection.parseProtoSpinesAndEventCollections`
    so you won't need to do all the setup.

    Assume that ec1 is

        C4     pp

    on source line 4, and ec2 is

        D4     .

    on source line 5:

    >>> SE = humdrum.spineParser.SpineEvent
    >>> eventList1 = [SE('C4', lineNumber=4), SE('pp', lineNumber=4)]
    >>> eventList2 = [SE('D4', lineNumber=5), SE('.', lineNumber=5)]
    >>> ec1 = humdrum.spineParser.EventCollection(maxSpines=2, lineNumber=4)
    >>> ec1.events = eventList1
    >>> ec2 = humdrum.spineParser.EventCollection(maxSpines=2, lineNumber=5)
    >>> ec2.events = eventList2
    >>> ec2.lastEvents[1] = eventList1[1]
    >>> ec2.maxSpines
    2
    >>> ec2.lineNumber
    5
    >>> ec2.getAllOccurring()
    [<music21.humdrum.spineParser.SpineEvent D4>, <music21.humdrum.spineParser.SpineEvent pp>]

    If there were spine path markers this next boolean would be true:

    >>> ec2.spinePathData
    False

    In the future, EventCollection may enforce that all events have the same lineNumber

    * New in v10: lineNumber.
    c                    t        j                  d       | _        t        j                  d       | _        || _        || _        d| _        y )Nc                      y r   r*   r*   r+   r,   r   z*EventCollection.__init__.<locals>.<lambda>z  s    Tr+   c                      y r   r*   r*   r+   r,   r   z*EventCollection.__init__.<locals>.<lambda>{  s    r+   F)r   r   r   
lastEventsr2   r   r   )r;   r2   r   s      r,   r<   zEventCollection.__init__y  s<    *0*<*<\*J.4.@.@.N')#(r+   c                h    d| j                    dt        | j                         d| j                   dS )Nr   z, z	 events, z spines)r   r>   r   r2   r?   s    r,   r   zEventCollection._reprInternal  s2    t'r#dkk*:);9T^^DTT[\\r+   c                "    || j                   |<   y r   r   r;   spineNum
spineEvents      r,   r   zEventCollection.addSpineEvent  s     *Hr+   c                "    || j                   |<   y r   )r,  r0  s      r,   r   z!EventCollection.addLastSpineEvent  s    $.!r+   c                V    t        | j                        D ]  }|| j                  |<    y r   )rb   r2   r   )r;   globalEventre   s      r,   r   zEventCollection.addGlobalEvent  s"    t~~&A(DKKN 'r+   c                     | j                   |   S r   r/  r;   r1  s     r,   getSpineEventzEventCollection.getSpineEvent  s    {{8$$r+   c                \    | j                   |   | j                   |   S | j                  |   S r   )r,  r   r7  s     r,   r   z!EventCollection.getSpineOccurring  s1     ??8$0??8,,;;x((r+   c                ~    g }t        | j                        D ]"  }|j                  | j                  |             $ |S r   )rb   r2   ra   r   )r;   	retEventsre   s      r,   getAllOccurringzEventCollection.getAllOccurring  s9    +-	t~~&AT33A67 'r+   N)r   r   )r2   r   r   r   r   r   r   )r1  r   r2  r   r   r   )r5  r   r   r   )r1  r   r   r   )r   zlist[SpineEvent | None])r&   r'   r(   r)   r<   r   r   r   r   r8  r   r<  r*   r+   r,   r   r   D  s1    3h)]+/)%)r+   r   c                   t        j                  d|       }d| v rt        j                         }nz|ri|j	                  d      }|d   j                         }||d   k(  rdt        |      z   }ndt        |      z
  }t        j                  |      }||_        |}nt        d|  d	      t        j                  d
|       }t        j                  d|       }t        |t        j                        r[|r!|j	                  d      |j                  _        n8|r!|j	                  d      |j                  _        nd| v rd|j                  _        t        | j                  d            D ]  }	 t        | j                  d            D ]  }	 t        | j                  d            D ]  }	 t        | j                  d            D ]  }	 d| v rt        j                   d      |_        n=d| v rt        j                   d      |_        nd| v rt        j                   d      |_        d| v r.|j"                  j%                  t#        j&                                n1d| v r-|j"                  j%                  t#        j(                                d| v r.|j"                  j%                  t#        j*                                nd| v r.|j"                  j%                  t#        j,                                ncd| v r.|j"                  j%                  t#        j.                                n1d| v r-|j"                  j%                  t#        j0                                d| v r.|j"                  j%                  t#        j2                                nld| v r.|j"                  j%                  t#        j4                                n:d| v r6t#        j2                         }
d |
_        |j"                  j%                  |
       d!| v r	 d"| v r-|j"                  j%                  t#        j8                                d#| v r-|j:                  j%                  t;        j<                                d$| v r-|j:                  j%                  t;        j>                                d%| v r-|j:                  j%                  t;        j@                                d&| v r-|j:                  j%                  t;        jB                                d'| v r-|j:                  j%                  t;        jD                                d(| v r-|j"                  j%                  t#        jF                                d)| v r.|j:                  j%                  t;        jH                                n1d*| v r-|j:                  j%                  t;        jJ                                t        |t        jL                        rd+| v rd,|_'        nd-| v rd.|_'        t        j                  d/|       }t        j                  d0|       }|r{tQ        |j	                  d            }tQ        |j	                  d1            }tS        d|z  |z        |jT                  _+        d2| v r| j                  d2      |jT                  _,        n|rtQ        |j	                  d            }|dk(  rw|j	                  d      }|d3k(  rd4|jT                  _-        n(|d5k(  rd6|jT                  _-        nd7|jT                  _-        d2| v r=| j                  d2      |jT                  _,        n|tT        j\                  v rItT        j\                  |   |jT                  _-        d2| v r| j                  d2      |jT                  _,        ntQ        |      d8z   }t_        j`                  t_        jb                  |            \  }}d1|z  }tT        j\                  tQ        |         |jT                  _-        tU        jd                         }tU        jf                  |jT                  jZ                  d      |_4        tU        jf                  |jT                  jZ                  d      |_5        t_        jl                  tQ        |      tQ        |            }tQ        ||z        |_7        tQ        tq        |      |z        |_9        tt        d9   }|sBd2| v r>tU        jf                  |jj                  jZ                  | j                  d2            |_5        |jT                  jw                  |       |r$d2| v r | j                  d2      |jT                  _,        d:| v r"|jy                         }d;|jT                  _-        n]d<| v r=|jy                         }|jT                  }t        |tz              sJ d=|_>        d;|_-        nd>| v r|jy                  d ?      }nd@| v r	 t        |t        jL                        rt        | j                  dA            D ]  }	|j~                  j%                  d        t        | j                  dB            D ]  }	|j~                  j%                  d        t        | j                  dC            D ]  }	|j~                  j%                  dDdE         t        | j                  dF            D ]  }	|j~                  j%                  dDdE         |S )Gaw	  
    returns a :class:`~music21.note.Note` (or Rest or Unpitched, etc.)
    matching the current SpineEvent.
    Does not check to see that it is sane or part of a :samp:`**kern` spine, etc.

    New rhythmic extensions formerly defined in
    `wiki.humdrum.org/index.php/Rational_rhythms`
    and now at https://extras.humdrum.org/man/rscale/
    are fully implemented:

    >>> n = humdrum.spineParser.hdStringToNote('CC3%2')
    >>> n.duration.quarterLength
    Fraction(8, 3)
    >>> n.duration.fullName
    'Whole Triplet (2 2/3 QL)'

    >>> n = humdrum.spineParser.hdStringToNote('e-00.')
    >>> n.pitch
    <music21.pitch.Pitch E-4>
    >>> n.duration.quarterLength
    24.0
    >>> n.duration.fullName
    'Perfect Longa'

    >>> n = humdrum.spineParser.hdStringToNote('F#000')
    >>> n.duration.quarterLength
    32.0
    >>> n.duration.fullName
    'Imperfect Maxima'

    Note that the following example is interpreted as one note in the time of a
    double-dotted quarter not a double-dotted quarter-note triplet.

    I believe that the latter definition, though used in
    https://kern.humdrum.org/cgi-bin/ksdata?l=musedata/mozart/quartet&file=k421-01.krn&f=kern
    and the Josquin Research Project [JRP] is incorrect, seeing as it
    contradicts the specification in
    https://web.archive.org/web/20100203144730/http://www.music-cog.ohio-state.edu/Humdrum/representations/kern.html#N-Tuplets

    >>> storedFlavors = humdrum.spineParser.flavors['JRP']  #_DOCS_HIDE

    This is the default:

    >>> humdrum.spineParser.flavors['JRP'] = False

    >>> n = humdrum.spineParser.hdStringToNote('6..fff')
    >>> n.duration.quarterLength
    Fraction(7, 6)

    >>> n.duration.dots
    0

    >>> n.duration.tuplets[0].durationNormal.dots
    2

    If you want the JRP definition, set humdrum.spineParser.flavors['JRP'] = True
    before calling converter.parse() or anything like that:

    >>> humdrum.spineParser.flavors['JRP'] = True
    >>> n = humdrum.spineParser.hdStringToNote('6..fff')
    >>> n.duration.quarterLength
    Fraction(7, 6)
    >>> n.duration.dots
    2
    >>> n.duration.tuplets[0].durationNormal.dots
    0

    >>> n = humdrum.spineParser.hdStringToNote('gg#q/LL')
    >>> n.duration
    <music21.duration.GraceDuration unlinked type:eighth quarterLength:0.0>
    >>> n.duration.isGrace
    True

    >>> humdrum.spineParser.flavors['JRP'] = storedFlavors  #_DOCS_HIDE

    z([a-gA-G]+)rr[   r         )octavezCould not parse z for note informationz(#+)z(-+)r  {}()[r  r   r  _r  rZ  TwWr  MS$RTr   O'"`~^;vur   up\downz(\d+)%(\d+)z(\d+)rY   r   000maxima00longabrever6  r   qeighthQFP)appoggiaturapLJkpartialrightK)@r_   r`   r   Restr*  lowerr>   r{  stepr%   r6   pitch
accidentalrb   countr   Tier   ra   HalfStepTrillWholeStepTrillHalfStepInvertedMordentWholeStepInvertedMordentHalfStepMordentWholeStepMordentTurnInvertedTurnconnectedToPreviousOrnamentr   Staccato	PizzicatoStaccatissimoTenutoAccentFermataUpBowDownBowNotReststemDirectionr   r   r   r9  dotsr  typeFromNumDictmathmodflog2TupletdurationTupleFromTypeDotsdurationActualdurationNormalgcdnumberNotesActualfloatnumberNotesNormalflavorsappendTupletgetGracer   slashrz  )r   matchedNoterV  kernNoteNamern  rA  	builtNotematchedSharpmatchedFlatre   t1foundRationalfoundNumberdurationFirstdurationSeconddurationTypedurationStringdTunused_remainder	exponents	baseValuenewTupr  r   durs                            r,   ru  ru    s   d ))M84K hYY[
	"((+A$$&<?"\**F\**FIIV,		
 !1(;PQRR99Wh/L))GX.K*dii(*6*<*<Q*?J'*5*;*;A*>J'H_*-J' 8>>#&' (8>>#&' (8>>#&' (8>>#&' (
h)
	
	,
 h%%k&?&?&AB	%%k&@&@&BC
h%%k&I&I&KL	%%k&J&J&LM	%%k&A&A&CD	%%k&B&B&DE
h%%k&6&6&89	%%k&>&>&@A	!%%%b)
h 	
h%%k&:&:&<= h  ''(>(>(@A
h  ''(?(?(AB
h 	  ''(C(C(EF
h  ''(<(<(>?
h  ''(<(<(>?
h%%k&9&9&;< h  ''(;(;(=>	  ''(=(=(?@ *dll+(?'+J$X'-J$ IInh7M))Hh/KM//23]0034,21~3E3U,V
)(?'/~~c':J$	;,,Q/01(..q1N&+3
##(4'+2
##(+2
##(h+3>>#+>
##(X555'/'?'?'MJ$h+3>>#+>
##(\"S(B,0IIdiim,D)yYI'/'?'?I'OJ$__&F$,$F$FzGZGZG_G_ab$cF!$,$F$FzGZGZG_G_ab$cF!((3r7C	N3C'*28}F$'*5+;c+A'BF$
 %.C3(?(0(J(J))..s0C)E% ,,V4sh+3>>#+>
##( h((*
#+
 	((*
!!#}---		((d(;
	 *dll+x~~c*+A##G, ,x~~c*+A##F+ ,x~~c*+A##Iw7 ,x~~c*+A##Iw7 , r+   c                  	 | dk(  rt         j                  d       t        j                         }t	        j
                  d|       }|rFt        |j                  d            |_        |j                  d      r|j                  d      |_	        d	d| v rd	n4d	| v rd
	n-d| v rd	n&d| v sd| v rd	nd| v rd	nd| v rd	nd| v rd	nd| v rd	| j                  d      dkD  }|xs t        t	        j
                  d|             }|xs t        t	        j
                  d|             }d 	fd} ||rdnd      }d| v rt        j                         |_        |||_        |r |d      |_        |S |r |d      n||_        |S )!a  
    kern uses an equals sign followed by processing instructions to
    create new measures.

    * Changed in v10: repeat dots are encoded as :class:`~music21.bar.Repeat`
        objects instead of being stuffed into a non-existent ``Barline.repeatDots``
        attribute.  ``:|:`` now produces an end-Repeat on the previous measure's
        right barline AND a start-Repeat on the new measure's left barline.
    z==|zd"Double bar visually rendered as a single bar" is not supported in music21; storing as a double bar.z(\d+)([a-z]?)r[   rY   rv   r  nonerP  shortrR  tickz||z==doublerw   zheavy-heavyz|!r[  z!|zheavy-light|regularr   z:[|!=]z[|!=]:c                t    | t        j                  |       }nt        j                         }r|_        |S )N)	direction)r   RepeatBarliner  )r  bbarTypes     r,   makeBarz"hdStringToMeasure.<locals>.makeBar	  s1      ZZ)<AAAFr+   endNrU  r  )r  r  r   zbar.Barline)rl  rm  r   r8  r_   r`   r   r*  rm   numberSuffixrq  r_  r   r  pauserightBarlineleftBarline)
r   previousMeasurer  match_measure_numberbothRepeats	endRepeatstartRepeatr  rightBarr  s
            @r,   rP  rP  	  s    53	4 	A99%5x@+11!45%%a(177:AN G
h				TX-							 ..%)KCtBIIi$BCIEbii	8&D!EK 	ut4H
h$,,."'/$#G,AM
 H -8(XHr+   c                   | t         v ry| j                  d      r| dd }|dk(  rt        j                         S |dk(  rt        j                         S |dk(  rt        j
                         S |dk(  rt        j
                         S |dk(  rt        j                         S |d	k(  rt        j                         S |d
k(  rt        j                         S |dk(  rt        j                         S 	 t        j                  |      }|S | j                  d      r)| dd }	 t        |      }t        j                  |      }|S | j                  d      r| dd }t        j"                  d|      }|rt%        |j'                  d            }	|j'                  d      }
|
dvrt)        j*                  |      S d}|
dk(  r|	dz  }	n|
dk(  r|	dz  }	n
|
dk(  r|	dz  }	t)        j*                  |	 d|       S t        d |  d      | j                  d!      r| dd }	 t-        j.                  |      }|S | j                  d"      rt3        |       S | j                  d#      rt3        |       S | j                  d$      r| dd }	 t-        j4                  |      }|S | j                  d%      r?| j7                  d&      }|d'k(  rd(| j7                  d      z  }t9        j:                  |      S | j=                  d)      r| dd( }t9        j>                  |      S t3        |       S # t        j                  $ r t        d|  d      w xY w# t        $ rI t        j                   dd|      }t        j                   dd|      }t        j                  |      }|cY S w xY w# t,        j0                  $ r t3        |      cY S w xY w# t,        j0                  $ r t3        |      cY S w xY w)*a  
    Kern uses symbols such as :samp:`*M5/4` and :samp:`*clefG2`, etc., to control processing

    This method converts them to music21 objects.

    >>> m = humdrum.spineParser.kernTandemToObject('*M3/1')
    >>> m
    <music21.meter.TimeSignature 3/1>

    Unknown objects are converted to MiscTandem objects:

    >>> m2 = humdrum.spineParser.kernTandemToObject('*TandyUnk')
    >>> m2
    <music21.humdrum.spineParser.MiscTandem *TandyUnk>
    Nz*clefr  r  XGv2GvzG^2zG^Fv4FvzUnknown clef type z foundz*MMr?  )rm   z^\[rv   z]\s*$)r  z*MrY   z(\d+)/(\d+)r[   )0r]  r[  r  r]  r@  r[     r   zIncorrect meter: z*ICz*IGz*ITrz*Iz*k#r   rZ   r   ) r   rQ  r
   NoClefPercussionClefTreble8vbClefTreble8vaClefBass8vbClefclefFromStringClefExceptionr%   r  r   MetronomeMark
ValueErrorr_   r  ry   r   r*  r   TimeSignaturer   fromHumdrumClassHumdrumInstrumentExceptionr7  fromHumdrumInstrumentrq  r   KeySignaturer  r  )r  clefTyper  metronomeMarkTextmetronomeMarkNumberMMMS	meterTypetsTemp	numeratordenominatorStrdenominatorinstrumentClassiObjinstrumentStr	numSharpsthisKeys                    r,   rf  rf  
  s   " $$			7	#!":s?;;= _&&((%%''%%''%%''%%''##%%##%%L!%!4!4X!>%% 
		5	!"12J		"'(9":$$,?@BI 
		4	 12J	.)4FLLO,I#\\!_N%77**955!S(NI#t+NI#u,NI**i[++GHH"%6vhf#EFF			5	! *	///@DK 
		5	!&!!			6	"&!!			4	 qr
	-44]CDK 
		4	 LL%	>fll3/0I	**		2,www&!!C %% L&);F86'JKKL  	 "vr3D E "x5F G$$*;<BI	> 55 	/o..	/ 55 	-m,,	-sC   )L "L7 N 4N0 #L47AN	N	N-,N-0OOc                  *     e Zd Zdd fdZddZ xZS )r7  c                2    t        |   di | || _        y )Nr*   )r   r<   r  )r;   r  keywordsr   s      r,   r<   zMiscTandem.__init__~
  s    $8$!r+   c                    | j                    S r   )r  r?   s    r,   r   zMiscTandem._reprInternal
  s    ++r+   rX  )r  r7   r   r   r   )r&   r'   r(   r<   r   r   r   s   @r,   r7  r7  }
  s    " r+   r7  c                  .     e Zd ZdZdd fdZddZ xZS )rR  a  
    A Music21Object that represents a comment in a single spine.

    >>> sc = humdrum.spineParser.SpineComment('! this is a spine comment')
    >>> sc
    <music21.humdrum.spineParser.SpineComment 'this is a spine comment'>
    >>> sc.comment
    'this is a spine comment'
    c                `    t        |   di | t        j                  dd|      }|| _        y )Nz^!+\s?rv   r*   )r   r<   r_   r  rg  r;   rg  r  commentPartr   s       r,   r<   zSpineComment.__init__
  s,    $8$ffYG4'r+   c                ,    t        | j                        S r   r  rg  r?   s    r,   r   zSpineComment._reprInternal
      DLL!!r+   rX  rg  r7   r   r   r   r&   r'   r(   r)   r<   r   r   r   s   @r,   rR  rR  
  s    (
"r+   rR  c                  .     e Zd ZdZdd fdZddZ xZS )r   a  
    A Music21Object that represents a comment for the whole score

    >>> sc = humdrum.spineParser.GlobalComment('!! this is a global comment')
    >>> sc
    <music21.humdrum.spineParser.GlobalComment 'this is a global comment'>
    >>> sc.comment
    'this is a global comment'
    c                    t        |   di | t        j                  dd|      }|j	                         }|| _        y )Nr  rv   r*   )r   r<   r_   r  r  rg  r  s       r,   r<   zGlobalComment.__init__
  s:    $8$ffZW5!'')'r+   c                ,    t        | j                        S r   r  r?   s    r,   r   zGlobalComment._reprInternal
  r  r+   rX  r  r   r  r   s   @r,   r   r   
  s    ("r+   r   c                  ~    e Zd ZU dZ	 	 d	 	 	 	 	 d fdZi dddddd	d
dddddddddddddddddddddddddd di d!d"d#dd$d%d&dd'd(d)dd*dd+dd,dd-dd.dd/dd0d1d2dd3dd4d5d6d7i d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPddQdRdSdTdUdVdWdXi dYdZd[d\d]dd^dd_d`dadbdcdddedfdgdhdidjdkdldmdndodpdqdrdsdtdudvdwdxi dyddzdd{dd|d}d~dddddddddddddddddddddddddddddddddddddZded<   ddZddZ xZ	S )r   a&  
    A Music21Object that represents a reference in the score, called a "reference record"
    in Humdrum.  See Humdrum User's Guide Chapter 2.

    >>> sc = humdrum.spineParser.GlobalReference('!!!REF:this is a global reference')
    >>> sc
    <music21.humdrum.spineParser.GlobalReference REF 'this is a global reference'>
    >>> sc.code
    'REF'
    >>> sc.value
    'this is a global reference'

    Alternate form:

    >>> sc = humdrum.spineParser.GlobalReference('REF', 'this is a global reference')
    >>> sc
    <music21.humdrum.spineParser.GlobalReference REF 'this is a global reference'>
    >>> sc.code
    'REF'
    >>> sc.value
    'this is a global reference'

    Language codes are parsed:

    >>> sc = humdrum.spineParser.GlobalReference('!!!OPT@@RUS: Vesna svyashchennaya')
    >>> sc.code
    'OPT'
    >>> sc.language
    'RUS'
    >>> sc.isPrimary
    True

    >>> sc = humdrum.spineParser.GlobalReference('!!!OPT@FRE: Le sacre du printemps')
    >>> sc.code
    'OPT'
    >>> sc.language
    'FRE'
    >>> sc.isPrimary
    False
    rv   c                   t        |   d
i | t        j                  dd|      }|j	                         }|2d|v r.t        j                  dd|      }t        j                  dd|      }|| _        || _        d | _        d| _        d| j
                  v r(d| _        | j
                  j                  dd	      | _        d	| j
                  v r)| j
                  j                  d	      \  | _        | _        y y )Nr   rv   r   z^.*?:z:.*$Fz@@T@r*   )r   r<   r_   r  r  r   r   language	isPrimaryreplacer   )r;   	codeOrAllvalueOrNoner  r   s       r,   r<   zGlobalReference.__init__
  s     	$8$FF8R3	OO%	3)#3&&2y9KwI6I"	*
"&$499!DN		))$4DI$))'+yys';$DIt} r+   COMcomposerCOAattributedComposerCOSsuspectedComposerCOLcomposerAliasCOCcomposerCorporateCDTCBLCDLCNTLYRlyricistLIB
librettistLARarrangerLORorchestratorTXOtextOriginalLanguageTXLtextLanguageTRN
translatorRTLRMMmanufacturerzRC#RRD
dateIssuedRLCRNPproducerRDTzRT#MGNMPNMPSMRDMLCMCN	conductorMPDMDTOTLtitleOTPpopularTitleOTAalternativeTitleOPRparentTitleOAC	actNumberOSCsceneNumberOMVmovementNumberOMDmovementNameOPS
opusNumberONMrm   OVMvolumeNumberODEdedicatedToOCO
commissionOCLtranscriberONBODTdateCreatedOCYcountryOfCompositionOPClocaleOfCompositionGTL
groupTitleGAWassociatedWorkGCOcollectionDesignationPUBPEDPPRfirstPublisherPDTdateFirstPublishedPTLpublicationTitlePPPplaceFirstPublishedzPC#publishersCatalogNumberSCTscholarlyCatalogAbbreviationSCAscholarlyCatalogNameSMSmanuscriptSourceNameSMLmanuscriptLocationSMAmanuscriptAccessAcknowledgementYEPelectronicPublisherYEC	copyrightYERelectronicReleaseDateYEMYENYORYOOoriginalDocumentOwnerYOYYOEoriginalEditorEEDelectronicEditorENCelectronicEncoderENDEMDEEVEFLESTVTSACOAFRAGN)ASTAMDAMTAINAREARLHAOHTXRLNRNBRWBzdict[str, str]humdrumKeyToUniqueNamec                   | j                   }| j                  }| j                  j                  |d      }|r|j	                  ||       y|| j                  v r|j                  d|z   |       y|j                  ||       y)z
        update a metadata object according to information in this GlobalReference

        See humdrum guide Appendix I for information
        rv   zhumdrum:N)r   r   r  r  add	addCustom)r;   r   crV  
uniqueNames        r,   r   zGlobalReference.updateMetadata[  so     IIJJ5599!R@
FF:q!$---LLa+ LLAr+   c                8    | j                    d| j                  S )Nr  r  r?   s    r,   r   zGlobalReference._reprInternaln  s    ))Adjj^,,r+   )rv   N)r  r7   r   r  r   r   )r   zmetadata.Metadatar   r   r   )
r&   r'   r(   r)   r<   r  r   r   r   r   r   s   @r,   r   r   
  sZ   'T  $<< <
 
<,l. 	zl. 	#	l.
 	"l. 	l. 	"l. 	rl. 	rl. 	rl. 	rl. 	zl. 	|l. 	zl. 	~l.  	%!l." 	~#l.( 	|)l.* 	r+l., 	~-l.. 	r/l.0 	|1l.2 	r3l.4 	z5l.6 	r7l.8 	r9l.< 	r=l.> 	r?l.@ 	rAl.B 	rCl.D 	rEl.F 	{Gl.H 	rIl.J 	rKl.N 	wOl.P 	~Ql.R 	!Sl.T 	}Ul.V 	{Wl.X 	}Yl.Z 	[l.\ 	~]l.^ 	|_l.` 	xal.b 	~cl.d 	}el.f 	|gl.h 	}il.j 	rkl.l 	}ml.n 	%ol.p 	$ql.t 	|ul.v 	wl.x 	&yl.| 	r}l.~ 	rl.@ 	Al.B 	#Cl.D 	!El.F 	$Gl.H 	(Il.J 	-Kl.L 	%Ml.N 	%Ol.P 	#Ql.R 	0Sl.T 	$Ul.V 	{Wl.X 	&Yl.Z 	r[l.\ 	r]l.^ 	r_l.` 	&al.b 	rcl.d 	el.f 	!gl.h 	"il.j 	rkl.l 	rml.n 	rol.p 	rql.r 	rsl.t 	rul.x 	ryl.z 	r{l.| 	r}l.~ Wl.N l\&-r+   r   c                      e Zd ZdZddZy)Testz
    Note: most spineParser tests are in :mod:`music21.humdrum.tests`.
    Only `testCopyAndDeepcopy` lives here so that `globals()` resolves.
    c                2    ddl m}  || t                      y )Nr   )testCopyAll)music21.test.commonTestr  globals)r;   r  s     r,   testCopyAndDeepcopyzTest.testCopyAndDeepcopyw  s    7D')$r+   Nr   )r&   r'   r(   r)   r  r*   r+   r,   r  r  r  s    %r+   r  __main__)r   r7   r   r  r   )r   r7   r  r^  r   zstream.Measure)r  r7   r   zbase.Music21Object | None)Mr)   
__future__r   rn   r  r_   typingrZ  unittestr  music21.common.numberToolsr   music21.common.typesr   music21r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   music21.durationr   music21.humdrumr   r   r  pathlibEnvironmentrl  r  r   Music21Exceptionr%   ProtoM21Objectr.   r   r   r|   rz   r{   rx   r   r  r]  r  r  r   r   r   ru  rP  rf  Music21Objectr7  rR  r   r   TestCaser  r&   mainTestr*   r+   r,   <module>r     sY  /` #   	    - ) !                      * & '??&{&&'<=%.9 	|44 	A/G22 A/H' >'(( &C C><.+ <.~"  " J) )0/'' /:N*7)) N*b^+ ^+B.* .*b2* 2*n=1'' =1DDg,, DR[g,, [|Ur ,0II(I IVj"r ##  "4%% "&"D&& "(B-d(( B-J%8 % zGT r+   