
    3jB                    J   d 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                  d
      Z G d dej                        Z G d d      Z G d d      Z G d dej&                        ZegZedk(  rddlZ ej.                  e       yy)an  
This module describes classes for performing windowed and overlapping windowed analysis.
The :class:`music21.analysis.windowed.WindowedAnalysis` provides a reusable framework for
systematic overlapping window analysis at the starting at the level of the quarter note
and moving to the size of an entire :class:`music21.stream.Stream`.

Modular analysis procedures inherit from :class:`music21.analysis.discrete.DiscreteAnalysis`.
The :class:`music21.analysis.discrete.KrumhanslSchmuckler` (for algorithmic key detection)
and :class:`music21.analysis.discrete.Ambitus` (for pitch range analysis) classes provide examples.
    )annotationsN)exceptions21)common)environment)meter)stream)DiscreteAnalysisExceptionzanalysis.windowedc                      e Zd Zy)WindowedAnalysisExceptionN)__name__
__module____qualname__     F/DATA/.local/lib/python3.12/site-packages/music21/analysis/windowed.pyr   r   '   s    r   r   c                  D    e Zd ZdZd ZddZddZ	 	 	 	 	 d		 	 	 	 	 d
dZy)WindowedAnalysisa  
    Create a WindowedAnalysis object.

    The provided `analysisProcessor` must provide a `process()` method that,
    when given a windowed Stream (a Measure) returns two element tuple containing
    (a) a data value (implementation dependent) and (b) a color code.
    c                    || _         t        |t        j                        st	        d      |j                         r|j                         }|| _        | j                         | _	        y )Nznon-stream provided as argument)
	processor
isinstancer   Streamr   hasPartLikeStreamsflatten
_srcStreamgetMinimumWindowStream_windowedStream)self	streamObjanalysisProcessors      r   __init__zWindowedAnalysis.__init__6   sU    *)V]]3+,MNN'')!))+I##::<r   c                   t        j                         }|j                  dt        j                  |             | j
                  j                  |      }|j                  d       |st        d      |j                  d       |S )a-  
        Take the loaded stream and restructure it into measures of 1 quarter note duration.

        >>> s = corpus.parse('bach/bwv324')
        >>> p = analysis.discrete.Ambitus()

        Placing one part into analysis:

        >>> wa = analysis.windowed.WindowedAnalysis(s.parts[0], p)

        >>> post = wa.getMinimumWindowStream()
        >>> len(post.getElementsByClass(stream.Measure))
        42
        >>> post.getElementsByClass(stream.Measure).first()
        <music21.stream.Measure 1 offset=0.0>

        Time signature set to 1/4 time signature

        >>> post.getElementsByClass(stream.Measure).first().timeSignature
        <music21.meter.TimeSignature 1/4>

        leaves one note in this measure

        >>> len(post.getElementsByClass(stream.Measure)[1].notes)
        1

        Placing a score with parts into analysis will automatically flatten
        the stream.  So these two calls are equivalent:

        >>> wa1 = analysis.windowed.WindowedAnalysis(s, p)
        >>> wa2 = analysis.windowed.WindowedAnalysis(s.flatten(), p)

        r   )meterStreamMeasurezMaking measures failedT)inPlace)
r   r   insertr   TimeSignaturer   makeMeasuresremoveByNotOfClassr   makeTies)r   timeSignaturer"   measureds       r   r   z'WindowedAnalysis.getMinimumWindowStreamA   sy    H mmo1e11-@A
 ??//K/H 	##I.+,DEE$'r   c                   t        | j                        }|dk(  r	||z
  dz   }nU|dk(  r0||z  dz   }t        |      }||k7  r8t        j                  dd       n |dk(  r|}nt        j                  d|       d	g|z  }d	g|z  }t        |      }|dk(  rv|D ]m  }	t        j                         }
t        |	|	|z         D ]   }|
j                  | j                  |          " 	 | j                  j                  |
      \  ||	<   ||	<   o ||fS |dk(  rd	}||z   }t        |      D ]  }	t        |t        | j                              }t        j                         }
t        ||      D ]   }|
j                  | j                  |          " 	 | j                  j                  |
      \  ||	<   ||	<   |}||z   } ||fS |dk(  rg }t        ||z
  dz         D ]n  }	t        j                         }
g }t        |	|	|z         D ]1  }|
j                  | j                  |          |j                  |       3 |j                  |
|g       p t        |      D ]b  }	t        j                         }
|D ]"  \  }}|	|v s|D ]  }|
j                  |        $ 	 | j                  j                  |
      \  ||	<   ||	<   d ||fS # t        $ r d
