def match_events(events_from, events_to, left=True, right=True):
    '''Match one set of events to another.

    This is useful for tasks such as matching beats to the nearest
    detected onsets, or frame-aligned events to the nearest zero-crossing.

    .. note:: A target event may be matched to multiple source events.

    Examples
    --------
    >>> # Sources are multiples of 7
    >>> s_from = np.arange(0, 100, 7)
    >>> s_from
    array([ 0,  7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91,
           98])
    >>> # Targets are multiples of 10
    >>> s_to = np.arange(0, 100, 10)
    >>> s_to
    array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
    >>> # Find the matching
    >>> idx = librosa.util.match_events(s_from, s_to)
    >>> idx
    array([0, 1, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 8, 9, 9])
    >>> # Print each source value to its matching target
    >>> zip(s_from, s_to[idx])
    [(0, 0), (7, 10), (14, 10), (21, 20), (28, 30), (35, 30),
     (42, 40), (49, 50), (56, 60), (63, 60), (70, 70), (77, 80),
     (84, 80), (91, 90), (98, 90)]

    Parameters
    ----------
    events_from : ndarray [shape=(n,)]
      Array of events (eg, times, sample or frame indices) to match from.

    events_to : ndarray [shape=(m,)]
      Array of events (eg, times, sample or frame indices) to
      match against.

    left : bool
    right : bool
        If `False`, then matched events cannot be to the left (or right)
        of source events.

    Returns
    -------
    event_mapping : np.ndarray [shape=(n,)]
        For each event in `events_from`, the corresponding event
        index in `events_to`.

        `event_mapping[i] == arg min |events_from[i] - events_to[:]|`

    See Also
    --------
    match_intervals

    Raises
    ------
    ParameterError
        If either array of input events is not the correct shape
    '''
    if len(events_from) == 0 or len(events_to) == 0:
        raise ParameterError('Attempting to match empty event list')

    # If we can't match left or right, then only strict equivalence
    # counts as a match.
    if not (left or right) and not np.all(np.in1d(events_from, events_to)):
        raise ParameterError('Cannot match events with left=right=False '
                             'and events_from is not contained '
                             'in events_to')

    # If we can't match to the left, then there should be at least one
    # target event greater-equal to every source event
    if (not left) and max(events_to) < max(events_from):
        raise ParameterError('Cannot match events with left=False '
                             'and max(events_to) < max(events_from)')

    # If we can't match to the right, then there should be at least one
    # target event less-equal to every source event
    if (not right) and min(events_to) > min(events_from):
        raise ParameterError('Cannot match events with right=False '
                             'and min(events_to) > min(events_from)')

    # array of matched items
    output = np.empty_like(events_from, dtype=np.int)

    return __match_events_helper(output, events_from, events_to, left, right)


def salience(S, freqs, h_range, weights=None, aggregate=None,
             filter_peaks=True, fill_value=np.nan,  kind='linear', axis=0):
    """Harmonic salience function.

    Parameters
    ----------
    S : np.ndarray [shape=(d, n)]
        input time frequency magnitude representation (stft, ifgram, etc).
        Must be real-valued and non-negative.
    freqs : np.ndarray, shape=(S.shape[axis])
        The frequency values corresponding to S's elements along the
        chosen axis.
    h_range : 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, shape=(len(h_range), [x.shape])
        `S_sal` will have the same shape as `S`, and measure
        the overal harmonic energy at each frequency.

    See Also
    --------
    interp_harmonics

    Examples
    --------
    >>> y, sr = librosa.load(librosa.util.example_audio_file(),
    ...                      duration=15, offset=30)
    >>> S = np.abs(librosa.stft(y))
    >>> freqs = librosa.core.fft_frequencies(sr)
    >>> harms = [1, 2, 3, 4]
    >>> weights = [1.0, 0.5, 0.33, 0.25]
    >>> S_sal = librosa.salience(S, freqs, harms, weights, fill_value=0)
    >>> print(S_sal.shape)
    (1025, 646)
    >>> import matplotlib.pyplot as plt
    >>> plt.figure()
    >>> librosa.display.specshow(librosa.amplitude_to_db(S_sal,
    ...                                                  ref=np.max),
    ...                          sr=sr, y_axis='log', x_axis='time')
    >>> plt.colorbar()
    >>> plt.title('Salience spectrogram')
    >>> plt.tight_layout()
    """
    if aggregate is None:
        aggregate = np.average

    if weights is None:
        weights = np.ones((len(h_range), ))
    else:
        weights = np.array(weights, dtype=float)

    S_harm = interp_harmonics(S, freqs, h_range, kind=kind, axis=axis)

    if aggregate is np.average:
        S_sal = aggregate(S_harm, axis=0, weights=weights)
    else:
        S_sal = aggregate(S_harm, axis=0)

    if filter_peaks:
        S_peaks = scipy.signal.argrelmax(S, axis=0)
        S_out = np.empty(S.shape)
        S_out.fill(fill_value)
        S_out[S_peaks[0], S_peaks[1]] = S_sal[S_peaks[0], S_peaks[1]]

        S_sal = S_out

    return S_sal

def salience ( S , freqs , h_range , weights = None , aggregate = None , filter_peaks = True , fill_value = np . nan , kind = 'linear' , axis = 0 ) : if aggregate is None : aggregate = np . average if weights is None : weights = np . ones ( ( len ( h_range ) , ) ) else : weights = np . array ( weights , dtype = float ) S_harm = interp_harmonics ( S , freqs , h_range , kind = kind , axis = axis ) if aggregate is np . average : S_sal = aggregate ( S_harm , axis = 0 , weights = weights ) else : S_sal = aggregate ( S_harm , axis = 0 ) if filter_peaks : S_peaks = scipy . signal . argrelmax ( S , axis = 0 ) S_out = np . empty ( S . shape ) S_out . fill ( fill_value ) S_out [ S_peaks [ 0 ] , S_peaks [ 1 ] ] = S_sal [ S_peaks [ 0 ] , S_peaks [ 1 ] ] S_sal = S_out return S_sal


def interp_harmonics(x, freqs, h_range, kind='linear', fill_value=0, axis=0):
    '''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])
        The frequency values corresponding to X's elements along the
        chosen axis.

    h_range : list-like, non-negative
        Harmonics to compute.  The first harmonic (1) corresponds to `x`
        itself.
        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, shape=(len(h_range), [x.shape])
        `x_harm[i]` will have the same shape as `x`, and measure
        the energy at the `h_range[i]` harmonic of each frequency.

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

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

    >>> y, sr = librosa.load(librosa.util.example_audio_file(),
    ...                      duration=15, offset=30)
    >>> # 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
    >>> h_range = [1, 2, 3, 4, 5]
    >>> f_tempo = librosa.tempo_frequencies(len(tempi), sr=sr)
    >>> # Build the harmonic tensor
    >>> t_harmonics = librosa.interp_harmonics(tempi, f_tempo, h_range)
    >>> print(t_harmonics.shape)
    (5, 384)

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

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

    >>> h_range = [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, fft_freqs, h_range, axis=0)
    >>> print(S_harm.shape)
    (6, 1025, 646)

    >>> plt.figure()
    >>> for i, _sh in enumerate(S_harm, 1):
    ...     plt.subplot(3, 2, i)
    ...     librosa.display.specshow(librosa.amplitude_to_db(_sh,
    ...                                                      ref=S.max()),
    ...                              sr=sr, y_axis='log')
    ...     plt.title('h={:.3g}'.format(h_range[i-1]))
    ...     plt.yticks([])
    >>> plt.tight_layout()
    '''

    # X_out will be the same shape as X, plus a leading
    # axis that has length = len(h_range)
    out_shape = [len(h_range)]
    out_shape.extend(x.shape)

    x_out = np.zeros(out_shape, dtype=x.dtype)

    if freqs.ndim == 1 and len(freqs) == x.shape[axis]:
        harmonics_1d(x_out, x, freqs, h_range,
                     kind=kind, fill_value=fill_value,
                     axis=axis)

    elif freqs.ndim == 2 and freqs.shape == x.shape:
        harmonics_2d(x_out, x, freqs, h_range,
                     kind=kind, fill_value=fill_value,
                     axis=axis)
    else:
        raise ParameterError('freqs.shape={} does not match '
                             'input shape={}'.format(freqs.shape, x.shape))

    return x_out

def
interp_harmonics
(
x
,
freqs
,
h_range
,
kind
=
'linear'
,
fill_value
=
0
,
axis
=
0
)
:
out_shape
=
[
len
(
h_range
)
]
out_shape
.
extend
(
x
.
shape
)
x_out
=
np
.
zeros
(
out_shape
,
dtype
=
x
.
dtype
)
if
freqs
.
ndim
==
1
and
len
(
freqs
)
==
x
.
shape
[
axis
]
:
harmonics_1d
(
x_out
,
x
,
freqs
,
h_range
,
kind
=
kind
,
fill_value
=
fill_value
,
axis
=
axis
)
elif
freqs
.
ndim
==
2
and
freqs
.
shape
==
x
.
shape
:
harmonics_2d
(
x_out
,
x
,
freqs
,
h_range
,
kind
=
kind
,
fill_value
=
fill_value
,
axis
=
axis
)
else
:
raise
ParameterError
(
'freqs.shape={} does not match '
'input shape={}'
.
format
(
freqs
.
shape
,
x
.
shape
)
)
return
x_out

Compute the energy at harmonics of time - frequency representation .


def harmonics_1d(harmonic_out, x, freqs, h_range, kind='linear',
                 fill_value=0, axis=0):
    '''Populate a harmonic tensor from a time-frequency representation.

    Parameters
    ----------
    harmonic_out : np.ndarray, shape=(len(h_range), X.shape)
        The output array to store harmonics

    X : np.ndarray
        The input energy

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

    h_range : list-like, non-negative
        Harmonics to compute.  The first harmonic (1) corresponds to `x`
        itself.
        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

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

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

    >>> y, sr = librosa.load(librosa.util.example_audio_file(),
    ...                      duration=15, offset=30)
    >>> # 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
    >>> h_range = [1, 2, 3, 4, 5]
    >>> f_tempo = librosa.tempo_frequencies(len(tempi), sr=sr)
    >>> # Build the harmonic tensor
    >>> t_harmonics = librosa.interp_harmonics(tempi, f_tempo, h_range)
    >>> print(t_harmonics.shape)
    (5, 384)

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

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

    >>> h_range = [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, fft_freqs, h_range, axis=0)
    >>> print(S_harm.shape)
    (6, 1025, 646)

    >>> plt.figure()
    >>> for i, _sh in enumerate(S_harm, 1):
    ...     plt.subplot(3,2,i)
    ...     librosa.display.specshow(librosa.amplitude_to_db(_sh,
    ...                                                      ref=S.max()),
    ...                              sr=sr, y_axis='log')
    ...     plt.title('h={:.3g}'.format(h_range[i-1]))
    ...     plt.yticks([])
    >>> plt.tight_layout()
    '''

    # Note: this only works for fixed-grid, 1d interpolation
    f_interp = scipy.interpolate.interp1d(freqs, x,
                                          kind=kind,
                                          axis=axis,
                                          copy=False,
                                          bounds_error=False,
                                          fill_value=fill_value)

    idx_out = [slice(None)] * harmonic_out.ndim

    # Compute the output index of the interpolated values
    interp_axis = 1 + (axis % x.ndim)

    # Iterate over the harmonics range
    for h_index, harmonic in enumerate(h_range):
        idx_out[0] = h_index

        # Iterate over frequencies
        for f_index, frequency in enumerate(freqs):
            # Offset the output axis by 1 to account for the harmonic index
            idx_out[interp_axis] = f_index

            # Estimate the harmonic energy at this frequency across time
            harmonic_out[tuple(idx_out)] = f_interp(harmonic * frequency)

