restore q value to shelves

This commit is contained in:
Boof2015
2026-08-11 19:11:02 -04:00
parent 915242bae6
commit 441299254b
7 changed files with 104 additions and 72 deletions
@@ -7,7 +7,7 @@ import kotlin.math.sin
import kotlin.math.sqrt
/**
* Web Audio BiquadFilterNode coefficients, a0-normalized as b0,b1,b2,a1,a2.
* Audio EQ Cookbook coefficients, a0-normalized as b0,b1,b2,a1,a2.
* Type ordinals match EQ_BAND_TYPE_ORDINAL in src/audio/eq.ts:
* 0 lowshelf, 1 peaking, 2 highshelf, 3 highpass, 4 lowpass.
*/
@@ -34,7 +34,6 @@ internal object EqCoefficients {
val a = 10.0.pow(gainDb / 40.0)
val alphaQ = sinW0 / (2.0 * q.coerceAtLeast(MIN_FILTER_Q.toFloat()))
val alphaQDb = sinW0 / (2.0 * 10.0.pow(q / 20.0))
val alphaShelf = (sinW0 / 2.0) * sqrt(2.0)
var b0 = 1.0; var b1 = 0.0; var b2 = 0.0
var a0 = 1.0; var a1 = 0.0; var a2 = 0.0
@@ -46,21 +45,21 @@ internal object EqCoefficients {
}
0 -> { // lowshelf
val sqrtA = sqrt(a)
b0 = a * (a + 1 - (a - 1) * cosW0 + 2 * sqrtA * alphaShelf)
b0 = a * (a + 1 - (a - 1) * cosW0 + 2 * sqrtA * alphaQ)
b1 = 2 * a * (a - 1 - (a + 1) * cosW0)
b2 = a * (a + 1 - (a - 1) * cosW0 - 2 * sqrtA * alphaShelf)
a0 = a + 1 + (a - 1) * cosW0 + 2 * sqrtA * alphaShelf
b2 = a * (a + 1 - (a - 1) * cosW0 - 2 * sqrtA * alphaQ)
a0 = a + 1 + (a - 1) * cosW0 + 2 * sqrtA * alphaQ
a1 = -2 * (a - 1 + (a + 1) * cosW0)
a2 = a + 1 + (a - 1) * cosW0 - 2 * sqrtA * alphaShelf
a2 = a + 1 + (a - 1) * cosW0 - 2 * sqrtA * alphaQ
}
2 -> { // highshelf
val sqrtA = sqrt(a)
b0 = a * (a + 1 + (a - 1) * cosW0 + 2 * sqrtA * alphaShelf)
b0 = a * (a + 1 + (a - 1) * cosW0 + 2 * sqrtA * alphaQ)
b1 = -2 * a * (a - 1 + (a + 1) * cosW0)
b2 = a * (a + 1 + (a - 1) * cosW0 - 2 * sqrtA * alphaShelf)
a0 = a + 1 - (a - 1) * cosW0 + 2 * sqrtA * alphaShelf
b2 = a * (a + 1 + (a - 1) * cosW0 - 2 * sqrtA * alphaQ)
a0 = a + 1 - (a - 1) * cosW0 + 2 * sqrtA * alphaQ
a1 = 2 * (a - 1 - (a + 1) * cosW0)
a2 = a + 1 - (a - 1) * cosW0 - 2 * sqrtA * alphaShelf
a2 = a + 1 - (a - 1) * cosW0 - 2 * sqrtA * alphaQ
}
4 -> { // lowpass
b0 = (1 - cosW0) / 2; b1 = 1 - cosW0; b2 = (1 - cosW0) / 2
@@ -1,6 +1,7 @@
package com.doublesymmetry.kotlinaudio.scope
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
class EqCoefficientsTest {
@@ -29,15 +30,34 @@ class EqCoefficientsTest {
}
@Test
fun shelfFiltersIgnoreQ() {
fun shelfFiltersUseQ() {
val lowWide = coeffs(type = 0, freq = 100f, gainDb = 6f, q = 0.5f)
val lowNarrow = coeffs(type = 0, freq = 100f, gainDb = 6f, q = 2f)
val highWide = coeffs(type = 2, freq = 8000f, gainDb = -4f, q = 0.5f)
val highNarrow = coeffs(type = 2, freq = 8000f, gainDb = -4f, q = 2f)
assertCoefficients(
coeffs(type = 0, freq = 100f, gainDb = 6f, q = 0.1f),
coeffs(type = 0, freq = 100f, gainDb = 6f, q = 18f)
lowWide,
doubleArrayOf(
1.004523905875,
-1.978032948597,
0.973748440145,
-1.978092655842,
0.978212638774
)
)
assertCoefficients(
coeffs(type = 2, freq = 8000f, gainDb = -4f, q = 0.1f),
coeffs(type = 2, freq = 8000f, gainDb = -4f, q = 18f)
highWide,
doubleArrayOf(
0.746848511923,
-0.319264680328,
0.034120017138,
-0.641024137473,
0.102727986206
)
)
assertCoefficientsDiffer(lowWide, lowNarrow)
assertCoefficientsDiffer(highWide, highNarrow)
}
private fun coeffs(type: Int, freq: Float, gainDb: Float, q: Float): FloatArray {
@@ -59,4 +79,12 @@ class EqCoefficientsTest {
assertEquals("coefficient $i", expected[i].toDouble(), actual[i].toDouble(), 0.0)
}
}
private fun assertCoefficientsDiffer(first: FloatArray, second: FloatArray) {
assertEquals("coefficient count", first.size, second.size)
assertTrue(
"expected at least one coefficient to change",
first.indices.any { i -> kotlin.math.abs(first[i] - second[i]) > 1e-6f }
)
}
}