test_sox_compatibility.py 20.7 KB
Newer Older
1
2
import unittest

3
4
5
import torch
import torchaudio
import torchaudio.functional as F
6
7
import torchaudio.transforms as T

8
from . import common_utils
9
10


moto's avatar
moto committed
11
12
13
14
@common_utils.skipIfNoSoxBackend
class TestFunctionalFiltering(common_utils.TorchaudioTestCase):
    backend = 'sox'

15
    def test_gain(self):
16
        test_filepath = common_utils.get_asset_path('steam-train-whistle-daniel_simon.wav')
17
18
19
20
21
22
23
24
25
26
        waveform, _ = torchaudio.load(test_filepath)

        waveform_gain = F.gain(waveform, 3)
        self.assertTrue(waveform_gain.abs().max().item(), 1.)

        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(test_filepath)
        E.append_effect_to_chain("gain", [3])
        sox_gain_waveform = E.sox_build_flow_effects()[0]

27
        self.assertEqual(waveform_gain, sox_gain_waveform, atol=1e-04, rtol=1e-5)
28
29

    def test_dither(self):
30
        test_filepath = common_utils.get_asset_path('steam-train-whistle-daniel_simon.wav')
31
32
33
34
35
36
37
38
39
40
        waveform, _ = torchaudio.load(test_filepath)

        waveform_dithered = F.dither(waveform)
        waveform_dithered_noiseshaped = F.dither(waveform, noise_shaping=True)

        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(test_filepath)
        E.append_effect_to_chain("dither", [])
        sox_dither_waveform = E.sox_build_flow_effects()[0]

41
        self.assertEqual(waveform_dithered, sox_dither_waveform, atol=1e-04, rtol=1e-5)
42
43
44
45
46
        E.clear_chain()

        E.append_effect_to_chain("dither", ["-s"])
        sox_dither_waveform_ns = E.sox_build_flow_effects()[0]

47
        self.assertEqual(waveform_dithered_noiseshaped, sox_dither_waveform_ns, atol=1e-02, rtol=1e-5)
48
49

    def test_vctk_transform_pipeline(self):
50
        test_filepath_vctk = common_utils.get_asset_path('VCTK-Corpus', 'wav48', 'p224', 'p224_002.wav')
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        wf_vctk, sr_vctk = torchaudio.load(test_filepath_vctk)

        # rate
        sample = T.Resample(sr_vctk, 16000, resampling_method='sinc_interpolation')
        wf_vctk = sample(wf_vctk)
        # dither
        wf_vctk = F.dither(wf_vctk, noise_shaping=True)

        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(test_filepath_vctk)
        E.append_effect_to_chain("gain", ["-h"])
        E.append_effect_to_chain("channels", [1])
        E.append_effect_to_chain("rate", [16000])
        E.append_effect_to_chain("gain", ["-rh"])
        E.append_effect_to_chain("dither", ["-s"])
        wf_vctk_sox = E.sox_build_flow_effects()[0]

68
        self.assertEqual(wf_vctk, wf_vctk_sox, rtol=1e-03, atol=1e-03)
69

70
71
72
73
74
    def test_lowpass(self):
        """
        Test biquad lowpass filter, compare to SoX implementation
        """

75
        cutoff_freq = 3000
76

77
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
78
79
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
80
        E.append_effect_to_chain("lowpass", [cutoff_freq])
81
82
        sox_output_waveform, sr = E.sox_build_flow_effects()

83
        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
84
        output_waveform = F.lowpass_biquad(waveform, sample_rate, cutoff_freq)
85

86
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
87
88
89
90
91
92

    def test_highpass(self):
        """
        Test biquad highpass filter, compare to SoX implementation
        """

93
        cutoff_freq = 2000
94

95
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
96
97
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
98
        E.append_effect_to_chain("highpass", [cutoff_freq])
99
100
        sox_output_waveform, sr = E.sox_build_flow_effects()

101
        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
102
        output_waveform = F.highpass_biquad(waveform, sample_rate, cutoff_freq)
103
104

        # TBD - this fails at the 1e-4 level, debug why
105
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-3, rtol=1e-5)
106

moto's avatar
moto committed
107
108
109
110
111
    def test_allpass(self):
        """
        Test biquad allpass filter, compare to SoX implementation
        """

112
113
        central_freq = 1000
        q = 0.707
moto's avatar
moto committed
114

115
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
moto's avatar
moto committed
116
117
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
118
        E.append_effect_to_chain("allpass", [central_freq, str(q) + 'q'])
moto's avatar
moto committed
119
120
121
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
122
        output_waveform = F.allpass_biquad(waveform, sample_rate, central_freq, q)
moto's avatar
moto committed
123

124
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
125
126
127
128
129
130

    def test_bandpass_with_csg(self):
        """
        Test biquad bandpass filter, compare to SoX implementation
        """

131
132
133
        central_freq = 1000
        q = 0.707
        const_skirt_gain = True
134

