
    3jY              
         d Z ddlmZ ddlmZ ddlZddlZddlm	Z	 ddlm
Z
 ddlmZ ddlmZ dd	lmZ dd
lmZ ej                   rddlmZ  ej$                  d      Z G d de	j(                        Ze
j,                  d   e
j,                  d   e
j,                  d   e
j,                  d   e
j,                  d   e
j,                  d   e
j,                  d   e
j,                  d   e
j,                  d   f	Z G d dej0                  eej2                        Z G d dej0                  e      Z G d dej8                        ZeegZedk(  rddlZ ej@                  e       yy)a  
The module defines Beam and Beams (note plural) objects.

The Beams object holds multiple Beam objects (e.g., a 32nd note might have
three Beam objects in its Beam object).

The Beams object is stored in :class:`~music21.note.Note` and
:class:`~music21.chord.Chord` objects as their :attr:`~music21.note.Note.beams`
attributes.  Beams objects can largely be treated as a list.

See `meter.TimeSignature`. :meth:`~music21.meter.TimeSignature.getBeams` for a
way of getting beam information for a measure given the meter.  The
`meter.TimeSignature`. :attr:`~music21.meter.TimeSignature.beamSequence`
attribute holds information about how to beam given the TimeSignature

Run `Stream`. :meth:`~music21.stream.Stream.makeBeams` to set beaming
information automatically given the current meter.

Suppose you had a measure of two eighths and a quarter and wanted to explicitly
beam the two eighth notes.  You could do this:

>>> m = stream.Measure()
>>> n1 = note.Note('C4', quarterLength=0.5)
>>> n2 = note.Note('D4', quarterLength=0.5)
>>> n3 = note.Note('E4', quarterLength=1.0)
>>> m.append(n1)
>>> m.append(n2)
>>> m.append(n3)
>>> n1.beams.fill('eighth', type='start')
>>> n2.beams.fill('eighth', type='stop')
>>> n1.beams
<music21.beam.Beams <music21.beam.Beam 1/start>>

>>> n2.beams
<music21.beam.Beams <music21.beam.Beam 1/stop>>

But suppose you wanted something harder: two 16ths, an 8th, a quarter, with the
first 3 notes beamed?  The first note and 3rd are easy to do, using the method
above:

>>> m = stream.Measure()
>>> n1 = note.Note('C4', quarterLength=0.25)
>>> n2 = note.Note('D4', quarterLength=0.25)
>>> n3 = note.Note('E4', quarterLength=0.5)
>>> n4 = note.Note('F4', quarterLength=1.0)
>>> for n in [n1, n2, n3, n4]:
...     m.append(n)
>>> n1.beams.fill('16th', type='start')
>>> n3.beams.fill('eighth', type='stop')

but the second note has an 8th beam that continues and a 16th beam that stops.
So you will need to set them separately:

>>> n2.beams.append('continue')
>>> n2.beams.append('stop')
>>> n2.beams
<music21.beam.Beams <music21.beam.Beam 1/continue>/<music21.beam.Beam 2/stop>>

To get rid of beams on a note do:

>>> n2.beams.beamsList = []
    )annotations)IterableN)exceptions21)duration)environment)prebase)style)EqualSlottedObjectMixin)basebeamc                      e Zd Zy)BeamExceptionN)__name__
__module____qualname__     9/DATA/.local/lib/python3.12/site-packages/music21/beam.pyr   r   ^   s    r   r             @                  c                  .     e Zd ZdZdZd fd	Zd Z xZS )Beama,  
    A Beam is an object representation of one single beam, that is, one
    horizontal line connecting two notes together (or less commonly a note to a
    rest).  Thus, it takes two separate Beam objects to represent the beaming of
    a 16th note.

    The Beams object (note the plural) is the object that handles groups of
    Beam objects; it is defined later on.

    Here are two ways to define the start of a beam

    >>> b1 = beam.Beam(type='start')
    >>> b2 = beam.Beam('start')

    Here is a partial beam (that is, one that does not connect to any other
    note, such as the second beam of a dotted eighth, sixteenth group)

    Two ways of doing the same thing

    >>> b3 = beam.Beam(number=1, type='partial', direction='left')
    >>> b3
    <music21.beam.Beam 1/partial/left>

    >>> b4 = beam.Beam('partial', 'left')
    >>> b4.number = 1
    >>> b4
    <music21.beam.Beam 1/partial/left>

    All attributes must be the same for equality:

    >>> b3 == b4
    True

    >>> b2
    <music21.beam.Beam None/start>
    >>> b2 == b3
    False
    )	directionidindependentAnglenumbertypec                z    t         |           || _        || _        d | _        || _        t        |       | _        y N)super__init__r$   r    r"   r#   r!   )selfr$   r    r#   	__class__s       r   r(   zBeam.__init__   s:    	" $  T(r   c                x    | j                    d| j                   }| j                  |d| j                   z  }|S N/)r#   r$   r    )r)   outs     r   _reprInternalzBeam._reprInternal   s?    Qtyyk*>>%Qt~~&''C