\  ||	<   ||	<   Y 6w xY w# t        $ r d
\  ||	<   ||	<   Y <w xY w# t        $ r d
\  ||	<   ||	<   Y w xY w)a~  
        Calls, for a given window size, an analysis method across all windows in the source Stream.

        If windowType is "overlap", windows above size 1 are always overlapped, so if a window
        of size 2 is used, windows 1-2, then 2-3, then 3-4 are compared. If a window of size 3
        is used, windows 1-3, then 2-4, then 3-5 are compared.

        Windows are assumed to be partitioned by :class:`music21.stream.Measure` objects.

        Returns two lists for results, each equal in size to the length of minimum windows
        minus the window size plus one. If we have 20 1/4 windows, then the results lists
        will be of length 20 for window size 1, 19 for window size 2, 18 for window size 3, etc.

        >>> s = corpus.parse('bach/bwv66.6')
        >>> p = analysis.discrete.Ambitus()
        >>> wa = analysis.windowed.WindowedAnalysis(s.flatten(), p)
        >>> len(wa._windowedStream)
        36
        >>> a, b = wa.analyze(1)
        >>> len(a), len(b)
        (36, 36)

        >>> a, b = wa.analyze(4)
        >>> len(a), len(b)
        (33, 33)

        >>> a, b = wa.analyze(1, windowType='noOverlap')
        >>> len(a), len(b)
        (37, 37)

        >>> a, b = wa.analyze(4, windowType='noOverlap')
        >>> len(a), len(b)
        (10, 10)

        >>> a, b = wa.analyze(1, windowType='adjacentAverage')
        >>> len(a), len(b)
        (36, 36)

        overlap   	noOverlapzJmaxWindowCount is not divisible by windowSize, possibly undefined behavior   )
stackleveladjacentAveragezUnknown windowType: r   ))NNr   z#ffffff)lenr   intwarningswarnr   Music21Exceptionranger   r   appendr   processr	   min)r   
windowSize
windowTypemaxWindowCountwindowCountwindowCountFloatdatacolorwindowCountIndicesicurrentjstartend
overlappedparticipants
dataStreamms                     r   analyzezWindowedAnalysis.analyzet   s^   P T112 "(:59K;&-
:Q>./K;.`  ,,(K//2Fzl0STTs[ k!";/"' --/q!j.1ANN4#7#7#:; 2C(,(>(>w(G%DGU1X (r U{[ ;&E*$C;'#s4#7#789 --/uc*ANN4#7#7#:; +C(,(>(>w(G%DGU1X
 j( (T U{5 ,,J>J6:; --/!q!j.1ANN4#7#7#:; ''* 2 !!7L"9: < >* --/0:,JL(!+A#NN1- ", 1;C(,(>(>w(G%DGU1X + U{c 1 C(B%DGU1XC  1 C(B%DGU1XC: 1 C(B%DGU1XCs6   !$J6$K$K,6KKK)(K),LLc                   |t        | j                        }n|}|t        | j                        }n|}|d}n>|j                         dv rd}n)|j                         dv rd}n|j                         dv rd}g }g }	g }
t        |t              rt        t        ||dz   |            }nOt        j                  |      \  }}g }|}	 |j                  |       |t        t	        |            z  }||dz  kD  rn2|r*t        | j                        }||vr|j                  |       |D ]O  }| j                  ||	      \  }}|j                  |       |	j                  |       d
|i}|
j                  |       Q ||	|
fS )a   
        Main method for windowed analysis across one or more window sizes.

        Calls :meth:`~music21.analysis.WindowedAnalysis.analyze` for
        the number of different window sizes to be analyzed.

        The `minWindow` and `maxWindow` set the range of window sizes in quarter lengths.
        The `windowStepSize` parameter determines the increment between these window sizes,
        in quarter lengths.

        If `minWindow` or `maxWindow` is None, the largest window size available will be set.

        If `includeTotalWindow` is True, the largest window size will always be added.

        >>> s = corpus.parse('bach/bwv324')
        >>> ksAnalyzer = analysis.discrete.KrumhanslSchmuckler()

        placing one part into analysis

        >>> sopr = s.parts[0]
        >>> wa = analysis.windowed.WindowedAnalysis(sopr, ksAnalyzer)
        >>> solutions, colors, meta = wa.process(1, 1, includeTotalWindow=False)
        >>> len(solutions)  # we only have one series of windows
        1

        >>> solutions, colors, meta = wa.process(1, 2, includeTotalWindow=False)
        >>> len(solutions)  # we have two series of windows
        2

        >>> solutions[1]
        [(<music21.pitch.Pitch B>, 'major', 0.6844...),
         (<music21.pitch.Pitch B>, 'minor', 0.8308...),
         (<music21.pitch.Pitch D>, 'major', 0.6844...),
         (<music21.pitch.Pitch B>, 'minor', 0.8308...),...]

        >>> colors[1]
        ['#ffb5ff', '#9b519b', '#ffd752', '#9b519b', ...]

        >>> meta
        [{'windowSize': 1}, {'windowSize': 2}]
        r-   r-   )	nooverlapnonoverlappingr/   )adjacentaverager2   r.   g      ?)r=   r<   )r3   r   lowerr   r4   listr8   r   getNumFromStrr9   roundrM   )r   	minWindow	maxWindowwindowStepSizer=   includeTotalWindow	maxLength	minLengthsolutionMatrixcolorMatrix
metaMatrixwindowSizesnumjunkxtotalWindowrD   solution	colorNamemetas                       r   r:   zWindowedAnalysis.process   s   ` D001I!ID001I!I"J;."J#BB$J#66*J 
nc*uY	A~NOK,,^<ICKA""1%c#h'	D()	  d223K+-"";/A #',,qZ,"HHi!!(+y) !$Dd#  {J66r   N)z1/4rO   )r.   r.   r.   r-   T)rW   
int | NonerX   rh   rY   z	int | str)r   r   r   __doc__r    r   rM   r:   r   r   r   r   r   -   sM    	=1fyz '(&'*+$#'e7#e7#e7 !(e7r   r   c                      e Zd Zd Zy)MockObjectProcessorc                L    t        |j                         j                        dfS )z8
        Simply count the number of notes found
        N)r3   r   notesAndRests)r   	subStreams     r   r:   zMockObjectProcessor.process\  s#     9$$&445t;;r   N)r   r   r   r:   r   r   r   rk   rk   Z  s    <r   rk   c                  $    e Zd Zd Zd Zd Zd Zy)Testc                2    ddl m}  || t                      y )Nr   )testCopyAll)music21.test.commonTestrr   globals)r   rr   s     r   testCopyAndDeepcopyzTest.testCopyAndDeepcopyd  s    7D')$r   c                "   ddl m} ddlm} |j	                  d      }|j
                  |j                  fD ]W  } |       }t        |j                         |      }t        t        dd            d gz   D ]  }|j                  ||      \  }}	}
 Y y )Nr   corpusdiscretezbach/bwv324r.      )music21rx   music21.analysisrz   parseKrumhanslSchmucklerAmbitusr   r   rT   r8   r:   )r   rx   rz   spClasspwarD   unused_xunused_yunused_zs              r   	testBasiczTest.testBasich  s    "- LL'33X5E5EFFA "!))+q1B%1+&$//1zz!Q/?,(H 0 Gr   c                <   t               }ddlm} t        j                         }|j                  |j                  d             |j                  |j                  d             t        j                         }|j                  |j                  d             |j                  |j                  d             |j                  |j                  d             |j                  |j                  d             |j                  |j                  d             |j                  |j                  d             |j                  |j                  d	             |j                  |j                  d             t        ||      }t        ||      }| j                  t        |j                        d
       | j                  t        |j                        d       |j                  dddd      \  }}}	| j                  t        |d         d
       | j                  |d   d   d       | j                  |d   d   d       |j                  d
