Caution

You're reading the documentation for a development version. For the latest released version, please have a look at 0.11.0.

librosa.sequence.path_to_steps

librosa.sequence.path_to_steps(path, *, inverse=False)[source]

Convert a DTW warping path to an array of fractional steps.

The step sequence is computed by linear interpolation of the warping path indices.

This function primarily exists as a helper to construct non-linear time grids for aligning two signals via phase vocoding, as illustrated in the example below.

Parameters:
pathnp.ndarray [shape=(k, 2)]

A path of index pairs, e.g., from dtw. path[i] = [n, m] indicates that step n of the first signal aligns to step m of the second signal.

inversebool

If False (default), the output is a time grid mapping the first sequence (first column of path) to the second sequence.

If True, the output is a time grid mapping the second sequence (second column of path) to the first sequence.

Returns:
stepsnp.ndarray [shape=(t,)]

An array of fractional steps, where steps[i] is the index in the first sequence corresponding to the ``i``th step of the second sequence. The number of steps is determined by the range of the target sequence indices.

Examples

This example generates a sine sweep over the same frequency range but at different speeds. It then uses dynamic time warping to align the chroma features of the two signals. Finally, the warping path is converted to a time grid that maps the second signal’s frames onto the first signal. This can be used for variable-rate phase vocoding to align the two signals.

>>> # We'll plot these below
>>> import matplotlib.pyplot as plt
>>> # Generate the sweeps at different rates
>>> y1 = librosa.chirp(fmin=220, fmax=1760, duration=1.0, sr=22050)
>>> y2 = librosa.chirp(fmin=220, fmax=1760, duration=2.0, sr=22050)
>>> # Compute the chroma features
>>> C1 = librosa.feature.chroma_cqt(y=y1, sr=22050)
>>> C2 = librosa.feature.chroma_cqt(y=y2, sr=22050)
>>> # Compute the DTW path
>>> cost, path = librosa.sequence.dtw(C1, C2, subseq=False)
>>> path
array([[43, 86],
       [42, 85],
       [42, 84],
       ...,
       [ 0,  2],
       [ 0,  1],
       [ 0,  0]], shape=(87, 2))
>>> # Convert the path to a fractional step grid
>>> steps = librosa.sequence.path_to_steps(path)
>>> steps
array([ 0.,  0.,  0., ..., 42., 42., 43.], shape=(87,))
>>> # Compute STFT for the first signal
>>> D1 = librosa.stft(y1)
>>> # Phase vocode it to match the second signal using the time grid
>>> D1_vocoded = librosa.phase_vocoder(D1, t_out=steps)
>>> # Map back into the time domain.  Match duration of y2 exactly
>>> y1_vocoded = librosa.istft(D1_vocoded, length=len(y2))
>>> fig, ax = plt.subplots(nrows=3, sharex=True, sharey=True)
>>> librosa.display.specshow(C1, x_axis='time', y_axis='chroma', ax=ax[0])
>>> ax[0].set(title='Chroma 1: fast')
>>> librosa.display.specshow(C2, x_axis='time', y_axis='chroma', ax=ax[1])
>>> ax[1].set(title='Chroma 2: slow')
>>> C3 = librosa.feature.chroma_cqt(y=y1_vocoded, sr=22050)
>>> librosa.display.specshow(C3, x_axis='time', y_axis='chroma', ax=ax[2])
>>> ax[2].set(title='Chroma 1 vocoded to match Chroma 2')
../_images/librosa-sequence-path_to_steps-1.png