
    }KgU>                        d 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mZmZ g dZddd	ej$                  d
dddej&                  dej&                  dee   dee   dee   dededededej&                  fdZd
ddddej&                  dej&                  dededededej&                  fdZd
ddddej&                  dej&                  dej&                  dededededej&                  fdZy)z3Harmonic calculations for frequency representations    N   )ParameterError)	is_unique)	ArrayLike)CallableOptionalSequence)salienceinterp_harmonicsf0_harmonicsTlinear)weights	aggregatefilter_peaks
fill_valuekindaxisSfreqs	harmonicsr   r   r   r   r   r   returnc                   |t         j                  }| t        j                  t        |      f      }nt        j                  |t
              }t        | ||||      }	|t         j                  u r ||	|dz
  |      }
n ||	|dz
        }
|r[t        j                  j                  | |      }t        j                  | j                        }|j                  |       |
|   ||<   |}
|
S )a  Harmonic salience function.

    Parameters
    ----------
    S : np.ndarray [shape=(..., d, n)]
        input time frequency magnitude representation (e.g. STFT or CQT magnitudes).
        Must be real-valued and non-negative.

    freqs : np.ndarray, shape=(S.shape[axis]) or shape=S.shape
        The frequency values corresponding to S's elements along the
        chosen axis.

        Frequencies can also be time-varying, e.g. as computed by
        `reassigned_spectrogram`, in which case the shape should
        match ``S``.

    harmonics : list-like, non-negative
        Harmonics to include in salience computation.  The first harmonic (1)
        corresponds to ``S`` itself. Values less than one (e.g., 1/2) correspond
        to sub-harmonics.

    weights : list-like
        The weight to apply to each harmonic in the summation. (default:
        uniform weights). Must be the same length as ``harmonics``.

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

        If ``aggregate=np.average``, then a weighted average is
        computed per-harmonic according to the specified weights.
        For all other aggregation functions, all harmonics
        are treated equally.

    filter_peaks : bool
        If true, returns harmonic summation only on frequencies of peak
        magnitude. Otherwise returns harmonic summation over the full spectrum.
        Defaults to True.

    fill_value : float
        The value to fill non-peaks in the output representation. (default:
        `np.nan`) Only used if ``filter_peaks == True``.

    kind : str
        Interpolation type for harmonic estimation.
        See `scipy.interpolate.interp1d`.

    axis : int
        The axis along which to compute harmonics

    Returns
    -------
    S_sal : np.ndarray
        ``S_sal`` will have the same shape as ``S``, and measure
        the overall harmonic energy at each frequency.

    See Also
    --------
    interp_harmonics

    Examples
    --------
    >>> y, sr = librosa.load(librosa.ex('trumpet'), duration=3)
    >>> S = np.abs(librosa.stft(y))
    >>> freqs = librosa.fft_frequencies(sr=sr)
    >>> harms = [1, 2, 3, 4]
    >>> weights = [1.0, 0.5, 0.33, 0.25]
    >>> S_sal = librosa.salience(S, freqs=freqs, harmonics=harms, weights=weights, fill_value=0)
    >>> print(S_sal.shape)
    (1025, 115)
    >>> import matplotlib.pyplot as plt
    >>> fig, ax = plt.subplots(nrows=2, sharex=True, sharey=True)
    >>> librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
    ...                          sr=sr, y_axis='log', x_axis='time', ax=ax[0])
    >>> ax[0].set(title='Magnitude spectrogram')
    >>> ax[0].label_outer()
    >>> img = librosa.display.specshow(librosa.amplitude_to_db(S_sal,
    ...                                                        ref=np.max),
    ...                                sr=sr, y_axis='log', x_axis='time', ax=ax[1])
    >>> ax[1].set(title='Salience spectrogram')
    >>> fig.colorbar(img, ax=ax, format="%+2.0f dB")
    )dtype)r   r   r   r      )r   r   r   )npaverageoneslenarrayfloatr   scipysignal	argrelmaxemptyshapefill)r   r   r   r   r   r   r   r   r   S_harmS_salS_peaksS_outs                Y/home/alanp/www/video.onchill/myenv/lib/python3.12/site-packages/librosa/core/harmonic.pyr
   r
      s    z JJ	''3y>+,((7%0au	SWXF BJJ&taxA&tax0,,(((6!

:wgL    )r   r   r   xc          	         |j                   dk(  rt        |      | j                  |   k(  rrt        |d      st	        j
                  dd       t        j                  j                  || |dd      }t        j                  j                  |      } ||      S |j                  | j                  k(  rt        j                  t        ||            st	        j
                  dd       fd	}t        j                  |d
      }	 |	|j                  |d      | j                  |d            j                  d|      j                  d|dz
        S t        d|j                   d| j                         )a  Compute the energy at harmonics of time-frequency representation.

    Given a frequency-based energy representation such as a spectrogram
    or tempogram, this function computes the energy at the chosen harmonics
    of the frequency axis.  (See examples below.)
    The resulting harmonic array can then be used as input to a salience
    computation.

    Parameters
    ----------
    x : np.ndarray
        The input energy
    freqs : np.ndarray, shape=(x.shape[axis]) or shape=x.shape
        The frequency values corresponding to x's elements along the
        chosen axis.
        Frequencies can also be time-varying, e.g. as computed by
        `reassigned_spectrogram`, in which case the shape should
        match ``x``.
    harmonics : list-like, non-negative
        Harmonics to compute as ``harmonics[i] * freqs``.
        The first harmonic (1) corresponds to ``freqs``.
        Values less than one (e.g., 1/2) correspond to sub-harmonics.
    kind : str
        Interpolation type.  See `scipy.interpolate.interp1d`.
    fill_value : float
        The value to fill when extrapolating beyond the observed
        frequency range.
    axis : int
        The axis along which to compute harmonics

    Returns
    -------
    x_harm : np.ndarray
        ``x_harm[i]`` will have the same shape as ``x``, and measure
        the energy at the ``harmonics[i]`` harmonic of each frequency.
        A new dimension indexing harmonics will be inserted immediately
        before ``axis``.

    See Also
    --------
    scipy.interpolate.interp1d

    Examples
    --------
    Estimate the harmonics of a time-averaged tempogram

    >>> y, sr = librosa.load(librosa.ex('sweetwaltz'))
    >>> # Compute the time-varying tempogram and average over time
    >>> tempi = np.mean(librosa.feature.tempogram(y=y, sr=sr), axis=1)
    >>> # We'll measure the first five harmonics
    >>> harmonics = [1, 2, 3, 4, 5]
    >>> f_tempo = librosa.tempo_frequencies(len(tempi), sr=sr)
    >>> # Build the harmonic tensor; we only have one axis here (tempo)
    >>> t_harmonics = librosa.interp_harmonics(tempi, freqs=f_tempo, harmonics=harmonics, axis=0)
    >>> print(t_harmonics.shape)
    (5, 384)

    >>> # And plot the results
    >>> import matplotlib.pyplot as plt
    >>> fig, ax = plt.subplots()
    >>> librosa.display.specshow(t_harmonics, x_axis='tempo', sr=sr, ax=ax)
    >>> ax.set(yticks=np.arange(len(harmonics)),
    ...        yticklabels=['{:.3g}'.format(_) for _ in harmonics],
    ...        ylabel='Harmonic', xlabel='Tempo (BPM)')

    We can also compute frequency harmonics for spectrograms.
    To calculate sub-harmonic energy, use values < 1.

    >>> y, sr = librosa.load(librosa.ex('trumpet'), duration=3)
    >>> harmonics = [1./3, 1./2, 1, 2, 3, 4]
    >>> S = np.abs(librosa.stft(y))
    >>> fft_freqs = librosa.fft_frequencies(sr=sr)
    >>> S_harm = librosa.interp_harmonics(S, freqs=fft_freqs, harmonics=harmonics, axis=0)
    >>> print(S_harm.shape)
    (6, 1025, 646)

    >>> fig, ax = plt.subplots(nrows=3, ncols=2, sharex=True, sharey=True)
    >>> for i, _sh in enumerate(S_harm):
    ...     img = librosa.display.specshow(librosa.amplitude_to_db(_sh,
    ...                                                      ref=S.max()),
    ...                              sr=sr, y_axis='log', x_axis='time',
    ...                              ax=ax.flat[i])
    ...     ax.flat[i].set(title='h={:.3g}'.format(harmonics[i]))
    ...     ax.flat[i].label_outer()
    >>> fig.colorbar(img, ax=ax, format="%+2.f dB")
    r   r   r   OFrequencies are not unique. This may produce incorrect harmonic interpolations.r   
stacklevelF)r   bounds_errorcopyr   r   c                     t         j                  j                  | |dd      } |t        j                  j                  |             S )NF)r4   r5   r   r   )r#   interpolateinterp1dr   multiplyouter)_a_binterpr   r   r   s      r-   	_f_interpz#interp_harmonics.<locals>._f_interp  sI    &&//BUTj 0 F "++++B	:;;r.   z(f),(f)->(f,h)	signaturer   freqs.shape=" is incompatible with input shape=)ndimr    r'   r   warningswarnr#   r7   r8   r   r9   r:   all	vectorizeswapaxesr   )
r/   r   r   r   r   r   f_interpf_outr>   xfuncs
     ```     r-   r   r      sZ   ~ zzQ3u:6
 Q'MMa
 $$--! . 
 !!)U3 		vviD12MMa	< Y2BC %..r*AJJtR,@AX
 Xq	
 5;;-'I!''S
 	
r.   f0c                   j                   dk(  rt              | j                  |   k(  rt        d      st	        j
                  dd       t        j                        fd}t        j                  |d	      } || j                  |d
      t        j                  j                  ||            j                  |d
      }	nj                  | j                  k(  rt        j                  t        |            st	        j
                  dd       fd}
t        j                  |
d	      } || j                  |d
      j                  |d
      t        j                  j                  ||            j                  |d
      }	n%t        dj                   d| j                         t        j                  |	d      S )a  Compute the energy at selected harmonics of a time-varying
    fundamental frequency.

    This function can be used to reduce a `frequency * time` representation
    to a `harmonic * time` representation, effectively normalizing out for
    the fundamental frequency.  The result can be used as a representation
    of timbre when f0 corresponds to pitch, or as a representation of
    rhythm when f0 corresponds to tempo.

    This function differs from `interp_harmonics`, which computes the
    harmonics of *all* frequencies.

    Parameters
    ----------
    x : np.ndarray [shape=(..., frequencies, n)]
        The input array (e.g., STFT magnitudes)
    f0 : np.ndarray [shape=(..., n)]
        The fundamental frequency (f0) of each frame in the input
        Shape should match ``x.shape[-1]``
    freqs : np.ndarray, shape=(x.shape[axis]) or shape=x.shape
        The frequency values corresponding to X's elements along the
        chosen axis.
        Frequencies can also be time-varying, e.g. as computed by
        `reassigned_spectrogram`, in which case the shape should
        match ``x``.
    harmonics : list-like, non-negative
        Harmonics to compute as ``harmonics[i] * f0``
        Values less than one (e.g., 1/2) correspond to sub-harmonics.
    kind : str
        Interpolation type.  See `scipy.interpolate.interp1d`.
    fill_value : float
        The value to fill when extrapolating beyond the observed
        frequency range.
    axis : int
        The axis corresponding to frequency in ``x``

    Returns
    -------
    f0_harm : np.ndarray [shape=(..., len(harmonics), n)]
        Interpolated energy at each specified harmonic of the fundamental
        frequency for each time step.

    See Also
    --------
    interp_harmonics
    librosa.feature.tempogram_ratio

    Examples
    --------
    This example estimates the fundamental (f0), and then extracts the first
    12 harmonics

    >>> y, sr = librosa.load(librosa.ex('trumpet'))
    >>> f0, voicing, voicing_p = librosa.pyin(y=y, sr=sr, fmin=200, fmax=700)
    >>> S = np.abs(librosa.stft(y))
    >>> freqs = librosa.fft_frequencies(sr=sr)
    >>> harmonics = np.arange(1, 13)
    >>> f0_harm = librosa.f0_harmonics(S, freqs=freqs, f0=f0, harmonics=harmonics)

    >>> import matplotlib.pyplot as plt
    >>> fig, ax =plt.subplots(nrows=2, sharex=True)
    >>> librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
    ...                          x_axis='time', y_axis='log', ax=ax[0])
    >>> times = librosa.times_like(f0)
    >>> for h in harmonics:
    ...     ax[0].plot(times, h * f0, label=f"{h}*f0")
    >>> ax[0].legend(ncols=4, loc='lower right')
    >>> ax[0].label_outer()
    >>> librosa.display.specshow(librosa.amplitude_to_db(f0_harm, ref=np.max),
    ...                          x_axis='time', ax=ax[1])
    >>> ax[1].set_yticks(harmonics-1)
    >>> ax[1].set_yticklabels(harmonics)
    >>> ax[1].set(ylabel='Harmonics')
    r   r   r   r1   r   r2   c           
      n    t         j                  j                     |    dddd      } ||      S Nr   F)r   r4   r5   assume_sortedr   r   )r#   r7   r8   )datafr=   r   r   idxr   s      r-   
_f_interpsz f0_harmonics.<locals>._f_interps  sJ    &&//c
S	"#% 0 	F !9r.   z(f),(h)->(h)r?   rA   c           
          t        j                  |      }t        j                  j	                  ||   | |   dddd      } ||      S rP   )r   isfiniter#   r7   r8   )rR   frequenciesrS   rT   r=   r   r   s        r-   
_f_interpdz f0_harmonics.<locals>._f_interpd  sY    ++k*C&&//C S	"#% 0 	F !9r.   z(f),(f),(h)->(h)rB   rC   F)r5   nan)rD   r    r'   r   rE   rF   r   rW   rH   rI   r9   r:   rG   r   
nan_to_num)r/   rM   r   r   r   r   r   rU   rL   resultrY   rT   s     ` ``     @r-   r   r   /  sv   j zzQ3u:6Q'MMa kk% 	 Z>Bqzz$+R[[->->r9-MNWW"
 
	vviD12MMa	 Z3EFJJtR NN4$KKb),
 (4
	 	 5;;-'I!''S
 	
 ==e<<r.   )__doc__rE   numpyr   scipy.interpolater#   scipy.signalutil.exceptionsr   utilr   numpy.typingr   typingr   r   r	   __all__rZ   ndarrayr"   boolstrintr
   r   r    r.   r-   <module>rk      s   :     ,  " / /
: $($(u	zzu ::u 	u
 i u !u u u u u ZZuz b
	zzb
 ::b
 	b

 b
 b
 b
 ZZb
V S=	zzS= 	

S= ::	S=
 S= S= S= S= ZZS=r.   