Spaces:
Build error
Build error
import torch | |
import numpy as np | |
import scipy.signal | |
from numba import jit | |
from deepafx_st.processors.processor import Processor | |
def biqaud( | |
gain_dB: float, | |
cutoff_freq: float, | |
q_factor: float, | |
sample_rate: float, | |
filter_type: str, | |
): | |
"""Use design parameters to generate coeffieicnets for a specific filter type. | |
Args: | |
gain_dB (float): Shelving filter gain in dB. | |
cutoff_freq (float): Cutoff frequency in Hz. | |
q_factor (float): Q factor. | |
sample_rate (float): Sample rate in Hz. | |
filter_type (str): Filter type. | |
One of "low_shelf", "high_shelf", or "peaking" | |
Returns: | |
b (np.ndarray): Numerator filter coefficients stored as [b0, b1, b2] | |
a (np.ndarray): Denominator filter coefficients stored as [a0, a1, a2] | |
""" | |
A = 10 ** (gain_dB / 40.0) | |
w0 = 2.0 * np.pi * (cutoff_freq / sample_rate) | |
alpha = np.sin(w0) / (2.0 * q_factor) | |
cos_w0 = np.cos(w0) | |
sqrt_A = np.sqrt(A) | |
if filter_type == "high_shelf": | |
b0 = A * ((A + 1) + (A - 1) * cos_w0 + 2 * sqrt_A * alpha) | |
b1 = -2 * A * ((A - 1) + (A + 1) * cos_w0) | |
b2 = A * ((A + 1) + (A - 1) * cos_w0 - 2 * sqrt_A * alpha) | |
a0 = (A + 1) - (A - 1) * cos_w0 + 2 * sqrt_A * alpha | |
a1 = 2 * ((A - 1) - (A + 1) * cos_w0) | |
a2 = (A + 1) - (A - 1) * cos_w0 - 2 * sqrt_A * alpha | |
elif filter_type == "low_shelf": | |
b0 = A * ((A + 1) - (A - 1) * cos_w0 + 2 * sqrt_A * alpha) | |
b1 = 2 * A * ((A - 1) - (A + 1) * cos_w0) | |
b2 = A * ((A + 1) - (A - 1) * cos_w0 - 2 * sqrt_A * alpha) | |
a0 = (A + 1) + (A - 1) * cos_w0 + 2 * sqrt_A * alpha | |
a1 = -2 * ((A - 1) + (A + 1) * cos_w0) | |
a2 = (A + 1) + (A - 1) * cos_w0 - 2 * sqrt_A * alpha | |
elif filter_type == "peaking": | |
b0 = 1 + alpha * A | |
b1 = -2 * cos_w0 | |
b2 = 1 - alpha * A | |
a0 = 1 + alpha / A | |
a1 = -2 * cos_w0 | |
a2 = 1 - alpha / A | |
else: | |
pass | |
# raise ValueError(f"Invalid filter_type: {filter_type}.") | |
b = np.array([b0, b1, b2]) / a0 | |
a = np.array([a0, a1, a2]) / a0 | |
return b, a | |
# Adapted from https://github.com/csteinmetz1/pyloudnorm/blob/master/pyloudnorm/iirfilter.py | |
def parametric_eq( | |
x: np.ndarray, | |
sample_rate: float, | |
low_shelf_gain_dB: float = 0.0, | |
low_shelf_cutoff_freq: float = 80.0, | |
low_shelf_q_factor: float = 0.707, | |
first_band_gain_dB: float = 0.0, | |
first_band_cutoff_freq: float = 300.0, | |
first_band_q_factor: float = 0.707, | |
second_band_gain_dB: float = 0.0, | |
second_band_cutoff_freq: float = 1000.0, | |
second_band_q_factor: float = 0.707, | |
third_band_gain_dB: float = 0.0, | |
third_band_cutoff_freq: float = 4000.0, | |
third_band_q_factor: float = 0.707, | |
fourth_band_gain_dB: float = 0.0, | |
fourth_band_cutoff_freq: float = 8000.0, | |
fourth_band_q_factor: float = 0.707, | |
high_shelf_gain_dB: float = 0.0, | |
high_shelf_cutoff_freq: float = 1000.0, | |
high_shelf_q_factor: float = 0.707, | |
dtype=np.float32, | |
): | |
"""Six-band parametric EQ. | |
Low-shelf -> Band 1 -> Band 2 -> Band 3 -> Band 4 -> High-shelf | |
Args: | |
""" | |
# print(f"autodiff peq fs = {sample_rate}") | |
# -------- apply low-shelf filter -------- | |
b, a = biqaud( | |
low_shelf_gain_dB, | |
low_shelf_cutoff_freq, | |
low_shelf_q_factor, | |
sample_rate, | |
"low_shelf", | |
) | |
sos0 = np.concatenate((b, a)) | |
x = scipy.signal.lfilter(b, a, x) | |
# -------- apply first-band peaking filter -------- | |
b, a = biqaud( | |
first_band_gain_dB, | |
first_band_cutoff_freq, | |
first_band_q_factor, | |
sample_rate, | |
"peaking", | |
) | |
sos1 = np.concatenate((b, a)) | |
x = scipy.signal.lfilter(b, a, x) | |
# -------- apply second-band peaking filter -------- | |
b, a = biqaud( | |
second_band_gain_dB, | |
second_band_cutoff_freq, | |
second_band_q_factor, | |
sample_rate, | |
"peaking", | |
) | |
sos2 = np.concatenate((b, a)) | |
x = scipy.signal.lfilter(b, a, x) | |
# -------- apply third-band peaking filter -------- | |
b, a = biqaud( | |
third_band_gain_dB, | |
third_band_cutoff_freq, | |
third_band_q_factor, | |
sample_rate, | |
"peaking", | |
) | |
sos3 = np.concatenate((b, a)) | |
x = scipy.signal.lfilter(b, a, x) | |
# -------- apply fourth-band peaking filter -------- | |
b, a = biqaud( | |
fourth_band_gain_dB, | |
fourth_band_cutoff_freq, | |
fourth_band_q_factor, | |
sample_rate, | |
"peaking", | |
) | |
sos4 = np.concatenate((b, a)) | |
x = scipy.signal.lfilter(b, a, x) | |
# -------- apply high-shelf filter -------- | |
b, a = biqaud( | |
high_shelf_gain_dB, | |
high_shelf_cutoff_freq, | |
high_shelf_q_factor, | |
sample_rate, | |
"high_shelf", | |
) | |
sos5 = np.concatenate((b, a)) | |
x = scipy.signal.lfilter(b, a, x) | |
return x.astype(dtype) | |
class ParametricEQ(Processor): | |
def __init__( | |
self, | |
sample_rate, | |
min_gain_dB=-24.0, | |
default_gain_dB=0.0, | |
max_gain_dB=24.0, | |
min_q_factor=0.1, | |
default_q_factor=0.707, | |
max_q_factor=10, | |
eps=1e-8, | |
): | |
""" """ | |
super().__init__() | |
self.sample_rate = sample_rate | |
self.eps = eps | |
self.ports = [ | |
{ | |
"name": "Lowshelf gain", | |
"min": min_gain_dB, | |
"max": max_gain_dB, | |
"default": default_gain_dB, | |
"units": "dB", | |
}, | |
{ | |
"name": "Lowshelf cutoff", | |
"min": 20.0, | |
"max": 200.0, | |
"default": 100.0, | |
"units": "Hz", | |
}, | |
{ | |
"name": "Lowshelf Q", | |
"min": min_q_factor, | |
"max": max_q_factor, | |
"default": default_q_factor, | |
"units": "", | |
}, | |
{ | |
"name": "First band gain", | |
"min": min_gain_dB, | |
"max": max_gain_dB, | |
"default": default_gain_dB, | |
"units": "dB", | |
}, | |
{ | |
"name": "First band cutoff", | |
"min": 200.0, | |
"max": 2000.0, | |
"default": 400.0, | |
"units": "Hz", | |
}, | |
{ | |
"name": "First band Q", | |
"min": min_q_factor, | |
"max": max_q_factor, | |
"default": 0.707, | |
"units": "", | |
}, | |
{ | |
"name": "Second band gain", | |
"min": min_gain_dB, | |
"max": max_gain_dB, | |
"default": default_gain_dB, | |
"units": "dB", | |
}, | |
{ | |
"name": "Second band cutoff", | |
"min": 800.0, | |
"max": 4000.0, | |
"default": 1000.0, | |
"units": "Hz", | |
}, | |
{ | |
"name": "Second band Q", | |
"min": min_q_factor, | |
"max": max_q_factor, | |
"default": default_q_factor, | |
"units": "", | |
}, | |
{ | |
"name": "Third band gain", | |
"min": min_gain_dB, | |
"max": max_gain_dB, | |
"default": default_gain_dB, | |
"units": "dB", | |
}, | |
{ | |
"name": "Third band cutoff", | |
"min": 2000.0, | |
"max": 8000.0, | |
"default": 4000.0, | |
"units": "Hz", | |
}, | |
{ | |
"name": "Third band Q", | |
"min": min_q_factor, | |
"max": max_q_factor, | |
"default": default_q_factor, | |
"units": "", | |
}, | |
{ | |
"name": "Fourth band gain", | |
"min": min_gain_dB, | |
"max": max_gain_dB, | |
"default": default_gain_dB, | |
"units": "dB", | |
}, | |
{ | |
"name": "Fourth band cutoff", | |
"min": 4000.0, | |
"max": (24000 // 2) * 0.9, | |
"default": 8000.0, | |
"units": "Hz", | |
}, | |
{ | |
"name": "Fourth band Q", | |
"min": min_q_factor, | |
"max": max_q_factor, | |
"default": default_q_factor, | |
"units": "", | |
}, | |
{ | |
"name": "Highshelf gain", | |
"min": min_gain_dB, | |
"max": max_gain_dB, | |
"default": default_gain_dB, | |
"units": "dB", | |
}, | |
{ | |
"name": "Highshelf cutoff", | |
"min": 4000.0, | |
"max": (24000 // 2) * 0.9, | |
"default": 8000.0, | |
"units": "Hz", | |
}, | |
{ | |
"name": "Highshelf Q", | |
"min": min_q_factor, | |
"max": max_q_factor, | |
"default": default_q_factor, | |
"units": "", | |
}, | |
] | |
self.num_control_params = len(self.ports) | |
self.process_fn = parametric_eq | |
def forward(self, x, p, sample_rate=24000, **kwargs): | |
"All processing in the forward is in numpy." | |
return self.run_series(x, p, sample_rate) | |