d
dd      \  }}}	| j                  t        |d         d       | j                  |d   d   d
       |j                  dddd      \  }}}	| j                  t        |d         d       | j                  |d   d   d       | j                  |d   d   d       |j                  d
d
dd      \  }}}	| j                  t        |d         d       |j                  dddd      \  }}}	| j                  t        |d         d
       |j                  dddd      \  }}}	| j                  t        |d         d       y)zJ
        Test that windows are doing what they are supposed to do
        r   )noteCDEFGABr0      r.   F)rZ      N)rk   r|   r   r   r   r9   Noter   assertEqualr3   r   r:   )
r   r   r   s1s2wa1wa2aunused_bunused_cs
             r   testWindowingzTest.testWindowingy  s     ! ]]_
		$))C.!
		$))C.!]]_
		$))C.!
		$))C.!
		$))C.!
		$))C.!
		$))C.!
		$))C.!
		$))C.!
		$))C.!r1%r1% 	S00115S00115 !$Aq! N8XQqTA&1a!$1a!$ !$Aq! N8XQqTA&1a!$ !$Aq! N8XQqTA&1a!$1a!$ !$Aq! N8XQqTA& !$Aq! N8XQqTA& !$Aq! N8XQqTA&r   c                   ddl m} ddlm} ddlm} |j                         }|j                  d      }t        |j                         |      }|j                  j                  |j                         d dd      }|j                          y )	Nr   ry   rw   )graphzbach/bwv66.6r{   r-   )
doneAction
windowStepr=   )r}   rz   r|   rx   r   r   r~   r   r   plotWindowedKeyrun)r   rz   rx   r   r   r   	unused_war   s           r   testVariableWindowingzTest.testVariableWindowing  sk    -"!((*LL($QYY[!4	zz%%aiikd12y & J
r   N)r   r   r   ru   r   r   r   r   r   r   rp   rp   c  s    %@"8'vr   rp   __main__)ri   
__future__r   unittestr5   r|   r   r   r   r   r   music21.analysis.discreter	   EnvironmentenvironLocalr7   r   r   rk   TestCaserp   
_DOC_ORDERr   mainTestr   r   r   <module>r      s   	 #         ?&{&&':;	 = = 	h7 h7Z	< <]8 ]F 
zGT r   