Skip to content

Commit a04a636

Browse files
Martmists-GHpre-commit-ci[bot]cclauss
authored
Add Equal Loudness Filter (TheAlgorithms#7019)
* Add Equal Loudness Filter Signed-off-by: Martmists <[email protected]> * NoneType return on __init__ Signed-off-by: Martmists <[email protected]> * Add data to JSON as requested by @CenTdemeern1 in a not very polite manner Signed-off-by: Martmists <[email protected]> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * 'modernize' Signed-off-by: Martmists <[email protected]> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update audio_filters/equal_loudness_filter.py Co-authored-by: Christian Clauss <[email protected]> * Update equal_loudness_filter.py * Update equal_loudness_filter.py * Finally!! * Arrgghh Signed-off-by: Martmists <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <[email protected]>
1 parent f0d1a42 commit a04a636

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from json import loads
2+
from pathlib import Path
3+
4+
import numpy as np
5+
from yulewalker import yulewalk
6+
7+
from audio_filters.butterworth_filter import make_highpass
8+
from audio_filters.iir_filter import IIRFilter
9+
10+
data = loads((Path(__file__).resolve().parent / "loudness_curve.json").read_text())
11+
12+
13+
class EqualLoudnessFilter:
14+
r"""
15+
An equal-loudness filter which compensates for the human ear's non-linear response
16+
to sound.
17+
This filter corrects this by cascading a yulewalk filter and a butterworth filter.
18+
19+
Designed for use with samplerate of 44.1kHz and above. If you're using a lower
20+
samplerate, use with caution.
21+
22+
Code based on matlab implementation at https://bit.ly/3eqh2HU
23+
(url shortened for flake8)
24+
25+
Target curve: https://i.imgur.com/3g2VfaM.png
26+
Yulewalk response: https://i.imgur.com/J9LnJ4C.png
27+
Butterworth and overall response: https://i.imgur.com/3g2VfaM.png
28+
29+
Images and original matlab implementation by David Robinson, 2001
30+
"""
31+
32+
def __init__(self, samplerate: int = 44100) -> None:
33+
self.yulewalk_filter = IIRFilter(10)
34+
self.butterworth_filter = make_highpass(150, samplerate)
35+
36+
# pad the data to nyquist
37+
curve_freqs = np.array(data["frequencies"] + [max(20000.0, samplerate / 2)])
38+
curve_gains = np.array(data["gains"] + [140])
39+
40+
# Convert to angular frequency
41+
freqs_normalized = curve_freqs / samplerate * 2
42+
# Invert the curve and normalize to 0dB
43+
gains_normalized = np.power(10, (np.min(curve_gains) - curve_gains) / 20)
44+
45+
# Scipy's `yulewalk` function is a stub, so we're using the
46+
# `yulewalker` library instead.
47+
# This function computes the coefficients using a least-squares
48+
# fit to the specified curve.
49+
ya, yb = yulewalk(10, freqs_normalized, gains_normalized)
50+
self.yulewalk_filter.set_coefficients(ya, yb)
51+
52+
def process(self, sample: float) -> float:
53+
"""
54+
Process a single sample through both filters
55+
56+
>>> filt = EqualLoudnessFilter()
57+
>>> filt.process(0.0)
58+
0.0
59+
"""
60+
tmp = self.yulewalk_filter.process(sample)
61+
return self.butterworth_filter.process(tmp)

audio_filters/loudness_curve.json

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"_comment": "The following is a representative average of the Equal Loudness Contours as measured by Robinson and Dadson, 1956",
3+
"_doi": "10.1088/0508-3443/7/5/302",
4+
"frequencies": [
5+
0,
6+
20,
7+
30,
8+
40,
9+
50,
10+
60,
11+
70,
12+
80,
13+
90,
14+
100,
15+
200,
16+
300,
17+
400,
18+
500,
19+
600,
20+
700,
21+
800,
22+
900,
23+
1000,
24+
1500,
25+
2000,
26+
2500,
27+
3000,
28+
3700,
29+
4000,
30+
5000,
31+
6000,
32+
7000,
33+
8000,
34+
9000,
35+
10000,
36+
12000,
37+
15000,
38+
20000
39+
],
40+
"gains": [
41+
120,
42+
113,
43+
103,
44+
97,
45+
93,
46+
91,
47+
89,
48+
87,
49+
86,
50+
85,
51+
78,
52+
76,
53+
76,
54+
76,
55+
76,
56+
77,
57+
78,
58+
79.5,
59+
80,
60+
79,
61+
77,
62+
74,
63+
71.5,
64+
70,
65+
70.5,
66+
74,
67+
79,
68+
84,
69+
86,
70+
86,
71+
85,
72+
95,
73+
110,
74+
125
75+
]
76+
}

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ tensorflow
1717
texttable
1818
tweepy
1919
xgboost
20+
yulewalker

0 commit comments

Comments
 (0)