From 368e9435c8d9d32ae921ea64570d6c6d88c17a26 Mon Sep 17 00:00:00 2001 From: Xinyang Wang Date: Fri, 25 Oct 2019 14:11:00 -0400 Subject: [PATCH 1/3] Add peaking equalizer filter in functional.py and test it in test_functional_filter.py. --- test/test_functional_filtering.py | 20 ++++++++++++++++++++ torchaudio/functional.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/test/test_functional_filtering.py b/test/test_functional_filtering.py index b3c23a67b7..a77ff12462 100644 --- a/test/test_functional_filtering.py +++ b/test/test_functional_filtering.py @@ -135,6 +135,26 @@ def test_highpass(self): # TBD - this fails at the 1e-4 level, debug why assert torch.allclose(sox_output_waveform, output_waveform, atol=1e-3) + + def test_equalizer(self): + """ + Test biquad peaking equalizer filter, compare to SoX implementation + """ + + CENTER_FREQ = 1000 + Q = 0.707 + GAIN = 1 + + noise_filepath = os.path.join(self.test_dirpath, "assets", "whitenoise.mp3") + E = torchaudio.sox_effects.SoxEffectsChain() + E.set_input_file(noise_filepath) + E.append_effect_to_chain("equalizer", [CENTER_FREQ, Q, GAIN]) + sox_output_waveform, sr = E.sox_build_flow_effects() + + waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True) + output_waveform = F.equalizer_biquad(waveform, sample_rate, CENTER_FREQ, Q, GAIN) + + assert torch.allclose(sox_output_waveform, output_waveform, atol=1e-4) def test_perf_biquad_filtering(self): diff --git a/torchaudio/functional.py b/torchaudio/functional.py index 6fa4b5341e..8d0587e56f 100644 --- a/torchaudio/functional.py +++ b/torchaudio/functional.py @@ -17,6 +17,7 @@ "lfilter", "lowpass_biquad", "highpass_biquad", + "equalizer_biquad", "biquad", 'mask_along_axis', 'mask_along_axis_iid' @@ -683,6 +684,35 @@ def lowpass_biquad(waveform, sample_rate, cutoff_freq, Q=0.707): return biquad(waveform, b0, b1, b2, a0, a1, a2) +def equalizer_biquad(waveform, sample_rate, center_freq, Q, gain): + # type: (Tensor, int, float, float, float) -> Tensor + r"""Designs biquad peaking equalizer filter and performs filtering. Similar to SoX implementation. + + Args: + waveform (torch.Tensor): audio waveform of dimension of `(channel, time)` + sample_rate (int): sampling rate of the waveform, e.g. 44100 (Hz) + center_freq (float): filter’s central frequency + Q (float): https://en.wikipedia.org/wiki/Q_factor + gain (float): desired gain at the boost (or cut) + + Returns: + output_waveform (torch.Tensor): Dimension of `(channel, time)` + """ + w0 = 2 * math.pi * center_freq / sample_rate + A = math.exp(gain / 40.0 * math.log(10)) + alpha = math.sin(w0) / 2 / Q + mult = _dB2Linear(max(gain, 0)) + + if A == 1: + return waveform + b0 = 1 + alpha * A + b1 = -2 * math.cos(w0) + b2 = 1 - alpha * A + a0 = 1 + alpha / A + a1 = -2 * math.cos(w0) + a2 = 1 - alpha / A + return biquad(waveform, b0, b1, b2, a0, a1, a2) + @torch.jit.script def mask_along_axis_iid(specgrams, mask_param, mask_value, axis): # type: (Tensor, int, float, int) -> Tensor From cc343e0509fe0f0b158f50335a3db060bbf8a6c3 Mon Sep 17 00:00:00 2001 From: Xinyang Wang Date: Fri, 25 Oct 2019 15:21:17 -0400 Subject: [PATCH 2/3] Remove whitespace in black line --- test/test_functional_filtering.py | 2 +- torchaudio/functional.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test_functional_filtering.py b/test/test_functional_filtering.py index a77ff12462..08fbc38735 100644 --- a/test/test_functional_filtering.py +++ b/test/test_functional_filtering.py @@ -135,7 +135,7 @@ def test_highpass(self): # TBD - this fails at the 1e-4 level, debug why assert torch.allclose(sox_output_waveform, output_waveform, atol=1e-3) - + def test_equalizer(self): """ Test biquad peaking equalizer filter, compare to SoX implementation diff --git a/torchaudio/functional.py b/torchaudio/functional.py index 8d0587e56f..27f2b506a1 100644 --- a/torchaudio/functional.py +++ b/torchaudio/functional.py @@ -687,13 +687,13 @@ def lowpass_biquad(waveform, sample_rate, cutoff_freq, Q=0.707): def equalizer_biquad(waveform, sample_rate, center_freq, Q, gain): # type: (Tensor, int, float, float, float) -> Tensor r"""Designs biquad peaking equalizer filter and performs filtering. Similar to SoX implementation. - + Args: waveform (torch.Tensor): audio waveform of dimension of `(channel, time)` sample_rate (int): sampling rate of the waveform, e.g. 44100 (Hz) center_freq (float): filter’s central frequency Q (float): https://en.wikipedia.org/wiki/Q_factor - gain (float): desired gain at the boost (or cut) + gain (float): desired gain at the boost (or cut) Returns: output_waveform (torch.Tensor): Dimension of `(channel, time)` @@ -702,7 +702,7 @@ def equalizer_biquad(waveform, sample_rate, center_freq, Q, gain): A = math.exp(gain / 40.0 * math.log(10)) alpha = math.sin(w0) / 2 / Q mult = _dB2Linear(max(gain, 0)) - + if A == 1: return waveform b0 = 1 + alpha * A @@ -713,6 +713,7 @@ def equalizer_biquad(waveform, sample_rate, center_freq, Q, gain): a2 = 1 - alpha / A return biquad(waveform, b0, b1, b2, a0, a1, a2) + @torch.jit.script def mask_along_axis_iid(specgrams, mask_param, mask_value, axis): # type: (Tensor, int, float, int) -> Tensor From 96c489207590fbdf0d1e6bbcff74747f18b630a9 Mon Sep 17 00:00:00 2001 From: Xinyang Wang Date: Thu, 31 Oct 2019 22:31:40 -0400 Subject: [PATCH 3/3] Revome A=1 special case. Add a default value for Q. Decrease center_freq from 1000 to 300 in test_functional_filtering.py --- test/test_functional_filtering.py | 4 ++-- torchaudio/functional.py | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/test/test_functional_filtering.py b/test/test_functional_filtering.py index 08fbc38735..ab209ed7a7 100644 --- a/test/test_functional_filtering.py +++ b/test/test_functional_filtering.py @@ -141,7 +141,7 @@ def test_equalizer(self): Test biquad peaking equalizer filter, compare to SoX implementation """ - CENTER_FREQ = 1000 + CENTER_FREQ = 300 Q = 0.707 GAIN = 1 @@ -152,7 +152,7 @@ def test_equalizer(self): sox_output_waveform, sr = E.sox_build_flow_effects() waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True) - output_waveform = F.equalizer_biquad(waveform, sample_rate, CENTER_FREQ, Q, GAIN) + output_waveform = F.equalizer_biquad(waveform, sample_rate, CENTER_FREQ, GAIN, Q) assert torch.allclose(sox_output_waveform, output_waveform, atol=1e-4) diff --git a/torchaudio/functional.py b/torchaudio/functional.py index 27f2b506a1..92d1ac2410 100644 --- a/torchaudio/functional.py +++ b/torchaudio/functional.py @@ -684,7 +684,7 @@ def lowpass_biquad(waveform, sample_rate, cutoff_freq, Q=0.707): return biquad(waveform, b0, b1, b2, a0, a1, a2) -def equalizer_biquad(waveform, sample_rate, center_freq, Q, gain): +def equalizer_biquad(waveform, sample_rate, center_freq, gain, Q=0.707): # type: (Tensor, int, float, float, float) -> Tensor r"""Designs biquad peaking equalizer filter and performs filtering. Similar to SoX implementation. @@ -692,8 +692,8 @@ def equalizer_biquad(waveform, sample_rate, center_freq, Q, gain): waveform (torch.Tensor): audio waveform of dimension of `(channel, time)` sample_rate (int): sampling rate of the waveform, e.g. 44100 (Hz) center_freq (float): filter’s central frequency - Q (float): https://en.wikipedia.org/wiki/Q_factor - gain (float): desired gain at the boost (or cut) + gain (float): desired gain at the boost (or attenuation) in dB + q_factor (float): https://en.wikipedia.org/wiki/Q_factor Returns: output_waveform (torch.Tensor): Dimension of `(channel, time)` @@ -701,10 +701,7 @@ def equalizer_biquad(waveform, sample_rate, center_freq, Q, gain): w0 = 2 * math.pi * center_freq / sample_rate A = math.exp(gain / 40.0 * math.log(10)) alpha = math.sin(w0) / 2 / Q - mult = _dB2Linear(max(gain, 0)) - if A == 1: - return waveform b0 = 1 + alpha * A b1 = -2 * math.cos(w0) b2 = 1 - alpha * A