
    3j/S                    `   d dl mZ d dlZd dlm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mZmZ  ej$                  d      Z G d	 d
ej(                        Zeeef   Zeedf   Zeeedf   df   ZdZ ee      Z ed      dd       Z ed      dd       Z  ed      dd       Z! ed      d d       Z" ed      d!d       Z# ed      d"d       Z$d#dZ%d#dZ&d$dZ'd$dZ(d%dZ)d$dZ* ed      d&d       Z+ ed      d&d       Z,e-dk(  rd dl	Z	 e	j\                          yy)'    )annotationsN)	lru_cache)common)MeterDivision)environment)MeterExceptionMusic21ExceptionTimeSignatureExceptionzmeter.toolsc                  ,    e Zd ZU ded<   ded<   ded<   y)MeterTerminalTupleint	numeratordenominatorr   divisionN)__name__
__module____qualname____annotations__     @/DATA/.local/lib/python3.12/site-packages/music21/meter/tools.pyr   r      s    Nr   r   .)                   @      i   c                   t        j                  | d      \  }}|j                         }|st        j                  }nf|j                         }d|j                         v rt        j                  }n3d|j                         v rt        j                  }nt        j                  }t        j                  d|      }|At        |j                  d            }t        |j                  d            }t        |||      S t        d|        )	a  
    Returns a three-element MeterTerminalTuple of numerator, denominator, and optional
    division of the meter.

    >>> meter.tools.slashToTuple('3/8')
    MeterTerminalTuple(numerator=3, denominator=8, division=<MeterDivision.NONE>)
    >>> meter.tools.slashToTuple('7/32')
    MeterTerminalTuple(numerator=7, denominator=32, division=<MeterDivision.NONE>)
    >>> meter.tools.slashToTuple('slow 6/8')
    MeterTerminalTuple(numerator=6, denominator=8, division=<MeterDivision.SLOW>)
    z0123456789/.)numbersslowfastz(\d+)/(\d+)r   r   z1slashToTuple() cannot find two part fraction for )r   getNumFromStrstripr   NONElowerSLOWFASTrematchr   groupr   r   )valuevalueNumbers
valueCharsr   matchesnds          r   slashToTupler3   (   s      &33E<J LL*%%'L %%%%'
Z%%''$))Hz''))$))H$))Hhh~|4Ga !a !!!Q11
LUGT
UUr   c                    g }| j                         } | j                  d      }|D ]5  }	 t        |      }|j                  |j                  |j
                  f       7 t        |      S # t        $ r Y Nw xY w)at  
    Change a compount meter into a list of simple numberator, demoninator values

    >>> meter.tools.slashCompoundToFraction('3/8+2/8')
    ((3, 8), (2, 8))
    >>> meter.tools.slashCompoundToFraction('5/8')
    ((5, 8),)
    >>> meter.tools.slashCompoundToFraction('5/8+2/4+6/8')
    ((5, 8), (2, 4), (6, 8))

    * Changed in v7: new location and returns a tuple.
    +)r%   splitr3   appendr   r   r   tuple)r-   post	valueListpartms        r   slashCompoundToFractionr=   M   st     DKKMEC I	T"AKKamm45  ;  		s   2A))	A54A5c                :   g }d}| j                         j                  d      }|D ]Y  }d|v r4	 t        |      }|j                  |j                  |j                  f       ;	 |j                  t        |      df       d}[ g }t        |      D ]A  \  }\  }	}
|
$||d
z   d D ]  \  }}|	|}
 n t        d|        |j                  |	|
f       C t        |      |fS # t        $ r}t	        d|  d      |d}~ww xY w# t        $ r t        d|  d	      w xY w)au  
    Given a mixture if possible meter fraction representations, return a tuple
    of two elements: The first element is a tuple of pairs of numerator, denominators
    that are implied by the time signature.

    The second element is False if the value was a simple time signature (like 4/4)
    or a composite meter where all numerators had their own denominators.

    >>> meter.tools.slashMixedToFraction('4/4')
    (((4, 4),), False)

    >>> meter.tools.slashMixedToFraction('3/8+2/8')
    (((3, 8), (2, 8)), False)

    >>> meter.tools.slashMixedToFraction('3+2/8')
    (((3, 8), (2, 8)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8')
    (((3, 8), (2, 8), (5, 8)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4')
    (((3, 8), (2, 8), (5, 8), (3, 4)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4+2+1+4/16')
    (((3, 8), (2, 8), (5, 8), (3, 4), (2, 16), (1, 16), (4, 16)), True)

    >>> meter.tools.slashMixedToFraction('3+2+5/8+3/4+2+1+4')
    Traceback (most recent call last):
    music21.exceptions21.MeterException: cannot match denominator to numerator in: 3+2+5/8+3/4+2+1+4

    >>> meter.tools.slashMixedToFraction('3.0/4.0')
    Traceback (most recent call last):
    music21.exceptions21.TimeSignatureException: Cannot create time signature from "3.0/4.0"

    * Changed in v7: new location and returns a tuple as first value.
    Fr5   /z#Cannot create time signature from ""NTzCannot parse this file -- this error often comes up if the musicxml pickled file is out of date after a change in musicxml/__init__.py . Clear your temp directory of .p and .p.gz files and try again. Time Signature:  r   z*cannot match denominator to numerator in: )r%   r6   r3   r   r
   r7   r   r   r   
ValueErrorr	   	enumerater8   )valueSrcpresummedNumeratorr-   r;   tupmer9   iintNumintDenom_	nextDenoms                r   slashMixedToFractionrN   g   si   L ,.CONN""3'E$;O"4( JJs78	4

CIt,-"& ( D "+3FH"%a!ef+I((H #.
 %'QRZQ[%\]]VX&' "0 ;''= " O,9(1EGLNOO  4&' (0j	34 44s#   C "D 	C>)C99C>Dc                F   g }| D ]>  \  }}|r#|d   d   |k(  r|d   d   j                  |       +|j                  |g|f       @ g }|D ]F  }|d   D cg c]  }t        |       }}dj                  |      }|d   }	|j                  ||	f       H t        |      S c c}w )ab  
    Given a tuple of fraction values, compact numerators by sum if denominators
    are the same

    >>> from music21.meter.tools import fractionToSlashMixed
    >>> fractionToSlashMixed(((3, 8), (2, 8), (5, 8), (3, 4), (2, 16), (1, 16), (4, 16)))
    (('3+2+5', 8), ('3', 4), ('2+1+4', 16))

    * Changed in v7: new location and returns a tuple.
    r   r   r5   )r7   strjoinr8   )
fListrE   r1   r2   r9   r;   xnStrListnStrdInts
             r   fractionToSlashMixedrX      s     (*C13r71:?GAJa  JJQx   #%D$(G,GqCFG,xx!AwT4L!	  ; -s   Bc                J   g }g }t               }| D ]8  \  }}|j                  |       |j                  |       |j                  |       : t        |      dk(  rt	        |      }|d   }||fS t        j                  | }d}t        ||      D ]  \  }}	||||	z  z  z  } ||fS )a  
    Given a tuple of tuples of numerator and denominator,
    find the sum; does NOT reduce to its lowest terms.

    >>> from music21.meter.tools import fractionSum
    >>> fractionSum(((3, 8), (5, 8), (1, 8)))
    (9, 8)
    >>> fractionSum(((1, 6), (2, 3)))
    (5, 6)
    >>> fractionSum(((3, 4), (1, 2)))
    (5, 4)
    >>> fractionSum(((1, 13), (2, 17)))
    (43, 221)
    >>> fractionSum(())
    (0, 1)

    This method might seem like an easy place to optimize and simplify
    by just doing a fractions.Fraction() sum (I tried!), but not reducing to
    its lowest terms is a feature of this method. 3/8 + 3/8 = 6/8, not 3/4:

    >>> fractionSum(((3, 8), (3, 8)))
    (6, 8)
    r   r   )setr7   addlensummathlcmzip)
numDenomTuplenListdListdListUniquer1   r2   dRednRednSrcdSrcs
             r   fractionSumri      s    2 EE%K1QQ 
 ;1J!H1vxx%eU+JD$DDDL))D ,d|r   c                z    t        j                  |       j                  d      }|j                  |j                  fS )a.  
    Given a floating point proportional value between 0 and 1, return the
    best-fit slash-base fraction up to 16.

    >>> from music21.meter.tools import proportionToFraction
    >>> proportionToFraction(0.5)
    (1, 2)
    >>> proportionToFraction(0.25)
    (1, 4)
    >>> proportionToFraction(0.75)
    (3, 4)
    >>> proportionToFraction(0.125)
    (1, 8)
    >>> proportionToFraction(0.375)
    (3, 8)
    >>> proportionToFraction(0.625)
    (5, 8)
    >>> proportionToFraction(0.333)
    (1, 3)
    >>> proportionToFraction(0.83333)
    (5, 6)
    r   )	fractionsFractionlimit_denominatorr   r   )r-   fs     r   proportionToFractionro     s2    0 	5!33B7AKK''r   c                    g }|t         d   k  rC| dz  }|dz  }|t         d   k  r-|j                  | d|        |dz  }|dz  }|t         d   k  r-t        |      S )a  
    This simply gets restatements of the same fraction in smaller units,
    up to the largest valid denominator.

    >>> meter.tools.divisionOptionsFractionsUpward(2, 4)
    ('4/8', '8/16', '16/32', '32/64', '64/128')
    >>> meter.tools.divisionOptionsFractionsUpward(3, 4)
    ('6/8', '12/16', '24/32', '48/64', '96/128')

    Note that this returns a tuple of strings not MeterOptions
    rP   r   r?   validDenominatorsr7   r8   r1   r2   optsnModdMods        r   divisionOptionsFractionsUpwardrw   &  s|     DR  1u1u'++KK4&$()AIDAID '++ ;r   c                    g }|t         d   kD  r_| dz  dk(  rW| dz  }|dz  }|t         d   k\  rA|j                  | d|        |dz  dk7  r	 t        |      S |dz  }|dz  }|t         d   k\  rAt        |      S )a  
    Get restatements of the same fraction in larger units

    >>> meter.tools.divisionOptionsFractionsDownward(2, 4)
    ('1/2',)
    >>> meter.tools.divisionOptionsFractionsDownward(12, 16)
    ('6/8', '3/4')

    Note that this returns a tuple of strings not MeterOptions
    r   r   r?   rq   rs   s        r    divisionOptionsFractionsDownwardry   >  s     DQAEQJAvAv'**KK4&$()ax1} ; 19D19D '** ;r   c                    g }|t         d   k  rR| dk(  rMd}|dz  }|t         d   k  r:|j                  t        |  d| g|z               |dz  }|dz  }|t         d   k  r:t        |      S )z
    >>> meter.tools.divisionOptionsAdditiveMultiplesDownward(1, 16)
    (('1/32', '1/32'), ('1/64', '1/64', '1/64', '1/64'),
     ('1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128'))
    rP   r   r   r?   rq   )r1   r2   rt   rI   rv   s        r   (divisionOptionsAdditiveMultiplesDownwardr{   V  s     DR  Q!V1u'++KK!AdV}o123!8DFA '++ ;r   c                    g }| dkD  rO| dz  dk(  rGd}|}| |z  }|dkD  r9t        | d| g|z        }||vr|j                  |       ||z  }||z  }|dkD  r9t        |      S )z
    Additive multiples with the same denominators.

    >>> meter.tools.divisionOptionsAdditiveMultiples(4, 16)
    (('2/16', '2/16'),)
    >>> meter.tools.divisionOptionsAdditiveMultiples(6, 4)
    (('3/4', '3/4'),)
       r   r   r   r?   )r8   r7   )r1   r2   rt   divrI   ru   seqs          r    divisionOptionsAdditiveMultiplesr   h  s     D1uQ!CxQhD61#!+,C$C 3;DHA Qh ;r   c                   g }| dz  dk(  rq|dz  dk\  ri| dz  }|dz  }|dk\  rZ|dkD  rU|j                  t        d d| gt        |      z               |dz  dk7  r	 t        |      S |dz  }|dz  }|dk\  r|dkD  rUt        |      S )a  
    >>> meter.tools.divisionOptionsAdditiveMultiplesEvenDivision(4, 16)
    (('1/8', '1/8'),)
    >>> meter.tools.divisionOptionsAdditiveMultiplesEvenDivision(4, 4)
    (('1/2', '1/2'),)
    >>> meter.tools.divisionOptionsAdditiveMultiplesEvenDivision(3, 4)
    ()
    r   r   r   r?   )r7   r8   r   rs   s        r   ,divisionOptionsAdditiveMultiplesEvenDivisionr     s     D 	1uza1fkAvAvaiD1HKK!AdV}oD	9:;ax1} ; 19D19D aiD1H ;r   c                    g }| dkD  rc|dk\  r^|}| }| dkD  r| }nd}|t         d   k  rD||k  r?d| g|z  }|j                  t        |             |dz  }|dz  }|t         d   k  r||k  r?t        |      S )a=  
    >>> meter.tools.divisionOptionsAdditiveMultiplesUpward(4, 16)
    (('1/16', '1/16', '1/16', '1/16'),
     ('1/32', '1/32', '1/32', '1/32', '1/32', '1/32', '1/32', '1/32'),
     ('1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64',
      '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64'))
    >>> meter.tools.divisionOptionsAdditiveMultiplesUpward(3, 4)
    (('1/4', '1/4', '1/4'),
     ('1/8', '1/8', '1/8', '1/8', '1/8', '1/8'),
     ('1/16', '1/16', '1/16', '1/16', '1/16', '1/16',
      '1/16', '1/16', '1/16', '1/16', '1/16', '1/16'))
    r   r   rP   1/r   rq   )r1   r2   rt   dCurrentnCountnCountLimitr   s          r   &divisionOptionsAdditiveMultiplesUpwardr     s     D1uar6KK +B//Fk4Iz?#f,CKKc
#MHaKF +B//Fk4I ;r   c                v   g }| dz  dk(  rQ| dkD  rLg }t        t        | dz              D ]  }|j                  d|         |j                  t        |             | dk(  r@dD ];  }g }|D ]  }|j                  | d|         |j                  t        |             = | dk(  r@dD ];  }g }|D ]  }|j                  | d|         |j                  t        |             = | d	k(  r@d
D ];  }g }|D ]  }|j                  | d|         |j                  t        |             = |j	                  t        | |             |j	                  t        | |             |j                  |  d| f       |j	                  t        | |             |j	                  t        | |             |j	                  t        | |      D cg c]  }|f c}       |j	                  t        | |      D cg c]  }|f c}       t        t        j                  j                  d |D                    S c c}w c c}w )ad  
    This is a primitive approach to algorithmic division production.
    This can be extended.

    It is assumed that these values are provided in order of priority

    >>> meter.tools.divisionOptionsAlgo(4, 4)
    (('1/4', '1/4', '1/4', '1/4'),
     ('1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8'),
     ('1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16',
      '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16'),
     ('1/2', '1/2'),
     ('4/4',),
     ('2/4', '2/4'),
     ('2/2',),
     ('1/1',),
     ('8/8',),
     ('16/16',),
     ('32/32',),
     ('64/64',),
     ('128/128',))

    >>> meter.tools.divisionOptionsAlgo(1, 4)
    (('1/4',),
     ('1/8', '1/8'),
     ('1/16', '1/16', '1/16', '1/16'),
     ('1/32', '1/32', '1/32', '1/32', '1/32', '1/32', '1/32', '1/32'),
     ('1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64',
      '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64'),
     ('1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128',
      '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128',
      '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128',
      '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128', '1/128'),
     ('2/8',), ('4/16',), ('8/32',), ('16/64',), ('32/128',))

    >>> meter.tools.divisionOptionsAlgo(2, 2)
    (('1/2', '1/2'),
     ('1/4', '1/4', '1/4', '1/4'),
     ('1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8'),
     ('1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16',
      '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16'),
     ('2/2',),
     ('1/1',),
     ('4/4',), ('8/8',), ('16/16',), ('32/32',), ('64/64',), ('128/128',))

    >>> meter.tools.divisionOptionsAlgo(3, 8)
    (('1/8', '1/8', '1/8'), ('1/16', '1/16', '1/16', '1/16', '1/16', '1/16'),
     ('1/32', '1/32', '1/32', '1/32', '1/32', '1/32',
      '1/32', '1/32', '1/32', '1/32', '1/32', '1/32'),
     ('3/8',), ('6/16',), ('12/32',), ('24/64',), ('48/128',))

    >>> meter.tools.divisionOptionsAlgo(6, 8)
    (('3/8', '3/8'),
     ('1/8', '1/8', '1/8', '1/8', '1/8', '1/8'),
     ('1/16', '1/16', '1/16', '1/16', '1/16', '1/16',
      '1/16', '1/16', '1/16', '1/16', '1/16', '1/16'),
     ('1/4', '1/4', '1/4'),
     ('6/8',),
     ('3/4',),
     ('12/16',), ('24/32',), ('48/64',), ('96/128',))

    >>> meter.tools.divisionOptionsAlgo(12, 8)
    (('3/8', '3/8', '3/8', '3/8'),
     ('1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8', '1/8'),
     ('1/4', '1/4', '1/4', '1/4', '1/4', '1/4'),
     ('1/2', '1/2', '1/2'),
     ('12/8',),
     ('6/8', '6/8'),
     ('6/4',),
     ('3/2',),
     ('24/16',), ('48/32',), ('96/64',), ('192/128',))

    >>> meter.tools.divisionOptionsAlgo(5, 8)
    (('2/8', '3/8'),
     ('3/8', '2/8'),
     ('1/8', '1/8', '1/8', '1/8', '1/8'),
     ('1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16', '1/16'),
     ('5/8',),
     ('10/16',), ('20/32',), ('40/64',), ('80/128',))

    >>> meter.tools.divisionOptionsAlgo(18, 4)
    (('3/4', '3/4', '3/4', '3/4', '3/4', '3/4'),
     ('1/4', '1/4', '1/4', '1/4', '1/4', '1/4', '1/4', '1/4', '1/4', '1/4',
      '1/4', '1/4', '1/4', '1/4', '1/4', '1/4', '1/4', '1/4'),
     ('1/2', '1/2', '1/2', '1/2', '1/2', '1/2', '1/2', '1/2', '1/2'),
     ('18/4',),
     ('9/4', '9/4'),
     ('4/4', '4/4', '4/4', '4/4'),
     ('2/4', '2/4', '2/4', '2/4', '2/4', '2/4', '2/4', '2/4'),
     ('9/2',),
     ('36/8',),
     ('72/16',),
     ('144/32',),
     ('288/64',),
     ('576/128',))

    >>> meter.tools.divisionOptionsAlgo(3, 128)
    (('1/128', '1/128', '1/128'), ('3/128',))
    r}   r   z3/   ))r   r}   )r}   r   r?      ))r   r   r}   )r}   r   r   )r   r}   r   
   ))r   r   r}   r}   c              3  ,   K   | ]  }|d k7  s	|  yw)r   Nr   ).0os     r   	<genexpr>z&divisionOptionsAlgo.<locals>.<genexpr>P  s     #?t!qBwAts   
)ranger   r7   r8   extendr   r   r   r{   ry   rw   r   miscunique)r1   r2   rt   r   jr,   ru   r   s           r   divisionOptionsAlgor     s   J D 	1uza!es1q5z"AJJA3x  #E#JAv%EC

dV1QC=) KKc
#	 &
 	Av6EC

dV1QC=) KKc
#	 7 	Bw$EC

dV1QC=) KKc
#	 % 	KK6q!<= 	KK<QBCKKA3as 	KK0A67 	KK8A>?KK?1EFE!!EFGKK=aCDC!!CDE###?t#??@@ GDs   
H11
H6c                    g }| dk(  r:|j                  d| d| d| f       |j                  d| d| d| f       t        |      S )a  
    Provide fixed set of meter divisions that will not be easily
    obtained algorithmically.

    Currently, does nothing except to allow partitioning 5/8 as 2/8, 2/8, 1/8 as a possibility
    (sim for 5/16, etc.)

    >>> meter.tools.divisionOptionsPreset(5, 8)
    (('2/8', '2/8', '1/8'), ('2/8', '1/8', '2/8'))
    >>> meter.tools.divisionOptionsPreset(3, 4)
    ()

    >>> ms2 = meter.MeterSequence('5/32')
    >>> ms2.getPartitionOptions()
    (('2/32', '3/32'), ('3/32', '2/32'), ('1/32', '1/32', '1/32', '1/32', '1/32'),
     ('1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64', '1/64'),
     ('5/32',), ('10/64',), ('20/128',), ('2/32', '2/32', '1/32'), ('2/32', '1/32', '2/32'))
    r   z2/r   )r7   r8   )r1   r2   rt   s      r   divisionOptionsPresetr   S  sd    ( DAvr!XA3x2aS23r!XA3x2aS23;r   __main__)r-   rQ   returnr   )r-   rQ   r   NumDenomTuple)rD   rQ   r   ztuple[NumDenomTuple, bool])rS   r   r   ztuple[tuple[str, int], ...])ra   r   r   NumDenom)r-   floatr   r   )r1   r   r2   r   r   ztuple[str, ...])r1   r   r2   r   r   MeterOptions)r1   r   r2   r   r   ztuple[tuple[str, ...], ...])r   r   )/
__future__r   rk   	functoolsr   r^   r*   typingtmusic21r   music21.common.enumsr   r   music21.exceptions21r   r	   r
   EnvironmentenvironLocal
NamedTupler   r8   r   r   r   rQ   r   rr   	frozensetvalidDenominatorsSetr3   r=   rN   rX   ri   ro   rw   ry   r{   r   r   r   r   r   r   mainTestr   r   r   <module>r      s   #    	   .  Y Y&{&&}5  c?hm$U38_c)*1  !23  3!V !VH 3 2 3J( J(Z 3 @ 3, ,^ 3( (>00$.0@ 3XA XAv 3 6 zG r   