
    }KgP                        d Z ddlZddlZddlm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mZmZmZmZmZ ddlmZmZ g dZddddddej8                  dee   dee   dedededeej8                  ej8                  f   fdZ  ed      ddddddej8                  deeeeef   ee   f   de!d ed!eeeeef   ee   f   deej8                  ej8                  f   fd"       Z" ed      ddd#d$dej8                  d%eeejF                  jH                  ej8                  f      d&ee   d'ededej8                  fd(       Z%dej8                  d&edej8                  fd)Z&y)*z
Spectrogram decomposition
=========================
.. autosummary::
    :toctree: generated/

    decompose
    hpss
    nn_filter
    N)median_filter   )core)cache)segment)util)ParameterError)AnyCallableListOptionalTupleUnion)_IntLike_co_FloatLike_co)	decomposehpss	nn_filterFT)n_componentstransformersortfitSr   r   r   r   kwargsreturnc                n   t        | j                        }| j                  dkD  r|rt        d      | j                  j                  | j                  d   dfd      } || j                  d   }|0|du rt        d      t        j                  j                  dd	|i|}|r|j                  |       j                  }n|j                  |       j                  }|j                  }|dd dgz   }	|j                  |	ddd   d      j                  }|rt        j                  |d
      \  }}
||
   }||fS )a  Decompose a feature matrix.

    Given a spectrogram ``S``, produce a decomposition into ``components``
    and ``activations`` such that ``S ~= components.dot(activations)``.

    By default, this is done with with non-negative matrix factorization (NMF),
    but any `sklearn.decomposition`-type object will work.

    Parameters
    ----------
    S : np.ndarray [shape=(..., n_features, n_samples), dtype=float]
        The input feature matrix (e.g., magnitude spectrogram)

        If the input has multiple channels (leading dimensions), they will be automatically
        flattened prior to decomposition.

        If the input is multi-channel, channels and features are automatically flattened into
        a single axis before the decomposition.
        For example, a stereo input `S` with shape `(2, n_features, n_samples)` is
        automatically reshaped to `(2 * n_features, n_samples)`.

    n_components : int > 0 [scalar] or None
        number of desired components

        if None, then ``n_features`` components are used

    transformer : None or object
        If None, use `sklearn.decomposition.NMF`

        Otherwise, any object with a similar interface to NMF should work.
        ``transformer`` must follow the scikit-learn convention, where
        input data is ``(n_samples, n_features)``.

        `transformer.fit_transform()` will be run on ``S.T`` (not ``S``),
        the return value of which is stored (transposed) as ``activations``

        The components will be retrieved as ``transformer.components_.T``::

            S ~= np.dot(activations, transformer.components_).T

        or equivalently::

            S ~= np.dot(transformer.components_.T, activations.T)

    sort : bool
        If ``True``, components are sorted by ascending peak frequency.

        .. note:: If used with ``transformer``, sorting is applied to copies
            of the decomposition parameters, and not to ``transformer``
            internal parameters.

        .. warning:: If the input array has more than two dimensions
            (e.g., if it's a multi-channel spectrogram), then axis sorting
            is not supported and a `ParameterError` exception is raised.

    fit : bool
        If `True`, components are estimated from the input ``S``.

        If `False`, components are assumed to be pre-computed and stored
        in ``transformer``, and are not changed.

    **kwargs : Additional keyword arguments to the default transformer
        `sklearn.decomposition.NMF`

    Returns
    -------
    components: np.ndarray [shape=(..., n_features, n_components)]
        matrix of components (basis elements).
    activations: np.ndarray [shape=(n_components, n_samples)]
        transformed matrix/activation matrix

    Raises
    ------
    ParameterError
        if ``fit`` is False and no ``transformer`` object is provided.

        if the input array is multi-channel and ``sort=True`` is specified.

    See Also
    --------
    sklearn.decomposition : SciKit-Learn matrix decomposition modules

    Examples
    --------
    Decompose a magnitude spectrogram into 16 components with NMF

    >>> y, sr = librosa.load(librosa.ex('pistachio'), duration=5)
    >>> S = np.abs(librosa.stft(y))
    >>> comps, acts = librosa.decompose.decompose(S, n_components=16)

    Sort components by ascending peak frequency

    >>> comps, acts = librosa.decompose.decompose(S, n_components=16,
    ...                                           sort=True)

    Or with sparse dictionary learning

    >>> import sklearn.decomposition
    >>> T = sklearn.decomposition.MiniBatchDictionaryLearning(n_components=16)
    >>> scomps, sacts = librosa.decompose.decompose(S, transformer=T, sort=True)

    >>> import matplotlib.pyplot as plt
    >>> layout = [list(".AAAA"), list("BCCCC"), list(".DDDD")]
    >>> fig, ax = plt.subplot_mosaic(layout, constrained_layout=True)
    >>> librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
    ...                          y_axis='log', x_axis='time', ax=ax['A'])
    >>> ax['A'].set(title='Input spectrogram')
    >>> ax['A'].label_outer()
    >>> librosa.display.specshow(librosa.amplitude_to_db(comps,
    >>>                                                  ref=np.max),
    >>>                          y_axis='log', ax=ax['B'])
    >>> ax['B'].set(title='Components')
    >>> ax['B'].label_outer()
    >>> ax['B'].sharey(ax['A'])
    >>> librosa.display.specshow(acts, x_axis='time', ax=ax['C'], cmap='gray_r')
    >>> ax['C'].set(ylabel='Components', title='Activations')
    >>> ax['C'].sharex(ax['A'])
    >>> ax['C'].label_outer()
    >>> S_approx = comps.dot(acts)
    >>> img = librosa.display.specshow(librosa.amplitude_to_db(S_approx,
    >>>                                                        ref=np.max),
    >>>                                y_axis='log', x_axis='time', ax=ax['D'])
    >>> ax['D'].set(title='Reconstructed spectrogram')
    >>> ax['D'].sharex(ax['A'])
    >>> ax['D'].sharey(ax['A'])
    >>> ax['D'].label_outer()
    >>> fig.colorbar(img, ax=list(ax.values()), format="%+2.f dB")
       zJParameter sort=True is unsupported for input with more than two dimensionsF)orderNFz'fit must be True if transformer is Noner   T)index )listshapendimr	   TreshapesklearndecompositionNMFfit_transform	transformcomponents_r   	axis_sort)r   r   r   r   r   r   
