How to apply a lowpass filter, with cutoff frequency varying linearly (or with a more general curve than linear) from e.g. 10000hz to 200hz along time, with numpy/scipy and possibly no other library?
Example:
- at 00:00,000, lowpass cutoff = 10000hz
- at 00:05,000, lowpass cutoff = 5000hz
- at 00:09,000, lowpass cutoff = 1000hz
- then cutoff stays at 1000hz during 10 seconds, then cutoff decreases down to 200hz
Here is how to do a simple 100hz lowpass:
from scipy.io import wavfile
import numpy as np
from scipy.signal import butter, lfilter
sr, x = wavfile.read('test.wav')
b, a = butter(2, 100.0 / sr, btype='low') # Butterworth
y = lfilter(b, a, x)
wavfile.write('out.wav', sr, np.asarray(y, dtype=np.int16))
but how to make the cutoff vary?
Note: I've already read Applying time-variant filter in Python but the answer is quite complex (and it applies to many kinds of filter in general).
you can use scipy.fftpack.fftfreq and scipy.fftpack.rfft to set thresholds
for the time_step I did twice the sampling rate of the sound
this would set all set all frequencies less than 200 hz to zero
for the time varying cut off, I'd split the sound and apply the filters then. assuming the sound has a sampling rate of 44100, the 5000hz filter would start at sample 220500 (five seconds in)
then for the next filter:
etc
edit: to make it "sliding" or a gradual filter instead of piece wise, you could make the "pieces" much smaller and apply increasingly bigger frequency thresholds to the corresponding piece(5000 -> 5001 -> 5002)
One comparatively easy method is to keep the filter fixed and modulate signal time instead. For example, if signal time runs 10x faster a 10KHz lowpass will act like a 1KHz lowpass in standard time.
To do this we need to solve a simple ODE
Here
t
is modulated timey
real time andf
the desired cutoff at timey
.Prototype implementation:
Sample output:
Spectrogram of first 25 seconds of BWV 826 Capriccio filtered with a time varying lowpass implemented via time bending.