def harmonics_1d ( harmonic_out , x , freqs , h_range , kind = 'linear' , fill_value = 0 , axis = 0 ) : f_interp = scipy . interpolate . interp1d ( freqs , x , kind = kind , axis = axis , copy = False , bounds_error = False , fill_value = fill_value ) idx_out = [ slice ( None ) ] * harmonic_out . ndim interp_axis = 1 + ( axis % x . ndim ) for h_index , harmonic in enumerate ( h_range ) : idx_out [ 0 ] = h_index for f_index , frequency in enumerate ( freqs ) : idx_out [ interp_axis ] = f_index harmonic_out [ tuple ( idx_out ) ] = f_interp ( harmonic * frequency )

Populate a harmonic tensor from a time - frequency representation .


def harmonics_2d(harmonic_out, x, freqs, h_range, kind='linear', fill_value=0,
                 axis=0):
    '''Populate a harmonic tensor from a time-frequency representation with
    time-varying frequencies.

    Parameters
    ----------
    harmonic_out : np.ndarray
        The output array to store harmonics

    x : np.ndarray
        The input energy

    freqs : np.ndarray, shape=x.shape
        The frequency values corresponding to each element of `x`

    h_range : list-like, non-negative
        Harmonics to compute.  The first harmonic (1) corresponds to `x`
        itself.  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

    See Also
    --------
    harmonics
    harmonics_1d
    '''
    idx_in = [slice(None)] * x.ndim
    idx_freq = [slice(None)] * x.ndim
    idx_out = [slice(None)] * harmonic_out.ndim

    # This is the non-interpolation axis
    ni_axis = (1 + axis) % x.ndim

    # For each value in the non-interpolated axis, compute its harmonics
    for i in range(x.shape[ni_axis]):
        idx_in[ni_axis] = slice(i, i + 1)
        idx_freq[ni_axis] = i
        idx_out[1 + ni_axis] = idx_in[ni_axis]

        harmonics_1d(harmonic_out[tuple(idx_out)], x[tuple(idx_in)], freqs[tuple(idx_freq)],
                     h_range, kind=kind, fill_value=fill_value,
                     axis=axis)

def harmonics_2d ( harmonic_out , x , freqs , h_range , kind = 'linear' , fill_value = 0 , axis = 0 ) : idx_in = [ slice ( None ) ] * x . ndim idx_freq = [ slice ( None ) ] * x . ndim idx_out = [ slice ( None ) ] * harmonic_out . ndim ni_axis = ( 1 + axis ) % x . ndim for i in range ( x . shape [ ni_axis ] ) : idx_in [ ni_axis ] = slice ( i , i + 1 ) idx_freq [ ni_axis ] = i idx_out [ 1 + ni_axis ] = idx_in [ ni_axis ] harmonics_1d ( harmonic_out [ tuple ( idx_out ) ] , x [ tuple ( idx_in ) ] , freqs [ tuple ( idx_freq ) ] , h_range , kind = kind , fill_value = fill_value , axis = axis )

Populate a harmonic tensor from a time - frequency representation with time - varying frequencies .


def load(path, sr=22050, mono=True, offset=0.0, duration=None,
         dtype=np.float32, res_type='kaiser_best'):
    """Load an audio file as a floating point time series.

    Audio will be automatically resampled to the given rate
    (default `sr=22050`).

    To preserve the native sampling rate of the file, use `sr=None`.

    Parameters
    ----------
    path : string, int, or file-like object
        path to the input file.

        Any codec supported by `soundfile` or `audioread` will work.

        If the codec is supported by `soundfile`, then `path` can also be
        an open file descriptor (int), or any object implementing Python's
        file interface.

        If the codec is not supported by `soundfile` (e.g., MP3), then only
        string file paths are supported.

    sr   : number > 0 [scalar]
        target sampling rate

        'None' uses the native sampling rate

    mono : bool
        convert signal to mono

    offset : float
        start reading after this time (in seconds)

    duration : float
        only load up to this much audio (in seconds)

    dtype : numeric type
        data type of `y`

    res_type : str
        resample type (see note)

        .. note::
            By default, this uses `resampy`'s high-quality mode ('kaiser_best').

            For alternative resampling modes, see `resample`

        .. note::
           `audioread` may truncate the precision of the audio data to 16 bits.

           See https://librosa.github.io/librosa/ioformats.html for alternate
           loading methods.

    Returns
    -------
    y    : np.ndarray [shape=(n,) or (2, n)]
        audio time series

    sr   : number > 0 [scalar]
        sampling rate of `y`

    Examples
    --------
    >>> # Load an ogg vorbis file
    >>> filename = librosa.util.example_audio_file()
    >>> y, sr = librosa.load(filename)
    >>> y
    array([ -4.756e-06,  -6.020e-06, ...,  -1.040e-06,   0.000e+00], dtype=float32)
    >>> sr
    22050

    >>> # Load a file and resample to 11 KHz
    >>> filename = librosa.util.example_audio_file()
    >>> y, sr = librosa.load(filename, sr=11025)
    >>> y
    array([ -2.077e-06,  -2.928e-06, ...,  -4.395e-06,   0.000e+00], dtype=float32)
    >>> sr
    11025

    >>> # Load 5 seconds of a file, starting 15 seconds in
    >>> filename = librosa.util.example_audio_file()
    >>> y, sr = librosa.load(filename, offset=15.0, duration=5.0)
    >>> y
    array([ 0.069,  0.1  , ..., -0.101,  0.   ], dtype=float32)
    >>> sr
    22050

    """

    try:
        with sf.SoundFile(path) as sf_desc:
            sr_native = sf_desc.samplerate
            if offset:
                # Seek to the start of the target read
                sf_desc.seek(int(offset * sr_native))
            if duration is not None:
                frame_duration = int(duration * sr_native)
            else:
                frame_duration = -1

            # Load the target number of frames, and transpose to match librosa form
            y = sf_desc.read(frames=frame_duration, dtype=dtype, always_2d=False).T

    except RuntimeError as exc:
        # If soundfile failed, fall back to the audioread loader
        y, sr_native = __audioread_load(path, offset, duration, dtype)

    # Final cleanup for dtype and contiguity
    if mono:
        y = to_mono(y)

    if sr is not None:
        y = resample(y, sr_native, sr, res_type=res_type)

    else:
        sr = sr_native

    return y, sr

def load ( path , sr = 22050 , mono = True , offset = 0.0 , duration = None , dtype = np . float32 , res_type = 'kaiser_best' ) : try : with sf . SoundFile ( path ) as sf_desc : sr_native = sf_desc . samplerate if offset : sf_desc . seek ( int ( offset * sr_native ) ) if duration is not None : frame_duration = int ( duration * sr_native ) else : frame_duration = - 1 y = sf_desc . read ( frames = frame_duration , dtype = dtype , always_2d = False ) . T except RuntimeError as exc : y , sr_native = __audioread_load ( path , offset , duration , dtype ) if mono : y = to_mono ( y ) if sr is not None : y = resample ( y , sr_native , sr , res_type = res_type ) else : sr = sr_native return y , sr

Load an audio file as a floating point time series .


def __audioread_load(path, offset, duration, dtype):
    '''Load an audio buffer using audioread.

    This loads one block at a time, and then concatenates the results.
    '''

    y = []
    with audioread.audio_open(path) as input_file:
        sr_native = input_file.samplerate
        n_channels = input_file.channels

        s_start = int(np.round(sr_native * offset)) * n_channels

        if duration is None:
            s_end = np.inf
        else:
            s_end = s_start + (int(np.round(sr_native * duration))
                               * n_channels)

        n = 0

        for frame in input_file:
            frame = util.buf_to_float(frame, dtype=dtype)
            n_prev = n
            n = n + len(frame)

            if n < s_start:
                # offset is after the current frame
                # keep reading
                continue

            if s_end < n_prev:
                # we're off the end.  stop reading
                break

            if s_end < n:
                # the end is in this frame.  crop.
                frame = frame[:s_end - n_prev]

            if n_prev <= s_start <= n:
                # beginning is in this frame
                frame = frame[(s_start - n_prev):]

            # tack on the current frame
            y.append(frame)

    if y:
        y = np.concatenate(y)
        if n_channels > 1:
            y = y.reshape((-1, n_channels)).T
    else:
        y = np.empty(0, dtype=dtype)

    return y, sr_native

def __audioread_load ( path , offset , duration , dtype ) : y = [ ] with audioread . audio_open ( path ) as input_file : sr_native = input_file . samplerate n_channels = input_file . channels s_start = int ( np . round ( sr_native * offset ) ) * n_channels if duration is None : s_end = np . inf else : s_end = s_start + ( int ( np . round ( sr_native * duration ) ) * n_channels ) n = 0 for frame in input_file : frame = util . buf_to_float ( frame , dtype = dtype ) n_prev = n n = n + len ( frame ) if n < s_start : continue if s_end < n_prev : break if s_end < n : frame = frame [ : s_end - n_prev ] if n_prev <= s_start <= n : frame = frame [ ( s_start - n_prev ) : ] y . append ( frame ) if y : y = np . concatenate ( y ) if n_channels > 1 : y = y . reshape ( ( - 1 , n_channels ) ) . T else : y = np . empty ( 0 , dtype = dtype ) return y , sr_native


def to_mono(y):
    '''Force an audio signal down to mono.

    Parameters
    ----------
    y : np.ndarray [shape=(2,n) or shape=(n,)]
        audio time series, either stereo or mono

    Returns
    -------
    y_mono : np.ndarray [shape=(n,)]
        `y` as a monophonic time-series

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

    Examples
    --------
    >>> y, sr = librosa.load(librosa.util.example_audio_file(), mono=False)
    >>> y.shape
    (2, 1355168)
    >>> y_mono = librosa.to_mono(y)
    >>> y_mono.shape
    (1355168,)

    '''

    # Validate the buffer.  Stereo is ok here.
    util.valid_audio(y, mono=False)

    if y.ndim > 1:
        y = np.mean(y, axis=0)

    return y

def to_mono ( y ) : util . valid_audio ( y , mono = False ) if y . ndim > 1 : y = np . mean ( y , axis = 0 ) return y


