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 from source through pip:

pip install resampy

Conda users can install pre-compiled packages:

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 setup.py build_ext -i
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:

pip install -e .[tests]
pip install pytest pytest-cov pytest-faulthandler
py.test --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

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')

Benchmarking

Benchmarking resampy is relatively simple, using ipython’s %timeit magic. The following example demonstrates resampling a monophonic signal of 400000 samples from 22.05 KHz to 16 KHz using both resampy and scipy.signal.resample.

In [1]: import numpy as np

In [2]: import scipy

In [3]: import resampy

In [4]: x = np.random.randn(400000)

In [5]: sr_in, sr_out = 22050, 16000

In [6]: %timeit resampy.resample(x, sr_in, sr_out, axis=-1)
1 loop, best of 3: 199 ms per loop

In [7]: %timeit scipy.signal.resample(x,
   ...:                               int(x.shape[-1] * sr_out / float(sr_in)),
   ...:                               axis=-1)
1 loop, best of 3: 6min 5s per loop

API Reference

Core functionality

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.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