r   )NNN)r   r   r   __doc__	__slots__r(   r/   __classcell__)r*   s   @r   r   r   k   s    %RI
r   r   c                      e Zd ZU dZdZddiZded<   ddZd Zd	 Z	d
 Z
d Zd Zedd       Zedd       Zed        Zedd       ZddZddZd Zd Zd Zd ZddZddZy) BeamsaH  
    The Beams object stores in it attribute beamsList (a list) all the Beam
    objects defined above.  Thus, len(beam.Beams) tells you how many beams the
    note currently has on it, and iterating over a Beams object gives you each
    Beam.

    >>> n = note.Note(type='16th')
    >>> isinstance(n.beams, beam.Beams)
    True

    >>> n.beams.fill(2, 'start')
    >>> len(n.beams)
    2

    >>> for thisBeam in n.beams:
    ...     thisBeam.type
    'start'
    'start'

    >>> print(n.beams)
    <music21.beam.Beams <music21.beam.Beam 1/start>/<music21.beam.Beam 2/start>>
    	beamsList	featheredr!   r7   zg
            Boolean determining if this is a feathered beam or not
            (does nothing for now).zdict[str, str]	_DOC_ATTRc                @    g | _         d| _        t        |       | _        y )NFr5   r)   s    r   r(   zBeams.__init__   s    %'$ T(r   c                ,    t        | j                        S r&   )iterr6   r:   s    r   __iter__zBeams.__iter__   s    DNN##r   c                ,    t        | j                        S r&   )lenr6   r:   s    r   __len__zBeams.__len__   s    4>>""r   c                `    t        || j                        xr t        |       t        |      k(  S r&   )
isinstancer*   repr)r)   others     r   __eq__zBeams.__eq__   s%    %0NT$Z4;5NNr   c                    t        |       dz	  S )N   )r!   r:   s    r   __hash__zBeams.__hash__   s    $x1}r   c                ~    g }| j                   D ]  }|j                  t        |              dj                  |      S r,   )r6   appendstrjoin)r)   msgr   s      r   r/   zBeams._reprInternal   s3    NNDJJs4y! #xx}r   c                4   g }| D ]  }|j                   j                  t        vr|j                  d       1d|j                  vr|j                  d       Qt               }|j                  |j                   j                         |j                  |        |S )af  
        Given a list or iterator of elements, return a list of None or Beams for
        each element: None if the element is a quarter or larger or
        if the element is a Rest, and the fullest possible set of beams
        for the duration if it is a beamable.  Each beam object has type of None

        staticmethod, does not need instance:

        >>> durList = [0, -1, -2, -3]
        >>> srcList = [note.Note(quarterLength=2 ** x) for x in durList]
        >>> srcList.append(note.Rest(type='32nd'))
        >>> beam.Beams.naiveBeams(srcList)
        [None,
         <music21.beam.Beams <music21.beam.Beam 1/None>>,
         <music21.beam.Beams <music21.beam.Beam 1/None>/<music21.beam.Beam 2/None>>,
         <music21.beam.Beams <music21.beam.Beam 1/None>/<music21.beam.Beam
                     2/None>/<music21.beam.Beam 3/None>>,
         None]
        NNotRest)r   r$   beamableDurationTypesrJ   classSetr4   fill)srcListr6   elbs       r   
