Introduction

resampy is a python module for efficient time-series resampling. It is based on the band-limited sinc interpolation method for sampling rate conversion as described by 1.

1

Smith, Julius O. Digital Audio Resampling Home Page Center for Computer Research in Music and Acoustics (CCRMA), Stanford University, 2015-02-23. Web published at http://ccrma.stanford.edu/~jos/resample/.

resampy supports multi-dimensional resampling on numpy arrays, and is well-suited to audio applications. For long-duration signals — e.g., minutes at a high-quality sampling rate — resampy will be considerably faster than scipy.signal.resample and have little perceivable difference in audio quality.

Its dependencies are numpy, scipy, and numba.

For a quick introduction to using resampy, please refer to the Examples section.

Installation

resampy can be installed through pip:

python -m pip install resampy

Conda users can install via the following command:

conda install -c conda-forge resampy

Advanced users and developers may wish to install from source by cloning the source repository:

git clone https://github.com/bmcfee/resampy.git
cd resampy
python -m pip install -e .

Running tests

Developers that wish to run the included unit test suite can do so by installing from source, and then executing the following commands from the source directory:

python -m pip install -e .[tests]
pytest --cov-report term-missing --cov resampy

Examples

Monophonic resampling

The following code block demonstrates how to resample an audio signal.

We use librosa for loading the audio, but this is purely for ease of demonstration. resampy does not depend on librosa.

 1import librosa
 2import resampy
 3
 4# Load in librosa's example audio file at its native sampling rate
 5x, sr_orig = librosa.load(librosa.ex('trumpet'), sr=None)
 6
 7# x is now a 1-d numpy array, with `sr_orig` audio samples per second
 8
 9# We can resample this to any sampling rate we like, say 16000 Hz
10y_low = resampy.resample(x, sr_orig, 16000)
11
12# That's it!

Stereo and multi-dimensional data

The previous example operates on monophonic signals, but resampy also supports stereo resampling, as demonstrated below.

 1import librosa
 2import resampy
 3
 4# Load in librosa's example audio file at its native sampling rate.
 5# This time, also disable the stereo->mono downmixing
 6x, sr_orig = librosa.load(librosa.ex('trumpet', hq=True), sr=None, mono=False)
 7
 8# x is now a 2-d numpy array, with `sr_orig` audio samples per second
 9# The first dimension of x indexes the channels, the second dimension indexes
10# samples.
11# x[0] is the left channel, x[1] is the right channel.
12
13# We can again resample.  By default, resample assumes the last index is time.
14y_low = resampy.resample(x, sr_orig, 16000)
15
16# To be more explicit, provide a target axis
17y_low = resampy.resample(x, sr_orig, 16000, axis=1)

The next block illustrates resampling along an arbitrary dimension.

 1import numpy as np
 2import resampy
 3
 4# Generate 4-dimensional white noise.  The third axis (axis=2) will index time.
 5sr_orig = 22050
 6x = np.random.randn(10, 3, sr_orig * 5, 2)
 7
 8# x is now a 10-by-3-by-(5*22050)-by-2 tensor of data.
 9
10# We can resample along the time axis as follows
11y_low = resampy.resample(x, sr_orig, 11025, axis=2)
12
13# y_low is now a 10-by-3-(5*11025)-by-2 tensor of data

Integer-valued samples

Integer-valued inputs are supported, but because resampy interpolates between sample values, it will always produce a floating-point output. If you really need integer-valued outputs after resampling, you’ll have to cast the output array as demonstrated below.

 1 import numpy as np
 2 import resampy
 3
 4 sr_orig = 22050
 5
 6 # Create 5 seconds of random integer noise
 7 x = np.random.randint(-32768, high=32767, size=5*sr_orig, dtype=np.int16)
 8
 9 # resample, y will be floating-point type
10 y = resampy.resample(x, sr_orig, 11025)
11
12 # Cast back to match x's dtype
13 y_int = y.astype(x.dtype)

Advanced filtering

resampy allows you to control the design of the filters used in resampling operations.

 1import numpy as np
 2import scipy.signal
 3import librosa
 4import resampy
 5
 6# Load in some audio
 7x, sr_orig = librosa.load(librosa.ex('trumpet'), sr=None, mono=False)
 8
 9# Resample to 22050Hz using a Hann-windowed sinc-filter
10y = resampy.resample(x, sr_orig, sr_new, filter='sinc_window', window=scipy.signal.hann)
11
12# Or a shorter sinc-filter than the default (num_zeros=64)
13y = resampy.resample(x, sr_orig, sr_new, filter='sinc_window', num_zeros=32)
14
15# Or use the pre-built high-quality filter
16y = resampy.resample(x, sr_orig, sr_new, filter='kaiser_best')
17
18# Or use the pre-built fast filter
19y = resampy.resample(x, sr_orig, sr_new, filter='kaiser_fast')

API Reference

Core functionality

Core resampling interface

resampy.core.resample(x, sr_orig, sr_new, axis=-1, filter='kaiser_best', parallel=False, **kwargs)[source]

Resample a signal x from sr_orig to sr_new along a given axis.