135
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
136
137
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
138
        E.append_effect_to_chain("bandpass", ["-c", central_freq, str(q) + 'q'])
139
140
141
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
142
        output_waveform = F.bandpass_biquad(waveform, sample_rate, central_freq, q, const_skirt_gain)
143

144
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
145
146
147
148
149
150

    def test_bandpass_without_csg(self):
        """
        Test biquad bandpass filter, compare to SoX implementation
        """

151
152
153
        central_freq = 1000
        q = 0.707
        const_skirt_gain = False
154

155
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
156
157
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
158
        E.append_effect_to_chain("bandpass", [central_freq, str(q) + 'q'])
159
160
161
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
162
        output_waveform = F.bandpass_biquad(waveform, sample_rate, central_freq, q, const_skirt_gain)
163

164
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
165
166
167
168
169
170

    def test_bandreject(self):
        """
        Test biquad bandreject filter, compare to SoX implementation
        """

171
172
        central_freq = 1000
        q = 0.707
173

174
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
175
176
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
177
        E.append_effect_to_chain("bandreject", [central_freq, str(q) + 'q'])
178
179
180
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
181
        output_waveform = F.bandreject_biquad(waveform, sample_rate, central_freq, q)
182

183
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
moto's avatar
moto committed
184

185
186
187
188
189
    def test_band_with_noise(self):
        """
        Test biquad band filter with noise mode, compare to SoX implementation
        """

190
191
192
        central_freq = 1000
        q = 0.707
        noise = True
193

194
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
195
196
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
197
        E.append_effect_to_chain("band", ["-n", central_freq, str(q) + 'q'])
198
199
200
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
201
        output_waveform = F.band_biquad(waveform, sample_rate, central_freq, q, noise)
202

203
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
204
205
206
207
208
209

    def test_band_without_noise(self):
        """
        Test biquad band filter without noise mode, compare to SoX implementation
        """

210
211
212
        central_freq = 1000
        q = 0.707
        noise = False
213

214
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
215
216
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
217
        E.append_effect_to_chain("band", [central_freq, str(q) + 'q'])
218
219
220
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
221
        output_waveform = F.band_biquad(waveform, sample_rate, central_freq, q, noise)
222

223
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
224
225
226
227
228
229

    def test_treble(self):
        """
        Test biquad treble filter, compare to SoX implementation
        """

230
231
232
        central_freq = 1000
        q = 0.707
        gain = 40
233

234
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
235
236
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
237
        E.append_effect_to_chain("treble", [gain, central_freq, str(q) + 'q'])
238
239
240
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
241
        output_waveform = F.treble_biquad(waveform, sample_rate, gain, central_freq, q)
242

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

jimchen90's avatar
jimchen90 committed
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
    def test_bass(self):
        """
        Test biquad bass filter, compare to SoX implementation
        """

        central_freq = 1000
        q = 0.707
        gain = 40

        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("bass", [gain, central_freq, str(q) + 'q'])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.bass_biquad(waveform, sample_rate, gain, central_freq, q)

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

265
266
267
268
269
    def test_deemph(self):
        """
        Test biquad deemph filter, compare to SoX implementation
        """

270
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
271
272
273
274
275
276
277
278
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("deemph")
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.deemph_biquad(waveform, sample_rate)

279
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
280
281
282
283
284
285

    def test_riaa(self):
        """
        Test biquad riaa filter, compare to SoX implementation
        """

286
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
287
288
289
290
291
292
293
294
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("riaa")
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.riaa_biquad(waveform, sample_rate)

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

297
298
299
300
301
302
303
304
305
306
307
308
309
310
    def test_contrast(self):
        """
        Test contrast effect, compare to SoX implementation
        """
        enhancement_amount = 80.
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("contrast", [enhancement_amount])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.contrast(waveform, enhancement_amount)

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

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
    def test_dcshift_with_limiter(self):
        """
        Test dcshift effect, compare to SoX implementation
        """
        shift = 0.5
        limiter_gain = 0.05
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("dcshift", [shift, limiter_gain])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, _ = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.dcshift(waveform, shift, limiter_gain)

328
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343

    def test_dcshift_without_limiter(self):
        """
        Test dcshift effect, compare to SoX implementation
        """
        shift = 0.6
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("dcshift", [shift])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, _ = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.dcshift(waveform, shift)

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

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
    def test_overdrive(self):
        """
        Test overdrive effect, compare to SoX implementation
        """
        gain = 30
        colour = 40
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("overdrive", [gain, colour])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, _ = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.overdrive(waveform, gain, colour)

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

363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
    def test_phaser_sine(self):
        """
        Test phaser effect with sine moduldation, compare to SoX implementation
        """
        gain_in = 0.5
        gain_out = 0.8
        delay_ms = 2.0
        decay = 0.4
        speed = 0.5
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("phaser", [gain_in, gain_out, delay_ms, decay, speed, "-s"])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.phaser(waveform, sample_rate, gain_in, gain_out, delay_ms, decay, speed, sinusoidal=True)