naiveBeamszBeams.naiveBeams   s    , ')	B {{'<<  &"++-  & G r{{''(  #  r   c                    d}t        t        |             D ],  }|t        |       dz
  k7  r	| |dz      }nd}||d| |<   | |   }. | S )a  
        Go through the naiveBeamsList and remove beams from objects surrounded
        by None objects -- you can't beam to nothing!

        Modifies beamsList in place

        >>> N = note.Note
        >>> R = note.Rest
        >>> e = 'eighth'
        >>> nList = [N(type=e), R(type=e), N(type=e), N(type=e),
        ...          R(type=e), N(type=e), R(type=e), N(type=e)]
        >>> beamsList = beam.Beams.naiveBeams(nList)
        >>> beamsList
        [<music21.beam.Beams <music21.beam.Beam 1/None>>,
         None,
         <music21.beam.Beams <music21.beam.Beam 1/None>>,
         <music21.beam.Beams <music21.beam.Beam 1/None>>,
         None,
         <music21.beam.Beams <music21.beam.Beam 1/None>>,
         None,
         <music21.beam.Beams <music21.beam.Beam 1/None>>]

        >>> beamsList2 = beam.Beams.removeSandwichedUnbeamables(beamsList)
        >>> beamsList2 is beamsList
        True
        >>> beamsList2
        [None,
         None,
         <music21.beam.Beams <music21.beam.Beam 1/None>>,
         <music21.beam.Beams <music21.beam.Beam 1/None>>,
         None,
         None,
         None,
         None]
        N   )ranger?   )r6   beamLastibeamNexts       r   removeSandwichedUnbeamablesz!Beams.removeSandwichedUnbeamables#  sf    L s9~&AC	NQ&&$QU+H$4#	! |H ' r   c                   t        t        | dd | dd             D ]  \  }\  }}|r|s|j                         }|s"|D ]  }|j                  |      }|j                  dk7  s|j
                  dk7  r3||j                         vrF|j                  |      }|j                  dk(  r|j
                  dk(  rv|j                  dv r"t        j                  d| d| d	| d
|         d|_        d|_        |j                  dk(  rd|_        n|j                  dk(  rd|_        d|_          t        | dd | dd       D ]  \  }}|r|s|j                         }|s|D ]{  }|j                  |      }|j                  dk7  s|j
                  dk7  r3||j                         vrF|j                  |      }	|	j                  dk7  rgd|_        d|_        d|	_        }  | S )z
        Partial-right followed by partial-left must also be connected, even if otherwise
        over a archetypeSpan, such as 16th notes 2 and 3 in a quarter note span where
        16ths are not beamed by default.
        NrX   partialright)continuestopzFound a messed up beam pair z, z, at index z of 
startrc   rb   left)	enumeratezip
getNumbersgetByNumberr$   r    environLocalwarn)
r6   r[   bThisbNextbThisNumthisNumthisBeamnextBeambPrevprevBeams
             r   mergeConnectingPartialBeamsz!Beams.mergeConnectingPartialBeamsU  s	    "+3y"~y}+M!NA~u'')H# ,,W5==I-1C1Cw1N%"2"2"44 ,,W5==I-(2D2D2O==$88 %%6ugRw G$$%3fYK9  '%)"==I-$*HM]]g-$.HM%)"3 $ "OH  	!"y"~>LE5'')H# ,,W5==I-1C1Cv1M%"2"2"44 ,,W5==F* &%)" * $ ?0 r   c                   t        |       D ]  \  }}|	|j                         }d|vrd|vr