def resample(y, orig_sr, target_sr, res_type='kaiser_best', fix=True, scale=False, **kwargs):
    """Resample a time series from orig_sr to target_sr

    Parameters
    ----------
    y : np.ndarray [shape=(n,) or shape=(2, n)]
        audio time series.  Can be mono or stereo.

    orig_sr : number > 0 [scalar]
        original sampling rate of `y`

    target_sr : number > 0 [scalar]
        target sampling rate

    res_type : str
        resample type (see note)

        .. note::
            By default, this uses `resampy`'s high-quality mode ('kaiser_best').

            To use a faster method, set `res_type='kaiser_fast'`.

            To use `scipy.signal.resample`, set `res_type='fft'` or `res_type='scipy'`.

            To use `scipy.signal.resample_poly`, set `res_type='polyphase'`.

        .. note::
            When using `res_type='polyphase'`, only integer sampling rates are
            supported.

    fix : bool
        adjust the length of the resampled signal to be of size exactly
        `ceil(target_sr * len(y) / orig_sr)`

    scale : bool
        Scale the resampled signal so that `y` and `y_hat` have approximately
        equal total energy.

    kwargs : additional keyword arguments
        If `fix==True`, additional keyword arguments to pass to
        `librosa.util.fix_length`.

    Returns
    -------
    y_hat : np.ndarray [shape=(n * target_sr / orig_sr,)]
        `y` resampled from `orig_sr` to `target_sr`

    Raises
    ------
    ParameterError
        If `res_type='polyphase'` and `orig_sr` or `target_sr` are not both
        integer-valued.

    See Also
    --------
    librosa.util.fix_length
    scipy.signal.resample
    resampy.resample

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

    Examples
    --------
    Downsample from 22 KHz to 8 KHz

    >>> y, sr = librosa.load(librosa.util.example_audio_file(), sr=22050)
    >>> y_8k = librosa.resample(y, sr, 8000)
    >>> y.shape, y_8k.shape
    ((1355168,), (491671,))
    """

    # First, validate the audio buffer
    util.valid_audio(y, mono=False)

    if orig_sr == target_sr:
        return y

    ratio = float(target_sr) / orig_sr

    n_samples = int(np.ceil(y.shape[-1] * ratio))

    if res_type in ('scipy', 'fft'):
        y_hat = scipy.signal.resample(y, n_samples, axis=-1)
    elif res_type == 'polyphase':
        if int(orig_sr) != orig_sr or int(target_sr) != target_sr:
            raise ParameterError('polyphase resampling is only supported for integer-valued sampling rates.')

        # For polyphase resampling, we need up- and down-sampling ratios
        # We can get those from the greatest common divisor of the rates
        # as long as the rates are integrable
        orig_sr = int(orig_sr)
        target_sr = int(target_sr)
        gcd = np.gcd(orig_sr, target_sr)
        y_hat = scipy.signal.resample_poly(y, target_sr // gcd, orig_sr // gcd, axis=-1)
    else:
        y_hat = resampy.resample(y, orig_sr, target_sr, filter=res_type, axis=-1)

    if fix:
        y_hat = util.fix_length(y_hat, n_samples, **kwargs)

    if scale:
        y_hat /= np.sqrt(ratio)

    return np.ascontiguousarray(y_hat, dtype=y.dtype)


def autocorrelate(y, max_size=None, axis=-1):
    """Bounded auto-correlation

    Parameters
    ----------
    y : np.ndarray
        array to autocorrelate

    max_size  : int > 0 or None
        maximum correlation lag.
        If unspecified, defaults to `y.shape[axis]` (unbounded)

    axis : int
        The axis along which to autocorrelate.
        By default, the last axis (-1) is taken.

    Returns
    -------
    z : np.ndarray
        truncated autocorrelation `y*y` along the specified axis.
        If `max_size` is specified, then `z.shape[axis]` is bounded
        to `max_size`.

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

    Examples
    --------
    Compute full autocorrelation of y

    >>> y, sr = librosa.load(librosa.util.example_audio_file(), offset=20, duration=10)
    >>> librosa.autocorrelate(y)
    array([  3.226e+03,   3.217e+03, ...,   8.277e-04,   3.575e-04], dtype=float32)

    Compute onset strength auto-correlation up to 4 seconds

    >>> import matplotlib.pyplot as plt
    >>> odf = librosa.onset.onset_strength(y=y, sr=sr, hop_length=512)
    >>> ac = librosa.autocorrelate(odf, max_size=4* sr / 512)
    >>> plt.plot(ac)
    >>> plt.title('Auto-correlation')
    >>> plt.xlabel('Lag (frames)')

    """

    if max_size is None:
        max_size = y.shape[axis]

    max_size = int(min(max_size, y.shape[axis]))

    # Compute the power spectrum along the chosen axis
    # Pad out the signal to support full-length auto-correlation.
    fft = get_fftlib()
    powspec = np.abs(fft.fft(y, n=2 * y.shape[axis] + 1, axis=axis))**2

    # Convert back to time domain
    autocorr = fft.ifft(powspec, axis=axis)

    # Slice down to max_size
    subslice = [slice(None)] * autocorr.ndim
    subslice[axis] = slice(max_size)

    autocorr = autocorr[tuple(subslice)]

    if not np.iscomplexobj(y):
        autocorr = autocorr.real

    return autocorr

def autocorrelate ( y , max_size = None , axis = - 1 ) : if max_size is None : max_size = y . shape [ axis ] max_size = int ( min ( max_size , y . shape [ axis ] ) ) fft = get_fftlib ( ) powspec = np . abs ( fft . fft ( y , n = 2 * y . shape [ axis ] + 1 , axis = axis ) ) ** 2 autocorr = fft . ifft ( powspec , axis = axis ) subslice = [ slice ( None ) ] * autocorr . ndim subslice [ axis ] = slice ( max_size ) autocorr = autocorr [ tuple ( subslice ) ] if not np . iscomplexobj ( y ) : autocorr = autocorr . real return autocorr


def lpc(y, order):
    """Linear Prediction Coefficients via Burg's method

    This function applies Burg's method to estimate coefficients of a linear
    filter on `y` of order `order`.  Burg's method is an extension to the
    Yule-Walker approach, which are both sometimes referred to as LPC parameter
    estimation by autocorrelation.

    It follows the description and implementation approach described in the
    introduction in [1]_.  N.B. This paper describes a different method, which
    is not implemented here, but has been chosen for its clear explanation of
    Burg's technique in its introduction.

    .. [1] Larry Marple
           A New Autoregressive Spectrum Analysis Algorithm
           IEEE Transactions on Accoustics, Speech, and Signal Processing
           vol 28, no. 4, 1980

    Parameters
    ----------
    y : np.ndarray
        Time series to fit

    order : int > 0
        Order of the linear filter

    Returns
    -------
    a : np.ndarray of length order + 1
        LP prediction error coefficients, i.e. filter denominator polynomial

    Raises
    ------
    ParameterError
        - If y is not valid audio as per `util.valid_audio`
        - If order < 1 or not integer
    FloatingPointError
        - If y is ill-conditioned

    See also
    --------
    scipy.signal.lfilter

    Examples
    --------
    Compute LP coefficients of y at order 16 on entire series

    >>> y, sr = librosa.load(librosa.util.example_audio_file(), offset=30,
    ...                      duration=10)
    >>> librosa.lpc(y, 16)

    Compute LP coefficients, and plot LP estimate of original series

    >>> import matplotlib.pyplot as plt
    >>> import scipy
    >>> y, sr = librosa.load(librosa.util.example_audio_file(), offset=30,
    ...                      duration=0.020)
    >>> a = librosa.lpc(y, 2)
    >>> y_hat = scipy.signal.lfilter([0] + -1*a[1:], [1], y)
    >>> plt.figure()
    >>> plt.plot(y)
    >>> plt.plot(y_hat)
    >>> plt.legend(['y', 'y_hat'])
    >>> plt.title('LP Model Forward Prediction')

    """
    if not isinstance(order, int) or order < 1:
        raise ParameterError("order must be an integer > 0")

    util.valid_audio(y, mono=True)

    return __lpc(y, order)

def
lpc
(
y
,
order
)
:
if
not
isinstance
(
order
,
int
)
or
order
<
1
:
raise
ParameterError
(
"order must be an integer > 0"
)
util
.
valid_audio
(
y
,
mono
=
True
)
return
__lpc
(
y
,
order
)

Linear Prediction Coefficients via Burg s method


def clicks(times=None, frames=None, sr=22050, hop_length=512,
           click_freq=1000.0, click_duration=0.1, click=None, length=None):
    """Returns a signal with the signal `click` placed at each specified time

    Parameters
    ----------
    times : np.ndarray or None
        times to place clicks, in seconds

    frames : np.ndarray or None
        frame indices to place clicks

    sr : number > 0
        desired sampling rate of the output signal

    hop_length : int > 0
        if positions are specified by `frames`, the number of samples between frames.

    click_freq : float > 0
        frequency (in Hz) of the default click signal.  Default is 1KHz.

    click_duration : float > 0
        duration (in seconds) of the default click signal.  Default is 100ms.

    click : np.ndarray or None
        optional click signal sample to use instead of the default blip.

    length : int > 0
        desired number of samples in the output signal

    Returns
    -------
    click_signal : np.ndarray
        Synthesized click signal

    Raises
    ------
    ParameterError
        - If neither `times` nor `frames` are provided.
        - If any of `click_freq`, `click_duration`, or `length` are out of range.

    Examples
    --------
    >>> # Sonify detected beat events
    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> tempo, beats = librosa.beat.beat_track(y=y, sr=sr)
    >>> y_beats = librosa.clicks(frames=beats, sr=sr)

    >>> # Or generate a signal of the same length as y
    >>> y_beats = librosa.clicks(frames=beats, sr=sr, length=len(y))

    >>> # Or use timing instead of frame indices
    >>> times = librosa.frames_to_time(beats, sr=sr)
    >>> y_beat_times = librosa.clicks(times=times, sr=sr)

    >>> # Or with a click frequency of 880Hz and a 500ms sample
    >>> y_beat_times880 = librosa.clicks(times=times, sr=sr,
    ...                                  click_freq=880, click_duration=0.5)

    Display click waveform next to the spectrogram

    >>> import matplotlib.pyplot as plt
    >>> plt.figure()
    >>> S = librosa.feature.melspectrogram(y=y, sr=sr)
    >>> ax = plt.subplot(2,1,2)
    >>> librosa.display.specshow(librosa.power_to_db(S, ref=np.max),
    ...                          x_axis='time', y_axis='mel')
    >>> plt.subplot(2,1,1, sharex=ax)
    >>> librosa.display.waveplot(y_beat_times, sr=sr, label='Beat clicks')
    >>> plt.legend()
    >>> plt.xlim(15, 30)
    >>> plt.tight_layout()
    """

    # Compute sample positions from time or frames
    if times is None:
        if frames is None:
            raise ParameterError('either "times" or "frames" must be provided')

        positions = frames_to_samples(frames, hop_length=hop_length)
    else:
        # Convert times to positions
        positions = time_to_samples(times, sr=sr)

    if click is not None:
        # Check that we have a well-formed audio buffer
        util.valid_audio(click, mono=True)

    else:
        # Create default click signal
        if click_duration <= 0:
            raise ParameterError('click_duration must be strictly positive')

        if click_freq <= 0:
            raise ParameterError('click_freq must be strictly positive')

        angular_freq = 2 * np.pi * click_freq / float(sr)

        click = np.logspace(0, -10,
                            num=int(np.round(sr * click_duration)),
                            base=2.0)

        click *= np.sin(angular_freq * np.arange(len(click)))

    # Set default length
    if length is None:
        length = positions.max() + click.shape[0]
    else:
        if length < 1:
            raise ParameterError('length must be a positive integer')

        # Filter out any positions past the length boundary
        positions = positions[positions < length]

    # Pre-allocate click signal
    click_signal = np.zeros(length, dtype=np.float32)

    # Place clicks
    for start in positions:
        # Compute the end-point of this click
        end = start + click.shape[0]

        if end >= length:
            click_signal[start:] += click[:length - start]
        else:
            # Normally, just add a click here
            click_signal[start:end] += click

    return click_signal

Returns a signal with the signal click placed at each specified time


def tone(frequency, sr=22050, length=None, duration=None, phi=None):
    """Returns a pure tone signal. The signal generated is a cosine wave.

    Parameters
    ----------
    frequency : float > 0
        frequency

    sr : number > 0
        desired sampling rate of the output signal

    length : int > 0
        desired number of samples in the output signal. When both `duration` and `length` are defined,
        `length` would take priority.

    duration : float > 0
        desired duration in seconds. When both `duration` and `length` are defined, `length` would take priority.

    phi : float or None
        phase offset, in radians. If unspecified, defaults to `-np.pi * 0.5`.

    Returns
    -------
    tone_signal : np.ndarray [shape=(length,), dtype=float64]
        Synthesized pure sine tone signal

    Raises
    ------
    ParameterError
        - If `frequency` is not provided.
        - If neither `length` nor `duration` are provided.

    Examples
    --------
    >>> # Generate a pure sine tone A4
    >>> tone = librosa.tone(440, duration=1)

    >>> # Or generate the same signal using `length`
    >>> tone = librosa.tone(440, sr=22050, length=22050)

    Display spectrogram

    >>> import matplotlib.pyplot as plt
    >>> plt.figure()
    >>> S = librosa.feature.melspectrogram(y=tone)
    >>> librosa.display.specshow(librosa.power_to_db(S, ref=np.max),
    ...                          x_axis='time', y_axis='mel')
    """

    if frequency is None:
        raise ParameterError('"frequency" must be provided')

    # Compute signal length
    if length is None:
        if duration is None:
            raise ParameterError('either "length" or "duration" must be provided')
        length = duration * sr

    if phi is None:
        phi = -np.pi * 0.5

    step = 1.0 / sr
    return np.cos(2 * np.pi * frequency * (np.arange(step * length, step=step)) + phi)

Returns a pure tone signal . The signal generated is a cosine wave .


def chirp(fmin, fmax, sr=22050, length=None, duration=None, linear=False, phi=None):
    """Returns a chirp signal that goes from frequency `fmin` to frequency `fmax`

    Parameters
    ----------
    fmin : float > 0
        initial frequency

    fmax : float > 0
        final frequency

    sr : number > 0
        desired sampling rate of the output signal

    length : int > 0
        desired number of samples in the output signal.
        When both `duration` and `length` are defined, `length` would take priority.

    duration : float > 0
        desired duration in seconds.
        When both `duration` and `length` are defined, `length` would take priority.

    linear : boolean
        - If `True`, use a linear sweep, i.e., frequency changes linearly with time
        - If `False`, use a exponential sweep.
        Default is `False`.

    phi : float or None
        phase offset, in radians.
        If unspecified, defaults to `-np.pi * 0.5`.

    Returns
    -------
    chirp_signal : np.ndarray [shape=(length,), dtype=float64]
        Synthesized chirp signal

    Raises
    ------
    ParameterError
        - If either `fmin` or `fmax` are not provided.
        - If neither `length` nor `duration` are provided.

    See Also
    --------
    scipy.signal.chirp

    Examples
    --------
    >>> # Generate a exponential chirp from A4 to A5
    >>> exponential_chirp = librosa.chirp(440, 880, duration=1)

    >>> # Or generate the same signal using `length`
    >>> exponential_chirp = librosa.chirp(440, 880, sr=22050, length=22050)

    >>> # Or generate a linear chirp instead
    >>> linear_chirp = librosa.chirp(440, 880, duration=1, linear=True)

    Display spectrogram for both exponential and linear chirps

    >>> import matplotlib.pyplot as plt
    >>> plt.figure()
    >>> S_exponential = librosa.feature.melspectrogram(y=exponential_chirp)
    >>> ax = plt.subplot(2,1,1)
    >>> librosa.display.specshow(librosa.power_to_db(S_exponential, ref=np.max),
    ...                          x_axis='time', y_axis='mel')
    >>> plt.subplot(2,1,2, sharex=ax)
    >>> S_linear = librosa.feature.melspectrogram(y=linear_chirp)
    >>> librosa.display.specshow(librosa.power_to_db(S_linear, ref=np.max),
    ...                          x_axis='time', y_axis='mel')
    >>> plt.tight_layout()
    """

    if fmin is None or fmax is None:
        raise ParameterError('both "fmin" and "fmax" must be provided')

    # Compute signal duration
    period = 1.0 / sr
    if length is None:
        if duration is None:
            raise ParameterError('either "length" or "duration" must be provided')
    else:
        duration = period * length

    if phi is None:
        phi = -np.pi * 0.5

    method = 'linear' if linear else 'logarithmic'
    return scipy.signal.chirp(
        np.arange(duration, step=period),
        fmin,
        duration,
        fmax,
        method=method,
        phi=phi / np.pi * 180,  # scipy.signal.chirp uses degrees for phase offset
    )

Returns a chirp signal that goes from frequency fmin to frequency fmax


def __get_files(dir_name, extensions):
    '''Helper function to get files in a single directory'''

    # Expand out the directory
    dir_name = os.path.abspath(os.path.expanduser(dir_name))

    myfiles = set()

    for sub_ext in extensions:
        globstr = os.path.join(dir_name, '*' + os.path.extsep + sub_ext)
        myfiles |= set(glob.glob(globstr))

    return myfiles

def __get_files ( dir_name , extensions ) : dir_name = os . path . abspath ( os . path . expanduser ( dir_name ) ) myfiles = set ( ) for sub_ext in extensions : globstr = os . path . join ( dir_name , '*' + os . path . extsep + sub_ext ) myfiles |= set ( glob . glob ( globstr ) ) return myfiles


def stretch_demo(input_file, output_file, speed):
    '''Phase-vocoder time stretch demo function.

    :parameters:
      - input_file : str
          path to input audio
      - output_file : str
          path to save output (wav)
      - speed : float > 0
          speed up by this factor
    '''

    # 1. Load the wav file, resample
    print('Loading ', input_file)

    y, sr = librosa.load(input_file)

    # 2. Time-stretch through effects module
    print('Playing back at {:3.0f}% speed'.format(speed * 100))

    y_stretch = librosa.effects.time_stretch(y, speed)

    print('Saving stretched audio to: ', output_file)
    librosa.output.write_wav(output_file, y_stretch, sr)

def
stretch_demo
(
input_file
,
output_file
,
speed
)
:
print
(
'Loading '
,
input_file
)
y
,
sr
=
librosa
.
load
(
input_file
)
print
(
'Playing back at {:3.0f}% speed'
.
format
(
speed
*
100
)
)
y_stretch
=
librosa
.
effects
.
time_stretch
(
y
,
speed
)
print
(
'Saving stretched audio to: '
,
output_file
)
librosa
.
output
.
write_wav
(
output_file
,
y_stretch
,
sr
)

Phase - vocoder time stretch demo function .


def process_arguments(args):
    '''Argparse function to get the program parameters'''

    parser = argparse.ArgumentParser(description='Time stretching example')

    parser.add_argument('input_file',
                        action='store',
                        help='path to the input file (wav, mp3, etc)')

    parser.add_argument('output_file',
                        action='store',
                        help='path to the stretched output (wav)')

    parser.add_argument('-s', '--speed',
                        action='store',
                        type=float,
                        default=2.0,
                        required=False,
                        help='speed')

    return vars(parser.parse_args(args))


def hpss_demo(input_file, output_harmonic, output_percussive):
    '''HPSS demo function.

    :parameters:
      - input_file : str
          path to input audio
      - output_harmonic : str
          path to save output harmonic (wav)
      - output_percussive : str
          path to save output harmonic (wav)
    '''

    # 1. Load the wav file, resample
    print('Loading ', input_file)

    y, sr = librosa.load(input_file)

    # Separate components with the effects module
    print('Separating harmonics and percussives... ')
    y_harmonic, y_percussive = librosa.effects.hpss(y)

    # 5. Save the results
    print('Saving harmonic audio to: ', output_harmonic)
    librosa.output.write_wav(output_harmonic, y_harmonic, sr)

    print('Saving percussive audio to: ', output_percussive)
    librosa.output.write_wav(output_percussive, y_percussive, sr)


def beat_track(y=None, sr=22050, onset_envelope=None, hop_length=512,
               start_bpm=120.0, tightness=100, trim=True, bpm=None,
               units='frames'):
    r'''Dynamic programming beat tracker.

    Beats are detected in three stages, following the method of [1]_:
      1. Measure onset strength
      2. Estimate tempo from onset correlation
      3. Pick peaks in onset strength approximately consistent with estimated
         tempo

    .. [1] Ellis, Daniel PW. "Beat tracking by dynamic programming."
           Journal of New Music Research 36.1 (2007): 51-60.
           http://labrosa.ee.columbia.edu/projects/beattrack/

    Parameters
    ----------

    y : np.ndarray [shape=(n,)] or None
        audio time series

    sr : number > 0 [scalar]
        sampling rate of `y`

    onset_envelope : np.ndarray [shape=(n,)] or None
        (optional) pre-computed onset strength envelope.

    hop_length : int > 0 [scalar]
        number of audio samples between successive `onset_envelope` values

    start_bpm  : float > 0 [scalar]
        initial guess for the tempo estimator (in beats per minute)

    tightness  : float [scalar]
        tightness of beat distribution around tempo

    trim       : bool [scalar]
        trim leading/trailing beats with weak onsets

    bpm        : float [scalar]
        (optional) If provided, use `bpm` as the tempo instead of
        estimating it from `onsets`.

    units : {'frames', 'samples', 'time'}
        The units to encode detected beat events in.
        By default, 'frames' are used.

    Returns
    -------

    tempo : float [scalar, non-negative]
        estimated global tempo (in beats per minute)

    beats : np.ndarray [shape=(m,)]
        estimated beat event locations in the specified units
        (default is frame indices)

    .. note::
        If no onset strength could be detected, beat_tracker estimates 0 BPM
        and returns an empty list.

    Raises
    ------
    ParameterError
        if neither `y` nor `onset_envelope` are provided

        or if `units` is not one of 'frames', 'samples', or 'time'

    See Also
    --------
    librosa.onset.onset_strength

    Examples
    --------
    Track beats using time series input

    >>> y, sr = librosa.load(librosa.util.example_audio_file())

    >>> tempo, beats = librosa.beat.beat_track(y=y, sr=sr)
    >>> tempo
    64.599609375

    Print the first 20 beat frames

    >>> beats[:20]
    array([ 320,  357,  397,  436,  480,  525,  569,  609,  658,
            698,  737,  777,  817,  857,  896,  936,  976, 1016,
           1055, 1095])

    Or print them as timestamps

    >>> librosa.frames_to_time(beats[:20], sr=sr)
    array([  7.43 ,   8.29 ,   9.218,  10.124,  11.146,  12.19 ,
            13.212,  14.141,  15.279,  16.208,  17.113,  18.042,
            18.971,  19.9  ,  20.805,  21.734,  22.663,  23.591,
            24.497,  25.426])

    Track beats using a pre-computed onset envelope

    >>> onset_env = librosa.onset.onset_strength(y, sr=sr,
    ...                                          aggregate=np.median)
    >>> tempo, beats = librosa.beat.beat_track(onset_envelope=onset_env,
    ...                                        sr=sr)
    >>> tempo
    64.599609375
    >>> beats[:20]
    array([ 320,  357,  397,  436,  480,  525,  569,  609,  658,
            698,  737,  777,  817,  857,  896,  936,  976, 1016,
           1055, 1095])

    Plot the beat events against the onset strength envelope

    >>> import matplotlib.pyplot as plt
    >>> hop_length = 512
    >>> plt.figure(figsize=(8, 4))
    >>> times = librosa.frames_to_time(np.arange(len(onset_env)),
    ...                                sr=sr, hop_length=hop_length)
    >>> plt.plot(times, librosa.util.normalize(onset_env),
    ...          label='Onset strength')
    >>> plt.vlines(times[beats], 0, 1, alpha=0.5, color='r',
    ...            linestyle='--', label='Beats')
    >>> plt.legend(frameon=True, framealpha=0.75)
    >>> # Limit the plot to a 15-second window
    >>> plt.xlim(15, 30)
    >>> plt.gca().xaxis.set_major_formatter(librosa.display.TimeFormatter())
    >>> plt.tight_layout()
    '''

    # First, get the frame->beat strength profile if we don't already have one
    if onset_envelope is None:
        if y is None:
            raise ParameterError('y or onset_envelope must be provided')

        onset_envelope = onset.onset_strength(y=y,
                                              sr=sr,
                                              hop_length=hop_length,
                                              aggregate=np.median)

    # Do we have any onsets to grab?
    if not onset_envelope.any():
        return (0, np.array([], dtype=int))

    # Estimate BPM if one was not provided
    if bpm is None:
        bpm = tempo(onset_envelope=onset_envelope,
                    sr=sr,
                    hop_length=hop_length,
                    start_bpm=start_bpm)[0]

    # Then, run the tracker
    beats = __beat_tracker(onset_envelope,
                           bpm,
                           float(sr) / hop_length,
                           tightness,
                           trim)

    if units == 'frames':
        pass
    elif units == 'samples':
        beats = core.frames_to_samples(beats, hop_length=hop_length)
    elif units == 'time':
        beats = core.frames_to_time(beats, hop_length=hop_length, sr=sr)
    else:
        raise ParameterError('Invalid unit type: {}'.format(units))

    return (bpm, beats)

def
beat_track
(
y
=
,
sr
=
22050
,
onset_envelope
=
,
hop_length
=
512
,
start_bpm
=
120.0
,
tightness
=
100
,
trim
=
True
,
bpm
=
,
units
=
'frames'
)
:
r
if
onset_envelope
is
:
if
y
is
:
raise
ParameterError
(
'y or onset_envelope must be provided'
)
onset_envelope
=
onset
.
onset_strength
(
y
=
y
,
sr
=
sr
,
hop_length
=
hop_length
,
aggregate
=
np
.
median
)
if
not
onset_envelope
.
any
(
)
:
return
(
0
,
np
.
array
(
[
]
,
dtype
=
int
)
)
if
bpm
is
:
bpm
=
tempo
(
onset_envelope
=
onset_envelope
,
sr
=
sr
,
hop_length
=
hop_length
,
start_bpm
=
start_bpm
)
[
0
]
beats
=
__beat_tracker
(
onset_envelope
,
bpm
,
float
(
sr
)
/
hop_length
,
tightness
,
trim
)
if
units
==
'frames'
:
pass
elif
units
==
'samples'
:
beats
=
core
.
frames_to_samples
(
beats
,
hop_length
=
hop_length
)
elif
units
==
'time'
:
beats
=
core
.
frames_to_time
(
beats
,
hop_length
=
hop_length
,
sr
=
sr
)
else
:
raise
ParameterError
(
'Invalid unit type: {}'
.
format
(
units
)
)
return
(
bpm
,
beats
)


def __beat_tracker(onset_envelope, bpm, fft_res, tightness, trim):
    """Internal function that tracks beats in an onset strength envelope.

    Parameters
    ----------
    onset_envelope : np.ndarray [shape=(n,)]
        onset strength envelope

    bpm : float [scalar]
        tempo estimate

    fft_res  : float [scalar]
        resolution of the fft (sr / hop_length)

    tightness: float [scalar]
        how closely do we adhere to bpm?

    trim : bool [scalar]
        trim leading/trailing beats with weak onsets?

    Returns
    -------
    beats : np.ndarray [shape=(n,)]
        frame numbers of beat events
    """

    if bpm <= 0:
        raise ParameterError('bpm must be strictly positive')

    # convert bpm to a sample period for searching
    period = round(60.0 * fft_res / bpm)

    # localscore is a smoothed version of AGC'd onset envelope
    localscore = __beat_local_score(onset_envelope, period)

    # run the DP
    backlink, cumscore = __beat_track_dp(localscore, period, tightness)

    # get the position of the last beat
    beats = [__last_beat(cumscore)]

    # Reconstruct the beat path from backlinks
    while backlink[beats[-1]] >= 0:
        beats.append(backlink[beats[-1]])

    # Put the beats in ascending order
    # Convert into an array of frame numbers
    beats = np.array(beats[::-1], dtype=int)

    # Discard spurious trailing beats
    beats = __trim_beats(localscore, beats, trim)

    return beats

def
__beat_tracker
(
onset_envelope
,
bpm
,
fft_res
,
tightness
,
trim
)
:
if
bpm
<=
0
:
raise
ParameterError
(
'bpm must be strictly positive'
)
period
=
round
(
60.0
*
fft_res
/
bpm
)
localscore
=
__beat_local_score
(
onset_envelope
,
period
)
backlink
,
cumscore
=
__beat_track_dp
(
localscore
,
period
,
tightness
)
beats
=
[
__last_beat
(
cumscore
)
]
while
backlink
[
beats
[
1
]
]
>=
0
:
beats
.
append
(
backlink
[
beats
[
1
]
]
)
beats
=
np
.
array
(
beats
[
:
:
1
]
,
dtype
=
int
)
beats
=
__trim_beats
(
localscore
,
beats
,
trim
)
return
beats

Internal function that tracks beats in an onset strength envelope .


def __beat_local_score(onset_envelope, period):
    '''Construct the local score for an onset envlope and given period'''

    window = np.exp(-0.5 * (np.arange(-period, period+1)*32.0/period)**2)
    return scipy.signal.convolve(__normalize_onsets(onset_envelope),
                                 window,
                                 'same')

def __beat_local_score ( onset_envelope , period ) : window = np . exp ( - 0.5 * ( np . arange ( - period , period + 1 ) * 32.0 / period ) ** 2 ) return scipy . signal . convolve ( __normalize_onsets ( onset_envelope ) , window , 'same' )


def __beat_track_dp(localscore, period, tightness):
    """Core dynamic program for beat tracking"""

    backlink = np.zeros_like(localscore, dtype=int)
    cumscore = np.zeros_like(localscore)

    # Search range for previous beat
    window = np.arange(-2 * period, -np.round(period / 2) + 1, dtype=int)

    # Make a score window, which begins biased toward start_bpm and skewed
    if tightness <= 0:
        raise ParameterError('tightness must be strictly positive')

    txwt = -tightness * (np.log(-window / period) ** 2)

    # Are we on the first beat?
    first_beat = True
    for i, score_i in enumerate(localscore):

        # Are we reaching back before time 0?
        z_pad = np.maximum(0, min(- window[0], len(window)))

        # Search over all possible predecessors
        candidates = txwt.copy()
        candidates[z_pad:] = candidates[z_pad:] + cumscore[window[z_pad:]]

        # Find the best preceding beat
        beat_location = np.argmax(candidates)

        # Add the local score
        cumscore[i] = score_i + candidates[beat_location]

        # Special case the first onset.  Stop if the localscore is small
        if first_beat and score_i < 0.01 * localscore.max():
            backlink[i] = -1
        else:
            backlink[i] = window[beat_location]
            first_beat = False

        # Update the time range
        window = window + 1

    return backlink, cumscore

def
__beat_track_dp
(
localscore
,
period
,
tightness
)
:
backlink
=
np
.
zeros_like
(
localscore
,
dtype
=
int
)
cumscore
=
np
.
zeros_like
(
localscore
)
window
=
np
.
arange
(
2
*
period
,
np
.
round
(
period
/
2
)
+
1
,
dtype
=
int
)
if
tightness
<=
0
:
raise
ParameterError
(
'tightness must be strictly positive'
)
txwt
=
tightness
*
(
np
.
log
(
window
/
period
)
**
2
)
first_beat
=
True
for
i
,
score_i
in
enumerate
(
localscore
)
:
z_pad
=
np
.
maximum
(
0
,
min
(
window
[
0
]
,
len
(
window
)
)
)
candidates
=
txwt
.
copy
(
)
candidates
[
z_pad
:
]
=
candidates
[
z_pad
:
]
+
cumscore
[
window
[
z_pad
:
]
]
beat_location
=
np
.
argmax
(
candidates
)
cumscore
[
i
]
=
score_i
+
candidates
[
beat_location
]
if
first_beat
and
score_i
<
0.01
*
localscore
.
max
(
)
:
backlink
[
i
]
=
1
else
:
backlink
[
i
]
=
window
[
beat_location
]
first_beat
=
False
window
=
window
+
1
return
backlink
,
cumscore


def __last_beat(cumscore):
    """Get the last beat from the cumulative score array"""

    maxes = util.localmax(cumscore)
    med_score = np.median(cumscore[np.argwhere(maxes)])

    # The last of these is the last beat (since score generally increases)
    return np.argwhere((cumscore * maxes * 2 > med_score)).max()

def __last_beat ( cumscore ) : maxes = util . localmax ( cumscore ) med_score = np . median ( cumscore [ np . argwhere ( maxes ) ] ) return np . argwhere ( ( cumscore * maxes * 2 > med_score ) ) . max ( )


def recurrence_to_lag(rec, pad=True, axis=-1):
    '''Convert a recurrence matrix into a lag matrix.

        `lag[i, j] == rec[i+j, j]`

    Parameters
    ----------
    rec : np.ndarray, or scipy.sparse.spmatrix [shape=(n, n)]
        A (binary) recurrence matrix, as returned by `recurrence_matrix`

    pad : bool
        If False, `lag` matrix is square, which is equivalent to
        assuming that the signal repeats itself indefinitely.

        If True, `lag` is padded with `n` zeros, which eliminates
        the assumption of repetition.

    axis : int
        The axis to keep as the `time` axis.
        The alternate axis will be converted to lag coordinates.

    Returns
    -------
    lag : np.ndarray
        The recurrence matrix in (lag, time) (if `axis=1`)
        or (time, lag) (if `axis=0`) coordinates

    Raises
    ------
    ParameterError : if `rec` is non-square

    See Also
    --------
    recurrence_matrix
    lag_to_recurrence

    Examples
    --------
    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> mfccs = librosa.feature.mfcc(y=y, sr=sr)
    >>> recurrence = librosa.segment.recurrence_matrix(mfccs)
    >>> lag_pad = librosa.segment.recurrence_to_lag(recurrence, pad=True)
    >>> lag_nopad = librosa.segment.recurrence_to_lag(recurrence, pad=False)

    >>> import matplotlib.pyplot as plt
    >>> plt.figure(figsize=(8, 4))
    >>> plt.subplot(1, 2, 1)
    >>> librosa.display.specshow(lag_pad, x_axis='time', y_axis='lag')
    >>> plt.title('Lag (zero-padded)')
    >>> plt.subplot(1, 2, 2)
    >>> librosa.display.specshow(lag_nopad, x_axis='time')
    >>> plt.title('Lag (no padding)')
    >>> plt.tight_layout()
    '''

    axis = np.abs(axis)

    if rec.ndim != 2 or rec.shape[0] != rec.shape[1]:
        raise ParameterError('non-square recurrence matrix shape: '
                             '{}'.format(rec.shape))

    sparse = scipy.sparse.issparse(rec)

    roll_ax = None
    if sparse:
        roll_ax = 1 - axis
        lag_format = rec.format
        if axis == 0:
            rec = rec.tocsc()
        elif axis in (-1, 1):
            rec = rec.tocsr()

    t = rec.shape[axis]

    if sparse:
        if pad:
            kron = np.asarray([[1, 0]]).swapaxes(axis, 0)
            lag = scipy.sparse.kron(kron.astype(rec.dtype), rec, format='lil')
        else:
            lag = scipy.sparse.lil_matrix(rec)
    else:
        if pad:
            padding = [(0, 0), (0, 0)]
            padding[(1-axis)] = (0, t)
            lag = np.pad(rec, padding, mode='constant')
        else:
            lag = rec.copy()

    idx_slice = [slice(None)] * lag.ndim

    for i in range(1, t):
        idx_slice[axis] = i
        lag[tuple(idx_slice)] = util.roll_sparse(lag[tuple(idx_slice)], -i, axis=roll_ax)

    if sparse:
        return lag.asformat(lag_format)
    return np.ascontiguousarray(lag.T).T

def
recurrence_to_lag
(
rec
,
pad
=
True
,
axis
=
1
)
:
axis
=
np
.
abs
(
axis
)
if
rec
.
ndim
!=
2
or
rec
.
shape
[
0
]
!=
rec
.
shape
[
1
]
:
raise
ParameterError
(
'non-square recurrence matrix shape: '
'{}'
.
format
(
rec
.
shape
)
)
sparse
=
scipy
.
sparse
.
issparse
(
rec
)
roll_ax
=
if
sparse
:
roll_ax
=
1
axis
lag_format
=
rec
.
format
if
axis
==
0
:
rec
=
rec
.
tocsc
(
)
elif
axis
in
(
1
,
1
)
:
rec
=
rec
.
tocsr
(
)
t
=
rec
.
shape
[
axis
]
if
sparse
:
if
pad
:
kron
=
np
.
asarray
(
[
[
1
,
0
]
]
)
.
swapaxes
(
axis
,
0
)
lag
=
scipy
.
sparse
.
kron
(
kron
.
astype
(
rec
.
dtype
)
,
rec
,
format
=
'lil'
)
else
:
lag
=
scipy
.
sparse
.
lil_matrix
(
rec
)
else
:
if
pad
:
padding
=
[
(
0
,
0
)
,
(
0
,
0
)
]
padding
[
(
1
axis
)
]
=
(
0
,
t
)
lag
=
np
.
pad
(
rec
,
padding
,
mode
=
'constant'
)
else
:
lag
=
rec
.
copy
(
)
idx_slice
=
[
slice
(
)
]
*
lag
.
ndim
for
i
in
range
(
1
,
t
)
:
idx_slice
[
axis
]
=
i
lag
[
tuple
(
idx_slice
)
]
=
util
.
roll_sparse
(
lag
[
tuple
(
idx_slice
)
]
,
i
,
axis
=
roll_ax
)
if
sparse
:
return
lag
.
asformat
(
lag_format
)
return
np
.
ascontiguousarray
(
lag
.
T
)
.
T

Convert a recurrence matrix into a lag matrix .


def lag_to_recurrence(lag, axis=-1):
    '''Convert a lag matrix into a recurrence matrix.

    Parameters
    ----------
    lag : np.ndarray or scipy.sparse.spmatrix
        A lag matrix, as produced by `recurrence_to_lag`

    axis : int
        The axis corresponding to the time dimension.
        The alternate axis will be interpreted in lag coordinates.

    Returns
    -------
    rec : np.ndarray or scipy.sparse.spmatrix [shape=(n, n)]
        A recurrence matrix in (time, time) coordinates
        For sparse matrices, format will match that of `lag`.

    Raises
    ------
    ParameterError : if `lag` does not have the correct shape

    See Also
    --------
    recurrence_to_lag

    Examples
    --------
    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> mfccs = librosa.feature.mfcc(y=y, sr=sr)
    >>> recurrence = librosa.segment.recurrence_matrix(mfccs)
    >>> lag_pad = librosa.segment.recurrence_to_lag(recurrence, pad=True)
    >>> lag_nopad = librosa.segment.recurrence_to_lag(recurrence, pad=False)
    >>> rec_pad = librosa.segment.lag_to_recurrence(lag_pad)
    >>> rec_nopad = librosa.segment.lag_to_recurrence(lag_nopad)

    >>> import matplotlib.pyplot as plt
    >>> plt.figure(figsize=(8, 4))
    >>> plt.subplot(2, 2, 1)
    >>> librosa.display.specshow(lag_pad, x_axis='time', y_axis='lag')
    >>> plt.title('Lag (zero-padded)')
    >>> plt.subplot(2, 2, 2)
    >>> librosa.display.specshow(lag_nopad, x_axis='time', y_axis='time')
    >>> plt.title('Lag (no padding)')
    >>> plt.subplot(2, 2, 3)
    >>> librosa.display.specshow(rec_pad, x_axis='time', y_axis='time')
    >>> plt.title('Recurrence (with padding)')
    >>> plt.subplot(2, 2, 4)
    >>> librosa.display.specshow(rec_nopad, x_axis='time', y_axis='time')
    >>> plt.title('Recurrence (without padding)')
    >>> plt.tight_layout()

    '''

    if axis not in [0, 1, -1]:
        raise ParameterError('Invalid target axis: {}'.format(axis))

    axis = np.abs(axis)

    if lag.ndim != 2 or (lag.shape[0] != lag.shape[1] and
                         lag.shape[1 - axis] != 2 * lag.shape[axis]):
        raise ParameterError('Invalid lag matrix shape: {}'.format(lag.shape))

    # Since lag must be 2-dimensional, abs(axis) = axis
    t = lag.shape[axis]

    sparse = scipy.sparse.issparse(lag)
    if sparse:
        rec = scipy.sparse.lil_matrix(lag)
        roll_ax = 1 - axis
    else:
        rec = lag.copy()
        roll_ax = None

    idx_slice = [slice(None)] * lag.ndim
    for i in range(1, t):
        idx_slice[axis] = i
        rec[tuple(idx_slice)] = util.roll_sparse(lag[tuple(idx_slice)], i, axis=roll_ax)

    sub_slice = [slice(None)] * rec.ndim
    sub_slice[1 - axis] = slice(t)
    rec = rec[tuple(sub_slice)]

    if sparse:
        return rec.asformat(lag.format)
    return np.ascontiguousarray(rec.T).T

def
lag_to_recurrence
(
lag
,
axis
=
1
)
:
if
axis
not
in
[
0
,
1
,
1
]
:
raise
ParameterError
(
'Invalid target axis: {}'
.
format
(
axis
)
)
axis
=
np
.
abs
(
axis
)
if
lag
.
ndim
!=
2
or
(
lag
.
shape
[
0
]
!=
lag
.
shape
[
1
]
and
lag
.
shape
[
1
axis
]
!=
2
*
lag
.
shape
[
axis
]
)
:
raise
ParameterError
(
'Invalid lag matrix shape: {}'
.
format
(
lag
.
shape
)
)
t
=
lag
.
shape
[
axis
]
sparse
=
scipy
.
sparse
.
issparse
(
lag
)
if
sparse
:
rec
=
scipy
.
sparse
.
lil_matrix
(
lag
)
roll_ax
=
1
axis
else
:
rec
=
lag
.
copy
(
)
roll_ax
=
idx_slice
=
[
slice
(
)
]
*
lag
.
ndim
for
i
in
range
(
1
,
t
)
:
idx_slice
[
axis
]
=
i
rec
[
tuple
(
idx_slice
)
]
=
util
.
roll_sparse
(
lag
[
tuple
(
idx_slice
)
]
,
i
,
axis
=
roll_ax
)
sub_slice
=
[
slice
(
)
]
*
rec
.
ndim
sub_slice
[
1
axis
]
=
slice
(
t
)
rec
=
rec
[
tuple
(
sub_slice
)
]
if
sparse
:
return
rec
.
asformat
(
lag
.
format
)
return
np
.
ascontiguousarray
(
rec
.
T
)
.
T

Convert a lag matrix into a recurrence matrix .


def timelag_filter(function, pad=True, index=0):
    '''Filtering in the time-lag domain.

    This is primarily useful for adapting image filters to operate on
    `recurrence_to_lag` output.

    Using `timelag_filter` is equivalent to the following sequence of
    operations:

    >>> data_tl = librosa.segment.recurrence_to_lag(data)
    >>> data_filtered_tl = function(data_tl)
    >>> data_filtered = librosa.segment.lag_to_recurrence(data_filtered_tl)

    Parameters
    ----------
    function : callable
        The filtering function to wrap, e.g., `scipy.ndimage.median_filter`

    pad : bool
        Whether to zero-pad the structure feature matrix

    index : int >= 0
        If `function` accepts input data as a positional argument, it should be
        indexed by `index`

    Returns
    -------
    wrapped_function : callable
        A new filter function which applies in time-lag space rather than
        time-time space.

    Examples
    --------

    Apply a 5-bin median filter to the diagonal of a recurrence matrix

    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
    >>> rec = librosa.segment.recurrence_matrix(chroma)
    >>> from scipy.ndimage import median_filter
    >>> diagonal_median = librosa.segment.timelag_filter(median_filter)
    >>> rec_filtered = diagonal_median(rec, size=(1, 3), mode='mirror')

    Or with affinity weights

    >>> rec_aff = librosa.segment.recurrence_matrix(chroma, mode='affinity')
    >>> rec_aff_fil = diagonal_median(rec_aff, size=(1, 3), mode='mirror')

    >>> import matplotlib.pyplot as plt
    >>> plt.figure(figsize=(8,8))
    >>> plt.subplot(2, 2, 1)
    >>> librosa.display.specshow(rec, y_axis='time')
    >>> plt.title('Raw recurrence matrix')
    >>> plt.subplot(2, 2, 2)
    >>> librosa.display.specshow(rec_filtered)
    >>> plt.title('Filtered recurrence matrix')
    >>> plt.subplot(2, 2, 3)
    >>> librosa.display.specshow(rec_aff, x_axis='time', y_axis='time',
    ...                          cmap='magma_r')
    >>> plt.title('Raw affinity matrix')
    >>> plt.subplot(2, 2, 4)
    >>> librosa.display.specshow(rec_aff_fil, x_axis='time',
    ...                          cmap='magma_r')
    >>> plt.title('Filtered affinity matrix')
    >>> plt.tight_layout()
    '''

    def __my_filter(wrapped_f, *args, **kwargs):
        '''Decorator to wrap the filter'''
        # Map the input data into time-lag space
        args = list(args)

        args[index] = recurrence_to_lag(args[index], pad=pad)

        # Apply the filtering function
        result = wrapped_f(*args, **kwargs)

        # Map back into time-time and return
        return lag_to_recurrence(result)

    return decorator(__my_filter, function)

def timelag_filter ( function , pad = True , index = 0 ) : def __my_filter ( wrapped_f , * args , ** kwargs ) : args = list ( args ) args [ index ] = recurrence_to_lag ( args [ index ] , pad = pad ) result = wrapped_f ( * args , ** kwargs ) return lag_to_recurrence ( result ) return decorator ( __my_filter , function )


def subsegment(data, frames, n_segments=4, axis=-1):
    '''Sub-divide a segmentation by feature clustering.

    Given a set of frame boundaries (`frames`), and a data matrix (`data`),
    each successive interval defined by `frames` is partitioned into
    `n_segments` by constrained agglomerative clustering.

    .. note::
        If an interval spans fewer than `n_segments` frames, then each
        frame becomes a sub-segment.

    Parameters
    ----------
    data : np.ndarray
        Data matrix to use in clustering

    frames : np.ndarray [shape=(n_boundaries,)], dtype=int, non-negative]
        Array of beat or segment boundaries, as provided by
        `librosa.beat.beat_track`,
        `librosa.onset.onset_detect`,
        or `agglomerative`.

    n_segments : int > 0
        Maximum number of frames to sub-divide each interval.

    axis : int
        Axis along which to apply the segmentation.
        By default, the last index (-1) is taken.

    Returns
    -------
    boundaries : np.ndarray [shape=(n_subboundaries,)]
        List of sub-divided segment boundaries

    See Also
    --------
    agglomerative : Temporal segmentation
    librosa.onset.onset_detect : Onset detection
    librosa.beat.beat_track : Beat tracking

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

    Examples
    --------
    Load audio, detect beat frames, and subdivide in twos by CQT

    >>> y, sr = librosa.load(librosa.util.example_audio_file(), duration=8)
    >>> tempo, beats = librosa.beat.beat_track(y=y, sr=sr, hop_length=512)
    >>> beat_times = librosa.frames_to_time(beats, sr=sr, hop_length=512)
    >>> cqt = np.abs(librosa.cqt(y, sr=sr, hop_length=512))
    >>> subseg = librosa.segment.subsegment(cqt, beats, n_segments=2)
    >>> subseg_t = librosa.frames_to_time(subseg, sr=sr, hop_length=512)
    >>> subseg
    array([  0,   2,   4,  21,  23,  26,  43,  55,  63,  72,  83,
            97, 102, 111, 122, 137, 142, 153, 162, 180, 182, 185,
           202, 210, 221, 231, 241, 256, 261, 271, 281, 296, 301,
           310, 320, 339, 341, 344, 361, 368, 382, 389, 401, 416,
           420, 430, 436, 451, 456, 465, 476, 489, 496, 503, 515,
           527, 535, 544, 553, 558, 571, 578, 590, 607, 609, 638])

    >>> import matplotlib.pyplot as plt
    >>> plt.figure()
    >>> librosa.display.specshow(librosa.amplitude_to_db(cqt,
    ...                                                  ref=np.max),
    ...                          y_axis='cqt_hz', x_axis='time')
    >>> lims = plt.gca().get_ylim()
    >>> plt.vlines(beat_times, lims[0], lims[1], color='lime', alpha=0.9,
    ...            linewidth=2, label='Beats')
    >>> plt.vlines(subseg_t, lims[0], lims[1], color='linen', linestyle='--',
    ...            linewidth=1.5, alpha=0.5, label='Sub-beats')
    >>> plt.legend(frameon=True, shadow=True)
    >>> plt.title('CQT + Beat and sub-beat markers')
    >>> plt.tight_layout()

    '''

    frames = util.fix_frames(frames, x_min=0, x_max=data.shape[axis], pad=True)

    if n_segments < 1:
        raise ParameterError('n_segments must be a positive integer')

    boundaries = []
    idx_slices = [slice(None)] * data.ndim

    for seg_start, seg_end in zip(frames[:-1], frames[1:]):
        idx_slices[axis] = slice(seg_start, seg_end)
        boundaries.extend(seg_start + agglomerative(data[tuple(idx_slices)],
                                                    min(seg_end - seg_start, n_segments),
                                                    axis=axis))

    return np.ascontiguousarray(boundaries)

def
subsegment
(
data
,
frames
,
n_segments
=
4
,
axis
=
1
)
:
frames
=
util
.
fix_frames
(
frames
,
x_min
=
0
,
x_max
=
data
.
shape
[
axis
]
,
pad
=
True
)
if
n_segments
<
1
:
raise
ParameterError
(
'n_segments must be a positive integer'
)
boundaries
=
[
]
idx_slices
=
[
slice
(
)
]
*
data
.
ndim
for
seg_start
,
seg_end
in
zip
(
frames
[
:
1
]
,
frames
[
1
:
]
)
:
idx_slices
[
axis
]
=
slice
(
seg_start
,
seg_end
)
boundaries
.
extend
(
seg_start
+
agglomerative
(
data
[
tuple
(
idx_slices
)
]
,
min
(
seg_end
seg_start
,
n_segments
)
,
axis
=
axis
)
)
return
np
.
ascontiguousarray
(
boundaries
)

Sub - divide a segmentation by feature clustering .


def agglomerative(data, k, clusterer=None, axis=-1):
    """Bottom-up temporal segmentation.

    Use a temporally-constrained agglomerative clustering routine to partition
    `data` into `k` contiguous segments.

    Parameters
    ----------
    data     : np.ndarray
        data to cluster

    k        : int > 0 [scalar]
        number of segments to produce

    clusterer : sklearn.cluster.AgglomerativeClustering, optional
        An optional AgglomerativeClustering object.
        If `None`, a constrained Ward object is instantiated.

    axis : int
        axis along which to cluster.
        By default, the last axis (-1) is chosen.

    Returns
    -------
    boundaries : np.ndarray [shape=(k,)]
        left-boundaries (frame numbers) of detected segments. This
        will always include `0` as the first left-boundary.

    See Also
    --------
    sklearn.cluster.AgglomerativeClustering

    Examples
    --------
    Cluster by chroma similarity, break into 20 segments

    >>> y, sr = librosa.load(librosa.util.example_audio_file(), duration=15)
    >>> chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
    >>> bounds = librosa.segment.agglomerative(chroma, 20)
    >>> bound_times = librosa.frames_to_time(bounds, sr=sr)
    >>> bound_times
    array([  0.   ,   1.672,   2.322,   2.624,   3.251,   3.506,
             4.18 ,   5.387,   6.014,   6.293,   6.943,   7.198,
             7.848,   9.033,   9.706,   9.961,  10.635,  10.89 ,
            11.54 ,  12.539])

    Plot the segmentation over the chromagram

    >>> import matplotlib.pyplot as plt
    >>> plt.figure()
    >>> librosa.display.specshow(chroma, y_axis='chroma', x_axis='time')
    >>> plt.vlines(bound_times, 0, chroma.shape[0], color='linen', linestyle='--',
    ...            linewidth=2, alpha=0.9, label='Segment boundaries')
    >>> plt.axis('tight')
    >>> plt.legend(frameon=True, shadow=True)
    >>> plt.title('Power spectrogram')
    >>> plt.tight_layout()

    """

    # Make sure we have at least two dimensions
    data = np.atleast_2d(data)

    # Swap data index to position 0
    data = np.swapaxes(data, axis, 0)

    # Flatten the features
    n = data.shape[0]
    data = data.reshape((n, -1))

    if clusterer is None:
        # Connect the temporal connectivity graph
        grid = sklearn.feature_extraction.image.grid_to_graph(n_x=n,
                                                              n_y=1, n_z=1)

        # Instantiate the clustering object
        clusterer = sklearn.cluster.AgglomerativeClustering(n_clusters=k,
                                                            connectivity=grid,
                                                            memory=cache.memory)

    # Fit the model
    clusterer.fit(data)

    # Find the change points from the labels
    boundaries = [0]
    boundaries.extend(
        list(1 + np.nonzero(np.diff(clusterer.labels_))[0].astype(int)))
    return np.asarray(boundaries)

def agglomerative ( data , k , clusterer = None , axis = - 1 ) : data = np . atleast_2d ( data ) data = np . swapaxes ( data , axis , 0 ) n = data . shape [ 0 ] data = data . reshape ( ( n , - 1 ) ) if clusterer is None : grid = sklearn . feature_extraction . image . grid_to_graph ( n_x = n , n_y = 1 , n_z = 1 ) clusterer = sklearn . cluster . AgglomerativeClustering ( n_clusters = k , connectivity = grid , memory = cache . memory ) clusterer . fit ( data ) boundaries = [ 0 ] boundaries . extend ( list ( 1 + np . nonzero ( np . diff ( clusterer . labels_ ) ) [ 0 ] . astype ( int ) ) ) return np . asarray ( boundaries )


def path_enhance(R, n, window='hann', max_ratio=2.0, min_ratio=None, n_filters=7,
                 zero_mean=False, clip=True, **kwargs):
    '''Multi-angle path enhancement for self- and cross-similarity matrices.

    This function convolves multiple diagonal smoothing filters with a self-similarity (or
    recurrence) matrix R, and aggregates the result by an element-wise maximum.

    Technically, the output is a matrix R_smooth such that

        `R_smooth[i, j] = max_theta (R * filter_theta)[i, j]`

    where `*` denotes 2-dimensional convolution, and `filter_theta` is a smoothing filter at
    orientation theta.

    This is intended to provide coherent temporal smoothing of self-similarity matrices
    when there are changes in tempo.

    Smoothing filters are generated at evenly spaced orientations between min_ratio and
    max_ratio.

    This function is inspired by the multi-angle path enhancement of [1]_, but differs by
    modeling tempo differences in the space of similarity matrices rather than re-sampling
    the underlying features prior to generating the self-similarity matrix.

    .. [1] Müller, Meinard and Frank Kurth.
            "Enhancing similarity matrices for music audio analysis."
            2006 IEEE International Conference on Acoustics Speech and Signal Processing Proceedings.
            Vol. 5. IEEE, 2006.

    .. note:: if using recurrence_matrix to construct the input similarity matrix, be sure to include the main
              diagonal by setting `self=True`.  Otherwise, the diagonal will be suppressed, and this is likely to
              produce discontinuities which will pollute the smoothing filter response.

    Parameters
    ----------
    R : np.ndarray
        The self- or cross-similarity matrix to be smoothed.
        Note: sparse inputs are not supported.

    n : int > 0
        The length of the smoothing filter

    window : window specification
        The type of smoothing filter to use.  See `filters.get_window` for more information
        on window specification formats.

    max_ratio : float > 0
        The maximum tempo ratio to support

    min_ratio : float > 0
        The minimum tempo ratio to support.
        If not provided, it will default to `1/max_ratio`

    n_filters : int >= 1
        The number of different smoothing filters to use, evenly spaced
        between `min_ratio` and `max_ratio`.

        If `min_ratio = 1/max_ratio` (the default), using an odd number
        of filters will ensure that the main diagonal (ratio=1) is included.

    zero_mean : bool
        By default, the smoothing filters are non-negative and sum to one (i.e. are averaging
        filters).

        If `zero_mean=True`, then the smoothing filters are made to sum to zero by subtracting
        a constant value from the non-diagonal coordinates of the filter.  This is primarily
        useful for suppressing blocks while enhancing diagonals.

    clip : bool
        If True, the smoothed similarity matrix will be thresholded at 0, and will not contain
        negative entries.

    kwargs : additional keyword arguments
        Additional arguments to pass to `scipy.ndimage.convolve`

    Returns
    -------
    R_smooth : np.ndarray, shape=R.shape
        The smoothed self- or cross-similarity matrix

    See Also
    --------
    filters.diagonal_filter
    recurrence_matrix

    Examples
    --------
    Use a 51-frame diagonal smoothing filter to enhance paths in a recurrence matrix

    >>> y, sr = librosa.load(librosa.util.example_audio_file(), duration=30)
    >>> chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
    >>> rec = librosa.segment.recurrence_matrix(chroma, mode='affinity', self=True)
    >>> rec_smooth = librosa.segment.path_enhance(rec, 51, window='hann', n_filters=7)

    Plot the recurrence matrix before and after smoothing

    >>> import matplotlib.pyplot as plt
    >>> plt.figure(figsize=(8, 4))
    >>> plt.subplot(1,2,1)
    >>> librosa.display.specshow(rec, x_axis='time', y_axis='time')
    >>> plt.title('Unfiltered recurrence')
    >>> plt.subplot(1,2,2)
    >>> librosa.display.specshow(rec_smooth, x_axis='time', y_axis='time')
    >>> plt.title('Multi-angle enhanced recurrence')
    >>> plt.tight_layout()
    '''

    if min_ratio is None:
        min_ratio = 1./max_ratio
    elif min_ratio > max_ratio:
        raise ParameterError('min_ratio={} cannot exceed max_ratio={}'.format(min_ratio, max_ratio))

    R_smooth = None
    for ratio in np.logspace(np.log2(min_ratio), np.log2(max_ratio), num=n_filters, base=2):
        kernel = diagonal_filter(window, n, slope=ratio, zero_mean=zero_mean)

        if R_smooth is None:
            R_smooth = scipy.ndimage.convolve(R, kernel, **kwargs)
        else:
            # Compute the point-wise maximum in-place
            np.maximum(R_smooth, scipy.ndimage.convolve(R, kernel, **kwargs),
                       out=R_smooth)

    if clip:
        # Clip the output in-place
        np.clip(R_smooth, 0, None, out=R_smooth)

    return R_smooth

Multi - angle path enhancement for self - and cross - similarity matrices .


def onset_detect(input_file, output_csv):
    '''Onset detection function

    :parameters:
      - input_file : str
          Path to input audio file (wav, mp3, m4a, flac, etc.)

      - output_file : str
          Path to save onset timestamps as a CSV file
    '''

    # 1. load the wav file and resample to 22.050 KHz
    print('Loading ', input_file)
    y, sr = librosa.load(input_file, sr=22050)

    # Use a default hop size of 512 frames @ 22KHz ~= 23ms
    hop_length = 512

    # 2. run onset detection
    print('Detecting onsets...')
    onsets = librosa.onset.onset_detect(y=y,
                                        sr=sr,
                                        hop_length=hop_length)

    print("Found {:d} onsets.".format(onsets.shape[0]))

    # 3. save output
    # 'beats' will contain the frame numbers of beat events.

    onset_times = librosa.frames_to_time(onsets,
                                         sr=sr,
                                         hop_length=hop_length)

    print('Saving output to ', output_csv)
    librosa.output.times_csv(output_csv, onset_times)
    print('done!')

def
onset_detect
(
input_file
,
output_csv
)
:
print
(
'Loading '
,
input_file
)
y
,
sr
=
librosa
.
load
(
input_file
,
sr
=
22050
)
hop_length
=
512
print
(
'Detecting onsets...'
)
onsets
=
librosa
.
onset
.
onset_detect
(
y
=
y
,
sr
=
sr
,
hop_length
=
hop_length
)
print
(
"Found {:d} onsets."
.
format
(
onsets
.
shape
[
0
]
)
)
onset_times
=
librosa
.
frames_to_time
(
onsets
,
sr
=
sr
,
hop_length
=
hop_length
)
print
(
'Saving output to '
,
output_csv
)
librosa
.
output
.
times_csv
(
output_csv
,
onset_times
)
print
(
'done!'
)


def frame(y, frame_length=2048, hop_length=512):
    '''Slice a time series into overlapping frames.

    This implementation uses low-level stride manipulation to avoid
    redundant copies of the time series data.

    Parameters
    ----------
    y : np.ndarray [shape=(n,)]
        Time series to frame. Must be one-dimensional and contiguous
        in memory.

    frame_length : int > 0 [scalar]
        Length of the frame in samples

    hop_length : int > 0 [scalar]
        Number of samples to hop between frames

    Returns
    -------
    y_frames : np.ndarray [shape=(frame_length, N_FRAMES)]
        An array of frames sampled from `y`:
        `y_frames[i, j] == y[j * hop_length + i]`

    Raises
    ------
    ParameterError
        If `y` is not contiguous in memory, not an `np.ndarray`, or
        not one-dimensional.  See `np.ascontiguous()` for details.

        If `hop_length < 1`, frames cannot advance.

        If `len(y) < frame_length`.

    Examples
    --------
    Extract 2048-sample frames from `y` with a hop of 64 samples per frame

    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> librosa.util.frame(y, frame_length=2048, hop_length=64)
    array([[ -9.216e-06,   7.710e-06, ...,  -2.117e-06,  -4.362e-07],
           [  2.518e-06,  -6.294e-06, ...,  -1.775e-05,  -6.365e-06],
           ...,
           [ -7.429e-04,   5.173e-03, ...,   1.105e-05,  -5.074e-06],
           [  2.169e-03,   4.867e-03, ...,   3.666e-06,  -5.571e-06]], dtype=float32)

    '''

    if not isinstance(y, np.ndarray):
        raise ParameterError('Input must be of type numpy.ndarray, '
                             'given type(y)={}'.format(type(y)))

    if y.ndim != 1:
        raise ParameterError('Input must be one-dimensional, '
                             'given y.ndim={}'.format(y.ndim))

    if len(y) < frame_length:
        raise ParameterError('Buffer is too short (n={:d})'
                             ' for frame_length={:d}'.format(len(y), frame_length))

    if hop_length < 1:
        raise ParameterError('Invalid hop_length: {:d}'.format(hop_length))

    if not y.flags['C_CONTIGUOUS']:
        raise ParameterError('Input buffer must be contiguous.')

    # Compute the number of frames that will fit. The end may get truncated.
    n_frames = 1 + int((len(y) - frame_length) / hop_length)

    # Vertical stride is one sample
    # Horizontal stride is `hop_length` samples
    y_frames = as_strided(y, shape=(frame_length, n_frames),
                          strides=(y.itemsize, hop_length * y.itemsize))
    return y_frames

def
frame
(
y
,
frame_length
=
2048
,
hop_length
=
512
)
:
if
not
isinstance
(
y
,
np
.
ndarray
)
:
raise
ParameterError
(
'Input must be of type numpy.ndarray, '
'given type(y)={}'
.
format
(
type
(
y
)
)
)
if
y
.
ndim
!=
1
:
raise
ParameterError
(
'Input must be one-dimensional, '
'given y.ndim={}'
.
format
(
y
.
ndim
)
)
if
len
(
y
)
<
frame_length
:
raise
ParameterError
(
'Buffer is too short (n={:d})'
' for frame_length={:d}'
.
format
(
len
(
y
)
,
frame_length
)
)
if
hop_length
<
1
:
raise
ParameterError
(
'Invalid hop_length: {:d}'
.
format
(
hop_length
)
)
if
not
y
.
flags
[
'C_CONTIGUOUS'
]
:
raise
ParameterError
(
'Input buffer must be contiguous.'
)
n_frames
=
1
+
int
(
(
len
(
y
)
frame_length
)
/
hop_length
)
y_frames
=
as_strided
(
y
,
shape
=
(
frame_length
,
n_frames
)
,
strides
=
(
y
.
itemsize
,
hop_length
*
y
.
itemsize
)
)
return
y_frames

Slice a time series into overlapping frames .


def valid_audio(y, mono=True):
    '''Validate whether a variable contains valid, mono audio data.

    Parameters
    ----------
    y : np.ndarray
      The input data to validate

    mono : bool
      Whether or not to force monophonic audio

    Returns
    -------
    valid : bool
        True if all tests pass

    Raises
    ------
    ParameterError
        If `y` fails to meet the following criteria:
            - `type(y)` is `np.ndarray`
            - `y.dtype` is floating-point
            - `mono == True` and `y.ndim` is not 1
            - `mono == False` and `y.ndim` is not 1 or 2
            - `np.isfinite(y).all()` is not True

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

    Examples
    --------
    >>> # Only allow monophonic signals
    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> librosa.util.valid_audio(y)
    True

    >>> # If we want to allow stereo signals
    >>> y, sr = librosa.load(librosa.util.example_audio_file(), mono=False)
    >>> librosa.util.valid_audio(y, mono=False)
    True
    '''

    if not isinstance(y, np.ndarray):
        raise ParameterError('data must be of type numpy.ndarray')

    if not np.issubdtype(y.dtype, np.floating):
        raise ParameterError('data must be floating-point')

    if mono and y.ndim != 1:
        raise ParameterError('Invalid shape for monophonic audio: '
                             'ndim={:d}, shape={}'.format(y.ndim, y.shape))

    elif y.ndim > 2 or y.ndim == 0:
        raise ParameterError('Audio must have shape (samples,) or (channels, samples). '
                             'Received shape={}'.format(y.shape))

    if not np.isfinite(y).all():
        raise ParameterError('Audio buffer is not finite everywhere')

    return True

Validate whether a variable contains valid mono audio data .


def valid_int(x, cast=None):
    '''Ensure that an input value is integer-typed.
    This is primarily useful for ensuring integrable-valued
    array indices.

    Parameters
    ----------
    x : number
        A scalar value to be cast to int

    cast : function [optional]
        A function to modify `x` before casting.
        Default: `np.floor`

    Returns
    -------
    x_int : int
        `x_int = int(cast(x))`

    Raises
    ------
    ParameterError
        If `cast` is provided and is not callable.
    '''

    if cast is None:
        cast = np.floor

    if not six.callable(cast):
        raise ParameterError('cast parameter must be callable')

    return int(cast(x))

def
valid_int
(
x
,
cast
=
)
:
if
cast
is
:
cast
=
np
.
floor
if
not
six
.
callable
(
cast
)
:
raise
ParameterError
(
'cast parameter must be callable'
)
return
int
(
cast
(
x
)
)

Ensure that an input value is integer - typed . This is primarily useful for ensuring integrable - valued array indices .


def fix_length(data, size, axis=-1, **kwargs):
    '''Fix the length an array `data` to exactly `size`.

    If `data.shape[axis] < n`, pad according to the provided kwargs.
    By default, `data` is padded with trailing zeros.

    Examples
    --------
    >>> y = np.arange(7)
    >>> # Default: pad with zeros
    >>> librosa.util.fix_length(y, 10)
    array([0, 1, 2, 3, 4, 5, 6, 0, 0, 0])
    >>> # Trim to a desired length
    >>> librosa.util.fix_length(y, 5)
    array([0, 1, 2, 3, 4])
    >>> # Use edge-padding instead of zeros
    >>> librosa.util.fix_length(y, 10, mode='edge')
    array([0, 1, 2, 3, 4, 5, 6, 6, 6, 6])

    Parameters
    ----------
    data : np.ndarray
      array to be length-adjusted

    size : int >= 0 [scalar]
      desired length of the array

    axis : int, <= data.ndim
      axis along which to fix length

    kwargs : additional keyword arguments
        Parameters to `np.pad()`

    Returns
    -------
    data_fixed : np.ndarray [shape=data.shape]
        `data` either trimmed or padded to length `size`
        along the specified axis.

    See Also
    --------
    numpy.pad
    '''

    kwargs.setdefault('mode', 'constant')

    n = data.shape[axis]

    if n > size:
        slices = [slice(None)] * data.ndim
        slices[axis] = slice(0, size)
        return data[tuple(slices)]

    elif n < size:
        lengths = [(0, 0)] * data.ndim
        lengths[axis] = (0, size - n)
        return np.pad(data, lengths, **kwargs)

    return data

def fix_length ( data , size , axis = - 1 , ** kwargs ) : kwargs . setdefault ( 'mode' , 'constant' ) n = data . shape [ axis ] if n > size : slices = [ slice ( None ) ] * data . ndim slices [ axis ] = slice ( 0 , size ) return data [ tuple ( slices ) ] elif n < size : lengths = [ ( 0 , 0 ) ] * data . ndim lengths [ axis ] = ( 0 , size - n ) return np . pad ( data , lengths , ** kwargs ) return data

Fix the length an array data to exactly size .


def axis_sort(S, axis=-1, index=False, value=None):
    '''Sort an array along its rows or columns.

    Examples
    --------
    Visualize NMF output for a spectrogram S

    >>> # Sort the columns of W by peak frequency bin
    >>> y, sr = librosa.load(librosa.util.example_audio_file())
    >>> S = np.abs(librosa.stft(y))
    >>> W, H = librosa.decompose.decompose(S, n_components=32)
    >>> W_sort = librosa.util.axis_sort(W)

    Or sort by the lowest frequency bin

    >>> W_sort = librosa.util.axis_sort(W, value=np.argmin)

    Or sort the rows instead of the columns

    >>> W_sort_rows = librosa.util.axis_sort(W, axis=0)

    Get the sorting index also, and use it to permute the rows of H

    >>> W_sort, idx = librosa.util.axis_sort(W, index=True)
    >>> H_sort = H[idx, :]

    >>> import matplotlib.pyplot as plt
    >>> plt.figure()
    >>> plt.subplot(2, 2, 1)
    >>> librosa.display.specshow(librosa.amplitude_to_db(W, ref=np.max),
    ...                          y_axis='log')
    >>> plt.title('W')
    >>> plt.subplot(2, 2, 2)
    >>> librosa.display.specshow(H, x_axis='time')
    >>> plt.title('H')
    >>> plt.subplot(2, 2, 3)
    >>> librosa.display.specshow(librosa.amplitude_to_db(W_sort,
    ...                                                  ref=np.max),
    ...                          y_axis='log')
    >>> plt.title('W sorted')
    >>> plt.subplot(2, 2, 4)
    >>> librosa.display.specshow(H_sort, x_axis='time')
    >>> plt.title('H sorted')
    >>> plt.tight_layout()

    Parameters
    ----------
    S : np.ndarray [shape=(d, n)]
        Array to be sorted

    axis : int [scalar]
        The axis along which to compute the sorting values

        - `axis=0` to sort rows by peak column index
        - `axis=1` to sort columns by peak row index

    index : boolean [scalar]
        If true, returns the index array as well as the permuted data.

    value : function
        function to return the index corresponding to the sort order.
        Default: `np.argmax`.

    Returns
    -------
    S_sort : np.ndarray [shape=(d, n)]
        `S` with the columns or rows permuted in sorting order

    idx : np.ndarray (optional) [shape=(d,) or (n,)]
        If `index == True`, the sorting index used to permute `S`.
        Length of `idx` corresponds to the selected `axis`.

    Raises
    ------
    ParameterError
        If `S` does not have exactly 2 dimensions (`S.ndim != 2`)
    '''

    if value is None:
        value = np.argmax

    if S.ndim != 2:
        raise ParameterError('axis_sort is only defined for 2D arrays')

    bin_idx = value(S, axis=np.mod(1-axis, S.ndim))
    idx = np.argsort(bin_idx)

    sort_slice = [slice(None)] * S.ndim
    sort_slice[axis] = idx

    if index:
        return S[tuple(sort_slice)], idx
    else:
        return S[tuple(sort_slice)]

Sort an array along its rows or columns .