Parameters
xnp.ndarray, dtype=np.float*

The input signal(s) to resample.

sr_origint > 0

The sampling rate of x

sr_newint > 0

The target sampling rate of the output signal(s)

If sr_new == sr_orig, then a copy of x is returned with no interpolation performed.

axisint

The target axis along which to resample x

filteroptional, str or callable

The resampling filter to use.

By default, uses the kaiser_best (pre-computed filter).

paralleloptional, bool

Enable/disable parallel computation exploiting multi-threading.

Default: True.

**kwargs

additional keyword arguments provided to the specified filter

Returns
ynp.ndarray

x resampled to sr_new

Raises
ValueError

if sr_orig or sr_new is not positive

TypeError

if the input signal x has an unsupported data type.

Examples

>>> import resampy
>>> np.set_printoptions(precision=3, suppress=True)
>>> # Generate a sine wave at 440 Hz for 5 seconds
>>> sr_orig = 44100.0
>>> x = np.sin(2 * np.pi * 440.0 / sr_orig * np.arange(5 * sr_orig))
>>> x
array([ 0.   ,  0.063, ..., -0.125, -0.063])
>>> # Resample to 22050 with default parameters
>>> resampy.resample(x, sr_orig, 22050)
array([ 0.011,  0.122,  0.25 , ..., -0.366, -0.25 , -0.122])
>>> # Resample using the fast (low-quality) filter
>>> resampy.resample(x, sr_orig, 22050, filter='kaiser_fast')
array([ 0.012,  0.121,  0.251, ..., -0.365, -0.251, -0.121])
>>> # Resample using a high-quality filter
>>> resampy.resample(x, sr_orig, 22050, filter='kaiser_best')
array([ 0.011,  0.122,  0.25 , ..., -0.366, -0.25 , -0.122])
>>> # Resample using a Hann-windowed sinc filter
>>> import scipy.signal
>>> resampy.resample(x, sr_orig, 22050, filter='sinc_window',
...                  window=scipy.signal.hann)
array([ 0.011,  0.123,  0.25 , ..., -0.366, -0.25 , -0.123])
>>> # Generate stereo data
>>> x_right = np.sin(2 * np.pi * 880.0 / sr_orig * np.arange(len(x)))
>>> x_stereo = np.stack([x, x_right])
>>> x_stereo.shape
(2, 220500)
>>> # Resample along the time axis (1)
>>> y_stereo = resampy.resample(x_stereo, sr_orig, 22050, axis=1)
>>> y_stereo.shape
(2, 110250)
resampy.core.resample_nu(x, sr_orig, t_out, axis=-1, filter='kaiser_best', parallel=False, **kwargs)[source]

Interpolate a signal x at specified positions (t_out) along a given axis.

Parameters
xnp.ndarray, dtype=np.float*

The input signal(s) to resample.

sr_origfloat

Sampling rate of the input signal (x).

t_outnp.ndarray, dtype=np.float*

Position of the output samples.

axisint

The target axis along which to resample x

filteroptional, str or callable

The resampling filter to use.

By default, uses the kaiser_best (pre-computed filter).

paralleloptional, bool

Enable/disable parallel computation exploiting multi-threading.

Default: True.

**kwargs

additional keyword arguments provided to the specified filter

Returns
ynp.ndarray

x resampled to t_out

Raises
TypeError

if the input signal x has an unsupported data type.

Notes

Differently form the resample function the filter rolloff is not automatically adapted in case of subsampling. For this reason results obtained with the resample_nu could be slightly different form the ones obtained with resample if the filter parameters are not carefully set by the user.

Examples

>>> import resampy
>>> np.set_printoptions(precision=3, suppress=True)
>>> # Generate a sine wave at 100 Hz for 5 seconds
>>> sr_orig = 100.0
>>> f0 = 1
>>> t = np.arange(5 * sr_orig) / sr_orig
>>> x = np.sin(2 * np.pi * f0 * t)
>>> x
array([ 0.   ,  0.063,  0.125, ..., -0.187, -0.125, -0.063])
>>> # Resample to non-uniform sampling
>>> t_new = np.log2(1 + t)[::5] - t[0]
>>> resampy.resample_nu(x, sr_orig, t_new)
array([ 0.001,  0.427,  0.76 , ..., -0.3  , -0.372, -0.442])

Filters

Filter construction and loading.

resampy provides two pre-computed resampling filters which are tuned for either high-quality or fast calculation. These filters are constructed by the create_filters.py script.

  • kaiser_best :

    > Parameters for kaiser_best: > —————————————- > beta = 12.9846 > roll = 0.917347 > # zeros = 50 > precision = 13 > attenuation = -120.0 > —————————————-

  • kaiser_fast :

    > Parameters for kaiser_fast: > —————————————- > beta = 9.90322 > roll = 0.868212 > # zeros = 24 > precision = 9 > attenuation = -93.0 > —————————————-

These filters can be used by calling resample as follows:

>>> # High-quality
>>> resampy.resample(x, sr_orig, sr_new, filter='kaiser_best')  
>>> # Fast calculation
>>> resampy.resample(x, sr_orig, sr_new, filter='kaiser_fast')  