d|vrd| |<   +d}d}|j                  D ]x  }|j                  dk(  rd}|j                  dk(  rd}'|r&|j                  dk(  r|j                  dk(  rd	|_        O|sR|j                  dk(  sb|j                  d	k(  srd|_        z  | S )
a<  
        It is possible at a late stage to have beams that only consist of partials
        or beams with a 'start' followed by 'partial/left' or possibly 'stop' followed
        by 'partial/right'; beams entirely consisting of partials are removed
        and the direction of irrational partials is fixed.
        Nrd   rc   rb   FTr`   re   ra   )rf   getTypesr6   r$   r    )r6   r[   beamsObjallTypeshasStarthasStoprU   s          r   sanitizePartialBeamszBeams.sanitizePartialBeams  s     %Y/KAx((*Hh&6+AjX`F`#	! HG''66W$#H66V#"G) 3v8M")AK9!49O"(AK ( 04 r   Nc                    t        |t              r*t        ||      }t        | j                        dz   |_        n|}| j                  j                  |       y)a  
        Append a new Beam object to this Beams object, automatically creating the Beam
        object and incrementing the number count.

        >>> beams = beam.Beams()
        >>> beams.append('start')
        >>> beams.beamsList
        [<music21.beam.Beam 1/start>]

        >>> beams.append('partial', 'right')
        >>> beams.beamsList
        [<music21.beam.Beam 1/start>, <music21.beam.Beam 2/partial/right>]

        A beam object can also be specified:

        >>> beams = beam.Beams()
        >>> beam1 = beam.Beam(type='start', number=1)
        >>> beams.append(beam1)
        >>> beams.beamsList
        [<music21.beam.Beam 1/start>]
        rX   N)rB   rK   r   r?   r6   r#   rJ   )r)   r$   r    objs       r   rJ   zBeams.append  sF    , dC tY'CT^^,q0CJCc"r   c                   g | _         |ddt        j                  d   fv rd}n|dt        j                  d   fv rd}n|dt        j                  d   fv rd}n|dt        j                  d	   fv rd}n|d
t        j                  d   fv rd
}nv|dt        j                  d   fv rd}n\|dt        j                  d   fv rd}nB|dt        j                  d   fv rd}n(|dt        j                  d   fv rd}nt        d|       t	        d|dz         D ].  }t               }||_        | j                   j                  |       0 || j                  |       yy)a2  
        A quick way of setting the beams list for a particular duration, for
        instance, `fill('16th')` will clear the current list of beams in the
        Beams object and add two beams.  `fill(2)` will do the same (though note
        that that is an int, not a string).

        It does not do anything to the direction that the beams are going in,
        or by default.  Either set type here or call `setAll()` on the Beams
        object afterwards.

        Both "eighth" and "8th" work.  Adding more than nine beams (i.e. things
        like 4096th notes) raises an error.

        >>> a = beam.Beams()
        >>> a.fill('16th')
        >>> len(a)
        2

        >>> a.fill('32nd', type='start')
        >>> len(a)
        3

        >>> a.beamsList[2]
        <music21.beam.Beam 3/start>

        >>> a.beamsList[2].type
        'start'

        Filling a smaller number wipes larger numbers of beams:

        >>> a.fill('eighth', type='start')
        >>> len(a)
        1

        OMIT_FROM_DOCS

        >>> a.fill(4)
        >>> len(a)
        4

        >>> a.fill('128th')
        >>> len(a)
        5

        >>> a.fill('256th')
        >>> len(a)
        6

        >>> a.fill(12)
        Traceback (most recent call last):
        music21.beam.BeamException: cannot fill beams for level 12
        rX   8thr      r      r   rG   r      r      r      r   r   	   r   zcannot fill beams for level N)	r6   r   typeFromNumDictr   rY   r   r#   rJ   setAll)r)   levelr$   countr[   r}   s         r   rR   z
Beams.fill  st   j Qx77:;;Eq(222677Eq(222677Eq(222677Eq(223788Eq(223788Eq(223788Eq(224899Eq(224899E">ug FGGq%!)$A&CCJNN!!#& % KK r   c                    || j                         vrt        d| d      | j                  D ]  }|j                  |k(  s|c S  y)aB  
        Gets an internal beam object by number.

        >>> a = beam.Beams()
        >>> a.fill('16th')
        >>> a.setAll('start')
        >>> a.getByNumber(2).type
        'start'

        >>> a.getByNumber(30)
        Traceback (most recent call last):
        IndexError: beam number 30 cannot be accessed
        beam number  cannot be accessedN)rh   
IndexErrorr6   r#   )r)   r#   r   s      r   ri   zBeams.getByNumber3  sG     **|F83FGHHNND{{f$ #r   c                T    | j                   D cg c]  }|j                   c}S c c}w )z
        Returns a list of all defined beam numbers; it should normally be a set
        of consecutive integers, but it might not be.

        >>> a = beam.Beams()
        >>> a.fill('32nd')
        >>> a.getNumbers()
        [1, 2, 3]
        )r6   r#   r)   xs     r   rh   zBeams.getNumbersG  s$     #'..1.Q.111   %c                    | j                  |      }|j                  |j                  S |j                   d|j                   S )a*  
        Get beam type, with direction, by number

        >>> a = beam.Beams()
        >>> a.fill('16th')
        >>> a.setAll('start')
        >>> a.setByNumber(2, 'partial-right')
        >>> a.getTypeByNumber(2)
        'partial-right'

        >>> a.getTypeByNumber(1)
        'start'
        -)ri   r    r$   )r)   r#   beamObjs      r   getTypeByNumberzBeams.getTypeByNumberS  sF     ""6*$<<ll^1W%6%6$788r   c                T    | j                   D cg c]  }|j                   c}S c c}w )z
        Returns a list of all beam types defined for the current beams

        >>> a = beam.Beams()
        >>> a.fill('16th')
        >>> a.setAll('start')
        >>> a.getTypes()
        ['start', 'start']
        )r6   r$   r   s     r   rv   zBeams.getTypesg  s$     !%/1///r   c                f    |dvrt        d|       | j                  D ]  }||_        ||_         y)a  
        `setAll` is a method of convenience that sets the type
        of each of the beam objects within the beamsList to the specified type.
        It also takes an optional "direction" attribute that sets the direction
        for each beam (otherwise the direction of each beam is set to None)
        Acceptable directions (start, stop, continue, etc.) are listed under
        Beam() above.

        >>> a = beam.Beams()
        >>> a.fill('16th')
        >>> a.setAll('start')
        >>> a.getTypes()
        ['start', 'start']

        >>> a.setAll('sexy')
        Traceback (most recent call last):
        music21.beam.BeamException: beam type cannot be sexy

        rd   rc   rb   r`   beam type cannot be N)r   r6   r$   r    )r)   r$   r    r   s       r   r   zBeams.setAlls  s<    ( ??"6tf =>>NNDDI&DN #r   c                    d|v r|j                  d      \  }}|dvrt        d|       || j                         vrt        d| d      | j                  D ]   }|j
                  |k(  s||_        ||_        " y)a
  
        Set an internal beam object by number, or rhythmic symbol level.

        >>> a = beam.Beams()
        >>> a.fill('16th')
        >>> a.setAll('start')
        >>> a.setByNumber(1, 'continue')
        >>> a.beamsList[0].type
        'continue'

        >>> a.setByNumber(2, 'stop')
        >>> a.beamsList[1].type
        'stop'

        >>> a.setByNumber(2, 'partial-right')
        >>> a.beamsList[1].type
        'partial'

        >>> a.beamsList[1].direction
        'right'

        >>> a.setByNumber(30, 'stop')
        Traceback (most recent call last):
        IndexError: beam number 30 cannot be accessed

        >>> a.setByNumber(2, 'crazy')
        Traceback (most recent call last):
        music21.beam.BeamException: beam type cannot be crazy

        r   r   r   r   r   N)splitr   rh   r   r6   r#   r$   r    )r)   r#   r$   r    r   s        r   setByNumberzBeams.setByNumber  s    @ $;"jjoOD)??"6tf =>>**|F83FGHHNND{{f$ 	!* #r   )returnNone)rS   zIterable[base.Music21Object])r6   list[Beams | None])r6   r   r   r   )NNr&   )r   r   r   r0   r1   r8   __annotations__r(   r=   r@   rE   rH   r/   staticmethodrV   r]   rt   r{   rJ   rR   ri   rh   r   rv   r   r   r   r   r   r4   r4      s    2I 	 '!I~ $#O % %N / /b C CJ ! !L#<Qf(
29(
0'4)+r   r4   c                      e Zd Zd Zy)Testc                2    ddl m}  || t                      y )Nr   )testCopyAll)music21.test.commonTestr   globals)r)   r   s     r   testCopyAndDeepcopyzTest.testCopyAndDeepcopy  s    7D')$r   N)r   r   r   r   r   r   r   r   r     s    %r   r   __main__)!r0   
__future__r   collections.abcr   typingtunittestmusic21r   r   r   r   r	   music21.common.objectsr
   TYPE_CHECKINGr   Environmentrj   Music21Exceptionr   r   rP   ProtoM21Object
StyleMixinr   r4   TestCaser   
_DOC_ORDERr   mainTestr   r   r   <module>r      sX  =| # $         : ?? '{&&v.	L11 	
 QR (":":2">R (":":3"?S!8#;#;C#@T"H$<$<T$B F7!!#:E<L<L FTA+G""$; A+N%8 % T]
 zGT r   