audio_filters.equal_loudness_filter¶
Attributes¶
Classes¶
An equal-loudness filter which compensates for the human ear's non-linear |
Functions¶
|
Least-squares estimate of the numerator polynomial of a transfer function |
|
Stabilize a polynomial by reflecting any roots that lie outside the unit |
|
Design a recursive (IIR) digital filter that approximates an arbitrary |
Module Contents¶
- class audio_filters.equal_loudness_filter.EqualLoudnessFilter(samplerate: int = 44100)¶
An equal-loudness filter which compensates for the human ear’s non-linear response to sound. This filter corrects this by cascading a Yule-Walker 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 the matlab implementation at https://bit.ly/3eqh2HU (url shortened for ruff)
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
https://en.wikipedia.org/wiki/Equal-loudness_contour
>>> filt = EqualLoudnessFilter() >>> isinstance(filt.yulewalk_filter, IIRFilter) True
- process(sample: float) float¶
Process a single sample through both filters
>>> filt = EqualLoudnessFilter() >>> filt.process(0.0) 0.0
- butterworth_filter¶
- yulewalk_filter¶
- audio_filters.equal_loudness_filter._numerator(impulse_response: numpy.ndarray, denominator: numpy.ndarray, numerator_order: int) numpy.ndarray¶
Least-squares estimate of the numerator polynomial of a transfer function given its impulse response and (already known) denominator polynomial.
>>> num = _numerator(np.array([1.0, 0.0, 0.0]), np.array([1.0, 0.0, 0.0]), 1) >>> np.round(num, 6) array([1., 0.])
- audio_filters.equal_loudness_filter._polystab(poly: numpy.ndarray) numpy.ndarray¶
Stabilize a polynomial by reflecting any roots that lie outside the unit circle back inside it. This keeps the resulting IIR filter stable without changing its magnitude response.
https://en.wikipedia.org/wiki/Minimum_phase
>>> np.round(_polystab(np.array([1.0, 2.0, 1.0])), 6) array([1., 2., 1.]) >>> np.round(_polystab(np.array([1.0, 2.0, 1.01])), 6) array([1. , 1.980198, 0.990099])
- audio_filters.equal_loudness_filter.yulewalk(order: int, frequencies: numpy.ndarray, magnitudes: numpy.ndarray, npt: int = 512) tuple[numpy.ndarray, numpy.ndarray]¶
Design a recursive (IIR) digital filter that approximates an arbitrary frequency response using the modified Yule-Walker method. This is a dependency-free re-implementation of MATLAB/Octave’s
yulewalkso that the equal-loudness filter below no longer relies on a third-party package.https://en.wikipedia.org/wiki/Autoregressive_model#Yule%E2%80%93Walker_equations
- Parameters:
order – order of the filter to design
frequencies – sample points on
[0, 1]where 1 is the Nyquist frequency, in increasing order and starting at 0magnitudes – desired (linear) magnitude at each point in
frequenciesnpt – number of points used to estimate the frequency response
- Returns:
(a_coeffs, b_coeffs), the denominator and numerator polynomials
>>> a, b = yulewalk(4, np.array([0.0, 0.5, 1.0]), np.array([1.0, 0.5, 0.0])) >>> len(a), len(b) (5, 5) >>> bool(np.all(np.abs(np.roots(a)) < 1)) # the designed filter is stable True
Mismatched inputs and non-increasing frequencies are rejected:
>>> yulewalk(4, np.array([0.0, 1.0]), np.array([1.0])) Traceback (most recent call last): ... ValueError: frequencies and magnitudes must have the same length >>> yulewalk(4, np.array([0.0, 1.0, 0.5]), np.array([1.0, 0.5, 0.0])) Traceback (most recent call last): ... ValueError: frequencies must be in increasing order
- audio_filters.equal_loudness_filter.data¶