pedalboard
pedalboard copied to clipboard
WindowedSinc resampling introduces distortion
Resample: WindowedSinc
resampling introduces distortion when setting a target sampling rate ≤ 8 kHz
Expected behaviour
Since WindowedSinc
is a relatively high-quality resampling scheme, I would expect a band-limited signal without distortion.
Actual behaviour
For resampling targets of 8 kHz or 4 kHz, I observe noticeable distortion in the signal, compared to the resampling library resampy
which also allows using sinc_window
resampling, which doesn't have this issue.
Since the other resampling algorithms in pedalboard are prone to introduce aliasing and other artifacts, I ask myself is this a bug or a feature? :D
Steps to reproduce the behaviour
The distortion is especially prominent in speech audio when there are sibilants. Therefore, I recommend using an speech example from librosa for testing:
import pedalboard as pb
import numpy as np
from pedalboard import Resample
import librosa
import soundfile as sf
import resampy
original_sample_rate = 24000
target_sample_rate = 8000
# needs librosa >= 0.9.2
audio, sr = librosa.load(librosa.example('libri3'), sr=original_sample_rate)
# resample with pedalboard
audio_resampled_pb = Resample(
target_sample_rate,
quality=pb.Resample.Quality.WindowedSinc,
)(audio, original_sample_rate)
sf.write(
"./libri3_pb.wav",
audio_resampled_pb,
samplerate=original_sample_rate)
# resample with resampy
audio_resampled_res = resampy.resample(
audio,
original_sample_rate,
target_sample_rate,
filter="sinc_window",
)
audio_resampled_res = resampy.resample(
audio_resampled_res,
target_sample_rate,
original_sample_rate,
filter="sinc_window",
)
sf.write(
"./libri3_resampy.wav",
audio_resampled_res,
samplerate=original_sample_rate
)
Hi @iCorv! Thanks for the bug report. Pedalboard's resamplers are just thin wrappers around JUCE's Interpolators
package; the WindowedSinc
algorithm just uses the WindowedSincInterpolator
, which uses a 10,000-point static lookup table.
Resampy's sinc_window
filter seems to construct a different window filter, which might be of higher quality. I'll look into a way to compare the two, as it would be possible to write a custom interpolator to avoid distortion.
Hi @psobot, yes, there seem to be more differences. Resampy also provides pre-computed window filters as kaiser_best
and kaiser_fast
, maybe that could be a starting point. resampy
+ kaiser_best
also being the default resampling librosa
uses, from experience I can say it is very slow compared to kaiser_fast
.
It surprises me that JUCE hasn't got any better resampling plugin, perhaps it is easier to use another library for high-quality resampling? Here is a list of open-source solutions. In general, the resampy
algorithm is described here in more detail.
Revisiting this issue, I solved this in my application by using a low pass filter set to target_sampling_rate / 2
before and after resampling. I guess this is common practice when resampling signals, but often this is taken care of by the library already. In case of pedalboard I think it would be helpful to either mention this in the docs or make the LP part of the resampling.
And I am still not sure with the windowed-sinc-interpolation, isn't the point of this resampling technique that it already is a type of bandlimited interpolation which makes LP filter redundant?