It is also possible to construct custom filters as follows:

>>> resampy.resample(x, sr_orig, sr_new, filter='sinc_window',
...                  **kwargs)                                  

where **kwargs are additional parameters to sinc_window.

resampy.filters.clear_cache()[source]

Clear the filter cache.

Calling this function will ensure that packaged filters are reloaded upon the next usage.

resampy.filters.get_filter(name_or_function, **kwargs)[source]

Retrieve a window given its name or function handle.

Parameters
name_or_functionstr or callable

If a function, returns name_or_function(**kwargs).

If a string, and it matches the name of one of the defined filter functions, the corresponding function is called with **kwargs.

If a string, and it matches the name of a pre-computed filter, the corresponding filter is retrieved, and kwargs is ignored.

Valid pre-computed filter names are:
  • ‘kaiser_fast’

  • ‘kaiser_best’

**kwargs

Additional keyword arguments passed to name_or_function (if callable)

Returns
half_windownp.ndarray

The right wing of the interpolation filter

precisionint > 0

The number of samples between zero-crossings of the filter

rollofffloat > 0

The roll-off frequency of the filter as a fraction of Nyquist

Raises
NotImplementedError

If name_or_function cannot be found as a filter.

resampy.filters.sinc_window(num_zeros=64, precision=9, window=None, rolloff=0.945)[source]

Construct a windowed sinc interpolation filter

Parameters
num_zerosint > 0

The number of zero-crossings to retain in the sinc filter

precisionint > 0

The number of filter coefficients to retain for each zero-crossing

windowcallable

The window function. By default, uses a Hann window.

rollofffloat > 0

The roll-off frequency (as a fraction of nyquist)

Returns
interp_window: np.ndarray [shape=(num_zeros * num_table + 1)]

The interpolation window (right-hand side)

num_bits: int

The number of bits of precision to use in the filter table

rollofffloat > 0

The roll-off frequency of the filter, as a fraction of Nyquist

Raises
TypeError

if window is not callable or None

ValueError

if num_zeros < 1, precision < 1, or rolloff is outside the range (0, 1].

Examples

>>> import scipy, scipy.signal
>>> import resampy
>>> np.set_printoptions(threshold=5, suppress=False)
>>> # A filter with 10 zero-crossings, 32 samples per crossing, and a
>>> # Hann window for tapering.
>>> halfwin, prec, rolloff = resampy.filters.sinc_window(num_zeros=10, precision=5,
...                                                      window=scipy.signal.hann)
>>> halfwin
array([  9.450e-01,   9.436e-01, ...,  -7.455e-07,  -0.000e+00])
>>> prec
32
>>> rolloff
0.945
>>> # Or using sinc-window filter construction directly in resample
>>> y = resampy.resample(x, sr_orig, sr_new, filter='sinc_window',
...                      num_zeros=10, precision=5,
...                      window=scipy.signal.hann)              

Changes

Changes

v0.4.2

2022-09-13

  • #115 Fixed buffer length calculation to avoid numerical overflow issues on some platforms.

v0.4.1

2022-09-09

  • #113 Fixed a rounding error in output buffer length calculations.

  • #110 Added a special case to disable unsupported parallel mode on 32bit architectures.

v0.4.0

2022-08-05

  • #109 Reduced import time and switched to parallel=False by default.

  • #109 Integer-valued inputs now produce floating point outputs.

v0.3.1

2022-07-07

  • #104 Fixed an efficiency regression introduced in the 0.3.0 release.

v0.3.0

2022-06-29

  • #99 Enable caching of pre-computed filters to improve runtime efficiency.

  • #98 Automate pre-computed filter generation. Regenerated and improved kaiser_fast and kaiser_best filters.

  • #95 Improved documentation

  • #93 Enable parallel processing for sample rate conversion. Antonio Valentino

  • #91 Improved python packaging workflow.

  • #90 Fixed a bug in resampling high-dimensional data.

  • #89 Removed support for python 2.7.

  • #88 Bypass sample rate conversion if input and output rates are identical.

  • #87 Added continuous integration tests for linting.

  • #82 Non-uniform output sample positions. Antonio Valentio

v0.2.2

2019-08-15

  • #68 Preserve array ordering (C- or F-contiguity) from input to output.

v0.2.1

2018-06-04

  • #63 Fixed an error in filter response boundary calculations.

v0.2.0

2017-09-16

  • #57 Rewrote the core resampler using Numba. This should alleviate Cython-based installation issues going forward.

  • #14 Added support for resampling complex-valued signals.

  • #17 Added a safety check for resampling short signals.

v0.1.5

2017-02-16

  • #44 Added type-checking to ensure floating-point inputs

v0.1.4

2016-07-13

  • #27 Fixed cython packaging

v0.1.3

2016-06-21

  • #23 updated the Cython version requirement.

v0.1.2

2016-05-26

  • #20 Expose the rolloff parameter of (pre-computed) filters

v0.1.1

2016-05-23

  • Fixed a cython installation and distribution issue

v0.1.0

2016-04-21

  • Initial release.

Contribute

Indices and tables