381
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400

    def test_phaser_triangle(self):
        """
        Test phaser effect with triangle modulation, compare to SoX implementation
        """
        gain_in = 0.5
        gain_out = 0.8
        delay_ms = 2.0
        decay = 0.4
        speed = 0.5
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("phaser", [gain_in, gain_out, delay_ms, decay, speed, "-t"])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.phaser(waveform, sample_rate, gain_in, gain_out, delay_ms, decay, speed, sinusoidal=False)

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

403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
    def test_flanger_triangle_linear(self):
        """
        Test flanger effect with triangle modulation and linear interpolation, compare to SoX implementation
        """
        delay = 0.6
        depth = 0.87
        regen = 3.0
        width = 0.9
        speed = 0.5
        phase = 30
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("flanger", [delay, depth, regen, width, speed, "triangle", phase, "linear"])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.flanger(waveform, sample_rate, delay, depth, regen, width, speed, phase,
                                    modulation='triangular', interpolation='linear')

        torch.testing.assert_allclose(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)

    def test_flanger_triangle_quad(self):
        """
        Test flanger effect with triangle modulation and quadratic interpolation, compare to SoX implementation
        """
        delay = 0.8
        depth = 0.88
        regen = 3.0
        width = 0.4
        speed = 0.5
        phase = 40
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("flanger", [delay, depth, regen, width, speed, "triangle", phase, "quadratic"])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.flanger(waveform, sample_rate, delay, depth, regen, width, speed, phase,
                                    modulation='triangular', interpolation='quadratic')

        torch.testing.assert_allclose(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)

    def test_flanger_sine_linear(self):
        """
        Test flanger effect with sine modulation and linear interpolation, compare to SoX implementation
        """
        delay = 0.8
        depth = 0.88
        regen = 3.0
        width = 0.23
        speed = 1.3
        phase = 60
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("flanger", [delay, depth, regen, width, speed, "sine", phase, "linear"])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.flanger(waveform, sample_rate, delay, depth, regen, width, speed, phase,
                                    modulation='sinusoidal', interpolation='linear')

        torch.testing.assert_allclose(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)

    def test_flanger_sine_quad(self):
        """
        Test flanger effect with sine modulation and quadratic interpolation, compare to SoX implementation
        """
        delay = 0.9
        depth = 0.9
        regen = 4.0
        width = 0.23
        speed = 1.3
        phase = 25
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
        E.append_effect_to_chain("flanger", [delay, depth, regen, width, speed, "sine", phase, "quadratic"])
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
        output_waveform = F.flanger(waveform, sample_rate, delay, depth, regen, width, speed, phase,
                                    modulation='sinusoidal', interpolation='quadratic')

        torch.testing.assert_allclose(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)

xinyang0's avatar
xinyang0 committed
491
492
493
494
495
    def test_equalizer(self):
        """
        Test biquad peaking equalizer filter, compare to SoX implementation
        """

496
497
498
        center_freq = 300
        q = 0.707
        gain = 1
xinyang0's avatar
xinyang0 committed
499

500
        noise_filepath = common_utils.get_asset_path('whitenoise.wav')
xinyang0's avatar
xinyang0 committed
501
502
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(noise_filepath)
503
        E.append_effect_to_chain("equalizer", [center_freq, q, gain])
xinyang0's avatar
xinyang0 committed
504
505
506
        sox_output_waveform, sr = E.sox_build_flow_effects()

        waveform, sample_rate = torchaudio.load(noise_filepath, normalization=True)
507
        output_waveform = F.equalizer_biquad(waveform, sample_rate, center_freq, gain, q)
xinyang0's avatar
xinyang0 committed
508

509
        self.assertEqual(output_waveform, sox_output_waveform, atol=1e-4, rtol=1e-5)
xinyang0's avatar
xinyang0 committed
510

511
512
    def test_perf_biquad_filtering(self):

513
        fn_sine = common_utils.get_asset_path('whitenoise.wav')
514
515
516
517
518
519
520
521
522
523
524
525

        b0 = 0.4
        b1 = 0.2
        b2 = 0.9
        a0 = 0.7
        a1 = 0.2
        a2 = 0.6

        # SoX method
        E = torchaudio.sox_effects.SoxEffectsChain()
        E.set_input_file(fn_sine)
        E.append_effect_to_chain("biquad", [b0, b1, b2, a0, a1, a2])
moto's avatar
moto committed
526
        waveform_sox_out, _ = E.sox_build_flow_effects()
527

moto's avatar
moto committed
528
        waveform, _ = torchaudio.load(fn_sine, normalization=True)
529
530
531
532
        waveform_lfilter_out = F.lfilter(
            waveform, torch.tensor([a0, a1, a2]), torch.tensor([b0, b1, b2])
        )

533
        self.assertEqual(waveform_lfilter_out, waveform_sox_out, atol=1e-4, rtol=1e-5)
534
535
536
537


if __name__ == "__main__":
    unittest.main()