mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-27 15:01:08 +00:00
Add Equal Loudness Filter (#7019)
* Add Equal Loudness Filter Signed-off-by: Martmists <martmists@gmail.com> * NoneType return on __init__ Signed-off-by: Martmists <martmists@gmail.com> * Add data to JSON as requested by @CenTdemeern1 in a not very polite manner Signed-off-by: Martmists <martmists@gmail.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * 'modernize' Signed-off-by: Martmists <martmists@gmail.com> * [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 <cclauss@me.com> * Update equal_loudness_filter.py * Update equal_loudness_filter.py * Finally!! * Arrgghh Signed-off-by: Martmists <martmists@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
parent
f0d1a42deb
commit
a04a6365de
61
audio_filters/equal_loudness_filter.py
Normal file
61
audio_filters/equal_loudness_filter.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
from json import loads
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from yulewalker import yulewalk
|
||||||
|
|
||||||
|
from audio_filters.butterworth_filter import make_highpass
|
||||||
|
from audio_filters.iir_filter import IIRFilter
|
||||||
|
|
||||||
|
data = loads((Path(__file__).resolve().parent / "loudness_curve.json").read_text())
|
||||||
|
|
||||||
|
|
||||||
|
class EqualLoudnessFilter:
|
||||||
|
r"""
|
||||||
|
An equal-loudness filter which compensates for the human ear's non-linear response
|
||||||
|
to sound.
|
||||||
|
This filter corrects this by cascading a yulewalk filter and a butterworth filter.
|
||||||
|
|
||||||
|
Designed for use with samplerate of 44.1kHz and above. If you're using a lower
|
||||||
|
samplerate, use with caution.
|
||||||
|
|
||||||
|
Code based on matlab implementation at https://bit.ly/3eqh2HU
|
||||||
|
(url shortened for flake8)
|
||||||
|
|
||||||
|
Target curve: https://i.imgur.com/3g2VfaM.png
|
||||||
|
Yulewalk response: https://i.imgur.com/J9LnJ4C.png
|
||||||
|
Butterworth and overall response: https://i.imgur.com/3g2VfaM.png
|
||||||
|
|
||||||
|
Images and original matlab implementation by David Robinson, 2001
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, samplerate: int = 44100) -> None:
|
||||||
|
self.yulewalk_filter = IIRFilter(10)
|
||||||
|
self.butterworth_filter = make_highpass(150, samplerate)
|
||||||
|
|
||||||
|
# pad the data to nyquist
|
||||||
|
curve_freqs = np.array(data["frequencies"] + [max(20000.0, samplerate / 2)])
|
||||||
|
curve_gains = np.array(data["gains"] + [140])
|
||||||
|
|
||||||
|
# Convert to angular frequency
|
||||||
|
freqs_normalized = curve_freqs / samplerate * 2
|
||||||
|
# Invert the curve and normalize to 0dB
|
||||||
|
gains_normalized = np.power(10, (np.min(curve_gains) - curve_gains) / 20)
|
||||||
|
|
||||||
|
# Scipy's `yulewalk` function is a stub, so we're using the
|
||||||
|
# `yulewalker` library instead.
|
||||||
|
# This function computes the coefficients using a least-squares
|
||||||
|
# fit to the specified curve.
|
||||||
|
ya, yb = yulewalk(10, freqs_normalized, gains_normalized)
|
||||||
|
self.yulewalk_filter.set_coefficients(ya, yb)
|
||||||
|
|
||||||
|
def process(self, sample: float) -> float:
|
||||||
|
"""
|
||||||
|
Process a single sample through both filters
|
||||||
|
|
||||||
|
>>> filt = EqualLoudnessFilter()
|
||||||
|
>>> filt.process(0.0)
|
||||||
|
0.0
|
||||||
|
"""
|
||||||
|
tmp = self.yulewalk_filter.process(sample)
|
||||||
|
return self.butterworth_filter.process(tmp)
|
76
audio_filters/loudness_curve.json
Normal file
76
audio_filters/loudness_curve.json
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
{
|
||||||
|
"_comment": "The following is a representative average of the Equal Loudness Contours as measured by Robinson and Dadson, 1956",
|
||||||
|
"_doi": "10.1088/0508-3443/7/5/302",
|
||||||
|
"frequencies": [
|
||||||
|
0,
|
||||||
|
20,
|
||||||
|
30,
|
||||||
|
40,
|
||||||
|
50,
|
||||||
|
60,
|
||||||
|
70,
|
||||||
|
80,
|
||||||
|
90,
|
||||||
|
100,
|
||||||
|
200,
|
||||||
|
300,
|
||||||
|
400,
|
||||||
|
500,
|
||||||
|
600,
|
||||||
|
700,
|
||||||
|
800,
|
||||||
|
900,
|
||||||
|
1000,
|
||||||
|
1500,
|
||||||
|
2000,
|
||||||
|
2500,
|
||||||
|
3000,
|
||||||
|
3700,
|
||||||
|
4000,
|
||||||
|
5000,
|
||||||
|
6000,
|
||||||
|
7000,
|
||||||
|
8000,
|
||||||
|
9000,
|
||||||
|
10000,
|
||||||
|
12000,
|
||||||
|
15000,
|
||||||
|
20000
|
||||||
|
],
|
||||||
|
"gains": [
|
||||||
|
120,
|
||||||
|
113,
|
||||||
|
103,
|
||||||
|
97,
|
||||||
|
93,
|
||||||
|
91,
|
||||||
|
89,
|
||||||
|
87,
|
||||||
|
86,
|
||||||
|
85,
|
||||||
|
78,
|
||||||
|
76,
|
||||||
|
76,
|
||||||
|
76,
|
||||||
|
76,
|
||||||
|
77,
|
||||||
|
78,
|
||||||
|
79.5,
|
||||||
|
80,
|
||||||
|
79,
|
||||||
|
77,
|
||||||
|
74,
|
||||||
|
71.5,
|
||||||
|
70,
|
||||||
|
70.5,
|
||||||
|
74,
|
||||||
|
79,
|
||||||
|
84,
|
||||||
|
86,
|
||||||
|
86,
|
||||||
|
85,
|
||||||
|
95,
|
||||||
|
110,
|
||||||
|
125
|
||||||
|
]
|
||||||
|
}
|
|
@ -17,3 +17,4 @@ tensorflow
|
||||||
texttable
|
texttable
|
||||||
tweepy
|
tweepy
|
||||||
xgboost
|
xgboost
|
||||||
|
yulewalker
|
||||||
|
|
Loading…
Reference in New Issue
Block a user