Skip to content

Commit a466b3c

Browse files
jimchen90Ji Chen
andauthored
Add Bass with Biquad (#661)
* Add bass with biquad * Update functional.py Add the normalization coefficients * Update test_sox_compatibility.py In test_sox_compatibility.py file, I add two bass tests: one test sets gain = 30, atol = 1e-4, the other sets gain = 40, atol = 1.5e-4. The details can be seen in #676 * Update torchscript_consistency_impl.py Add torchscript test * Add flake8 test Co-authored-by: Ji Chen <[email protected]>
1 parent 53e5074 commit a466b3c

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

docs/source/functional.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ Functions to perform common audio operations.
113113

114114
.. autofunction:: treble_biquad
115115

116+
:hidden:`bass_biquad`
117+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118+
119+
.. autofunction:: bass_biquad
120+
116121
:hidden:`deemph_biquad`
117122
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118123

test/test_sox_compatibility.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,28 @@ def test_treble(self):
265265

266266
self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
267267

268+
@unittest.skipIf("sox" not in BACKENDS, "sox not available")
269+
@AudioBackendScope("sox")
270+
def test_bass(self):
271+
"""
272+
Test biquad bass filter, compare to SoX implementation
273+
"""
274+
275+
central_freq = 1000
276+
q = 0.707
277+
gain = 40
278+
279+
noise_filepath = common_utils.get_asset_path('whitenoise.wav')
280+
E = torchaudio.sox_effects.SoxEffectsChain()
281+
E.set_input_file(noise_filepath)
282+
E.append_effect_to_chain("bass", [gain, central_freq, str(q) + 'q'])
283+
sox_output_waveform, sr = E.sox_build_flow_effects()
284+
285+
waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
286+
output_waveform = F.bass_biquad(waveform, sample_rate, gain, central_freq, q)
287+
288+
self.assertEqual(output_waveform, sox_output_waveform, atol=1.5e-4, rtol=1e-5)
289+
268290
@unittest.skipIf("sox" not in BACKENDS, "sox not available")
269291
@AudioBackendScope("sox")
270292
def test_deemph(self):

test/torchscript_consistency_impl.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,21 @@ def func(tensor):
367367

368368
self._assert_consistency(func, waveform)
369369

370+
def test_bass(self):
371+
if self.dtype == torch.float64:
372+
raise unittest.SkipTest("This test is known to fail for float64")
373+
374+
waveform = common_utils.get_whitenoise(sample_rate=44100)
375+
376+
def func(tensor):
377+
sample_rate = 44100
378+
gain = 40.
379+
central_freq = 1000.
380+
q = 0.707
381+
return F.bass_biquad(tensor, sample_rate, gain, central_freq, q)
382+
383+
self._assert_consistency(func, waveform)
384+
370385
def test_deemph(self):
371386
if self.dtype == torch.float64:
372387
raise unittest.SkipTest("This test is known to fail for float64")

torchaudio/functional.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"equalizer_biquad",
3030
"band_biquad",
3131
"treble_biquad",
32+
"bass_biquad",
3233
"deemph_biquad",
3334
"riaa_biquad",
3435
"biquad",
@@ -988,6 +989,47 @@ def treble_biquad(
988989
return biquad(waveform, b0, b1, b2, a0, a1, a2)
989990

990991

992+
def bass_biquad(
993+
waveform: Tensor,
994+
sample_rate: int,
995+
gain: float,
996+
central_freq: float = 100,
997+
Q: float = 0.707
998+
) -> Tensor:
999+
r"""Design a bass tone-control effect. Similar to SoX implementation.
1000+
1001+
Args:
1002+
waveform (Tensor): audio waveform of dimension of `(..., time)`
1003+
sample_rate (int): sampling rate of the waveform, e.g. 44100 (Hz)
1004+
gain (float): desired gain at the boost (or attenuation) in dB.
1005+
central_freq (float, optional): central frequency (in Hz). (Default: ``100``)
1006+
Q (float, optional): https://en.wikipedia.org/wiki/Q_factor (Default: ``0.707``).
1007+
1008+
Returns:
1009+
Tensor: Waveform of dimension of `(..., time)`
1010+
1011+
References:
1012+
http://sox.sourceforge.net/sox.html
1013+
https://www.w3.org/2011/audio/audio-eq-cookbook.html#APF
1014+
"""
1015+
w0 = 2 * math.pi * central_freq / sample_rate
1016+
alpha = math.sin(w0) / 2 / Q
1017+
A = math.exp(gain / 40 * math.log(10))
1018+
1019+
temp1 = 2 * math.sqrt(A) * alpha
1020+
temp2 = (A - 1) * math.cos(w0)
1021+
temp3 = (A + 1) * math.cos(w0)
1022+
1023+
b0 = A * ((A + 1) - temp2 + temp1)
1024+
b1 = 2 * A * ((A - 1) - temp3)
1025+
b2 = A * ((A + 1) - temp2 - temp1)
1026+
a0 = (A + 1) + temp2 + temp1
1027+
a1 = -2 * ((A - 1) + temp3)
1028+
a2 = (A + 1) + temp2 - temp1
1029+
1030+
return biquad(waveform, b0 / a0, b1 / a0, b2 / a0, a0 / a0, a1 / a0, a2 / a0)
1031+
1032+
9911033
def deemph_biquad(
9921034
waveform: Tensor,
9931035
sample_rate: int

0 commit comments

Comments
 (0)