orig_shapeactivations
componentscomponent_shapeidxs              U/home/alanp/www/video.onchill/myenv/lib/python3.12/site-packages/librosa/decompose.pyr   r       s<   T aggJvvzdX
 	
 	
QWWR["%S1Awwr{%< !JKK++//T\TVT
 !//244!++A.00(44J "o,O##ODbD$9#EGGJ..4@
C!#&{""       )level   g       @g      ?)kernel_sizepowermaskmarginr9   r:   r;   r<   c                   t        j                  |       rt        j                  |       \  } }nd}t	        |t
              st	        |t              r|d   }|d   }n|}|}t	        |t
              st	        |t              r|d   }|d   }	n|}|}	|dk  s|	dk  rt        d      dg| j                  z  }
||
d<   dg| j                  z  }||d<   t        j                  |       }t        | |
d      |dd t        j                  |       }t        | |d      |dd |dk(  xr |	dk(  }t        j                  |||z  ||	      }t        j                  |||	z  ||	      }|r||fS | |z  |z  | |z  |z  fS )
u  Median-filtering harmonic percussive source separation (HPSS).

    If ``margin = 1.0``, decomposes an input spectrogram ``S = H + P``
    where ``H`` contains the harmonic components,
    and ``P`` contains the percussive components.

    If ``margin > 1.0``, decomposes an input spectrogram ``S = H + P + R``
    where ``R`` contains residual components not included in ``H`` or ``P``.

    This implementation is based upon the algorithm described by [#]_ and [#]_.

    .. [#] Fitzgerald, Derry.
        "Harmonic/percussive separation using median filtering."
        13th International Conference on Digital Audio Effects (DAFX10),
        Graz, Austria, 2010.

    .. [#] Driedger, Müller, Disch.
        "Extending harmonic-percussive separation of audio."
        15th International Society for Music Information Retrieval Conference (ISMIR 2014),
        Taipei, Taiwan, 2014.

    Parameters
    ----------
    S : np.ndarray [shape=(..., d, n)]
        input spectrogram. May be real (magnitude) or complex.
        Multi-channel is supported.

    kernel_size : int or tuple (kernel_harmonic, kernel_percussive)
        kernel size(s) for the median filters.

        - If scalar, the same size is used for both harmonic and percussive.
        - If tuple, the first value specifies the width of the
          harmonic filter, and the second value specifies the width
          of the percussive filter.

    power : float > 0 [scalar]
        Exponent for the Wiener filter when constructing soft mask matrices.

    mask : bool
        Return the masking matrices instead of components.

        Masking matrices contain non-negative real values that
        can be used to measure the assignment of energy from ``S``
        into harmonic or percussive components.

        Components can be recovered by multiplying ``S * mask_H``
        or ``S * mask_P``.

    margin : float or tuple (margin_harmonic, margin_percussive)
        margin size(s) for the masks (as described in [2]_)

        - If scalar, the same size is used for both harmonic and percussive.
        - If tuple, the first value specifies the margin of the
          harmonic mask, and the second value specifies the margin
          of the percussive mask.

    Returns
    -------
    harmonic : np.ndarray [shape=(..., d, n)]
        harmonic component (or mask)
    percussive : np.ndarray [shape=(..., d, n)]
        percussive component (or mask)

    See Also
    --------
    librosa.util.softmask

    Notes
    -----
    This function caches at level 30.

    Examples
    --------
    Separate into harmonic and percussive

    >>> y, sr = librosa.load(librosa.ex('choice'), duration=5)
    >>> D = librosa.stft(y)
    >>> H, P = librosa.decompose.hpss(D)

    >>> import matplotlib.pyplot as plt
    >>> fig, ax = plt.subplots(nrows=3, sharex=True, sharey=True)
    >>> img = librosa.display.specshow(librosa.amplitude_to_db(np.abs(D),
    ...                                                        ref=np.max),
    ...                          y_axis='log', x_axis='time', ax=ax[0])
    >>> ax[0].set(title='Full power spectrogram')
    >>> ax[0].label_outer()
    >>> librosa.display.specshow(librosa.amplitude_to_db(np.abs(H),
    ...                                                  ref=np.max(np.abs(D))),
    ...                          y_axis='log', x_axis='time', ax=ax[1])
    >>> ax[1].set(title='Harmonic power spectrogram')
    >>> ax[1].label_outer()
    >>> librosa.display.specshow(librosa.amplitude_to_db(np.abs(P),
    ...                                                  ref=np.max(np.abs(D))),
    ...                          y_axis='log', x_axis='time', ax=ax[2])
    >>> ax[2].set(title='Percussive power spectrogram')
    >>> fig.colorbar(img, ax=ax, format='%+2.0f dB')

    Or with a narrower horizontal filter

    >>> H, P = librosa.decompose.hpss(D, kernel_size=(13, 31))

    Just get harmonic/percussive masks, not the spectra

    >>> mask_H, mask_P = librosa.decompose.hpss(D, mask=True)
    >>> mask_H
    array([[1.853e-03, 1.701e-04, ..., 9.922e-01, 1.000e+00],
           [2.316e-03, 2.127e-04, ..., 9.989e-01, 1.000e+00],
           ...,
           [8.195e-05, 6.939e-05, ..., 3.105e-04, 4.231e-04],
           [3.159e-05, 4.156e-05, ..., 6.216e-04, 6.188e-04]],
          dtype=float32)
    >>> mask_P
    array([[9.981e-01, 9.998e-01, ..., 7.759e-03, 3.201e-05],
           [9.977e-01, 9.998e-01, ..., 1.122e-03, 4.451e-06],
           ...,
           [9.999e-01, 9.999e-01, ..., 9.997e-01, 9.996e-01],
           [1.000e+00, 1.000e+00, ..., 9.994e-01, 9.994e-01]],
          dtype=float32)

    Separate into harmonic/percussive/residual components by using a margin > 1.0

    >>> H, P = librosa.decompose.hpss(D, margin=3.0)
    >>> R = D - (H+P)
    >>> y_harm = librosa.istft(H)
    >>> y_perc = librosa.istft(P)
    >>> y_resi = librosa.istft(R)

    Get a more isolated percussive component by widening its margin

    >>> H, P = librosa.decompose.hpss(D, margin=(1.0,5.0))
    r   r   z<Margins must be >= 1.0. A typical range is between 1 and 10.r   reflect)sizemodeN)r:   split_zeros)npiscomplexobjr   magphase
isinstancetupler#   r	   r%   
empty_liker   r   softmask)r   r9   r:   r;   r<   phasewin_harmwin_percmargin_harmmargin_perc
harm_shape
perc_shapeharmpercrB   	mask_harm	mask_percs                    r4   r   r      s   d 
q==#5+u%K)Fq>q>&% Jvt$<QiQi Q+/M
 	

 &'C!&&LJJrN%&C!&&LJJrN ==DAJY?DG==DAJY?DG"7{a'7Kd[ ;I d[ ;I )##]e#a)mu%<==r5   r   )rec	aggregateaxisrU   rV   rW   c          	      ^   |t         j                  }|)t        |      }d|d<   t        j                  | fd|i|}nAt
        j                  j                  |      s t
        j                  j                  |      }n|}|j                  d   | j                  |   k7  s|j                  d   |j                  d   k7  r%t        d|j                   d| j                         t        |j                  |j                  |j                  | j                  d|      |      j                  d|      S )ay  Filter by nearest-neighbor aggregation.

    Each data point (e.g, spectrogram column) is replaced
    by aggregating its nearest neighbors in feature space.

    This can be useful for de-noising a spectrogram or feature matrix.

    The non-local means method [#]_ can be recovered by providing a
    weighted recurrence matrix as input and specifying ``aggregate=np.average``.

    Similarly, setting ``aggregate=np.median`` produces sparse de-noising
    as in REPET-SIM [#]_.

    .. [#] Buades, A., Coll, B., & Morel, J. M.
        (2005, June). A non-local algorithm for image denoising.
        In Computer Vision and Pattern Recognition, 2005.
        CVPR 2005. IEEE Computer Society Conference on (Vol. 2, pp. 60-65). IEEE.

    .. [#] Rafii, Z., & Pardo, B.
        (2012, October).  "Music/Voice Separation Using the Similarity Matrix."
        International Society for Music Information Retrieval Conference, 2012.

    Parameters
    ----------
    S : np.ndarray
        The input data (spectrogram) to filter. Multi-channel is supported.

    rec : (optional) scipy.sparse.spmatrix or np.ndarray
        Optionally, a pre-computed nearest-neighbor matrix
        as provided by `librosa.segment.recurrence_matrix`

    aggregate : function
        aggregation function (default: `np.mean`)

        If ``aggregate=np.average``, then a weighted average is
        computed according to the (per-row) weights in ``rec``.

        For all other aggregation functions, all neighbors
        are treated equally.

    axis : int
        The axis along which to filter (by default, columns)

    **kwargs
        Additional keyword arguments provided to
        `librosa.segment.recurrence_matrix` if ``rec`` is not provided

    Returns
    -------
    S_filtered : np.ndarray
        The filtered data, with shape equivalent to the input ``S``.

    Raises
    ------
    ParameterError
        if ``rec`` is provided and its shape is incompatible with ``S``.

    See Also
    --------
    decompose
    hpss
    librosa.segment.recurrence_matrix

    Notes
    -----
    This function caches at level 30.

    Examples
    --------
    De-noise a chromagram by non-local median filtering.
    By default this would use euclidean distance to select neighbors,
    but this can be overridden directly by setting the ``metric`` parameter.

    >>> y, sr = librosa.load(librosa.ex('brahms'),
    ...                      offset=30, duration=10)
    >>> chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
    >>> chroma_med = librosa.decompose.nn_filter(chroma,
    ...                                          aggregate=np.median,
    ...                                          metric='cosine')

    To use non-local means, provide an affinity matrix and ``aggregate=np.average``.

    >>> rec = librosa.segment.recurrence_matrix(chroma, mode='affinity',
    ...                                         metric='cosine', sparse=True)
    >>> chroma_nlm = librosa.decompose.nn_filter(chroma, rec=rec,
    ...                                          aggregate=np.average)

    >>> import matplotlib.pyplot as plt
    >>> fig, ax = plt.subplots(nrows=5, sharex=True, sharey=True, figsize=(10, 10))
    >>> librosa.display.specshow(chroma, y_axis='chroma', x_axis='time', ax=ax[0])
    >>> ax[0].set(title='Unfiltered')
    >>> ax[0].label_outer()
    >>> librosa.display.specshow(chroma_med, y_axis='chroma', x_axis='time', ax=ax[1])
    >>> ax[1].set(title='Median-filtered')
    >>> ax[1].label_outer()
    >>> imgc = librosa.display.specshow(chroma_nlm, y_axis='chroma', x_axis='time', ax=ax[2])
    >>> ax[2].set(title='Non-local means')
    >>> ax[2].label_outer()
    >>> imgr1 = librosa.display.specshow(chroma - chroma_med,
    ...                          y_axis='chroma', x_axis='time', ax=ax[3])
    >>> ax[3].set(title='Original - median')
    >>> ax[3].label_outer()
    >>> imgr2 = librosa.display.specshow(chroma - chroma_nlm,
    ...                          y_axis='chroma', x_axis='time', ax=ax[4])
    >>> ax[4].label_outer()
    >>> ax[4].set(title='Original - NLM')
    >>> fig.colorbar(imgc, ax=ax[:3])
    >>> fig.colorbar(imgr1, ax=[ax[3]])
    >>> fig.colorbar(imgr2, ax=[ax[4]])
    TsparserW   r   r   z/Invalid self-similarity matrix shape rec.shape=z for S.shape=)rC   meandictr   recurrence_matrixscipyrY   issparse
csc_matrixr$   r	   __nn_filter_helperdataindicesindptrswapaxes)r   rU   rV   rW   r   rec_ss         r4   r   r     s	   n GG	 {fx))!A$A&A\\""3''',{{1~&%++a.EKKN*J]177)=
 	

 

EMM5<<At1Dihq$r5   c                 T   t        j                  |      }t        t        |      dz
        D ]x  }|||   ||dz       }t        |      s	||   ||<   %t        j                  ||d      }|t         j
                  u r| ||   ||dz       }	 ||d|	      ||<   l ||d      ||<   z |S )aN  Nearest-neighbor filter helper function.

    This is an internal function, not for use outside of the decompose module.

    It applies the nearest-neighbor filter to S, assuming that the first index
    corresponds to observations.

    Parameters
    ----------
    R_data, R_indices, R_ptr : np.ndarrays
        The ``data``, ``indices``, and ``indptr`` of a scipy.sparse matrix
    S : np.ndarray
        The observation data to filter
    aggregate : callable
        The aggregation operator

    Returns
    -------
    S_out : np.ndarray like S
        The filtered data array
    r   r   )rW   )rW   weights)rC   rH   rangelentakeaverage)
R_data	R_indicesR_ptrr   rV   s_outitargets	neighborsrg   s
             r4   r`   r`   +  s    0 MM!E3u:>"E!HuQU|47|tE!HGGAwQ/	

"U1Xa!e5G GDE!H 3E!H #  Lr5   )'__doc__numpyrC   scipy.sparser]   scipy.ndimager   sklearn.decompositionr(    r   _cacher   r   r   util.exceptionsr	   typingr
   r   r   r   r   r   _typingr   r   __all__ndarrayintobjectboolr   floatr   rY   spmatrixr   r`   r"   r5   r4   <module>r      s'  	   '      + > > /
, #'$(o#	zzo# 3-o# &!	o#
 o# 
o# o# 2::rzz!"o#d R 	 	E>	zzE> U;34d;6GGE> E> E> u]M9:D<OOE> 2::rzz!"E> E>P R ?C$(L	zzL 
%--rzz9:	;L !	L
 L L ZZL L^*!#*8@*ZZ*r5   