-
Notifications
You must be signed in to change notification settings - Fork 196
Detection of lowpass BiquadFilter implementation
In WebAudio Issue 771 it was discovered that the current BiquadFilterNode
could not represent some valid lowpass and highpass filters. This issue was resolved by changing the formulas for the lowpass and highpass filters. Of course, this changes the output of the filters.
If you need to detect which filter formula is being used, here is a bit of code to tell you. This works by creating two lowpass filters with different negative Q values. In the original formulation, negative Q values are silently clamped to 0. So, if you have the original formulas, the output of the two filters are exactly the same. This code tests for that. The new formulas don't have this restriction on Q, so the output of the two filters are different. (It would be a bug if they were the same.)
var result;
var isNewBiquadFilter = false;
function testForNewBiquadFilter() {
var context = new OfflineAudioContext(1, 1000, 48000);
var src = context.createOscillator();
// The type and frequency don't really matter.
src.type = "sawtooth";
src.frequency.value = 8 * 440;
var gain = context.createGain();
gain.gain.value = -1;
var f1 = context.createBiquadFilter();
var f2 = context.createBiquadFilter();
// Each filter should get a different negative Q value.
f1.Q.value = -1;
f2.Q.value = -20;
src.connect(f1);
src.connect(f2);
f1.connect(context.destination);
f2.connect(gain);
gain.connect(context.destination);
src.start();
context.startRendering().then(function (buffer) {
result = buffer;
isNewBiquadFilter = Math.max(...buffer.getChannelData(0)) != 0;
});
}
If you've determined that you're using the new formulas but want to preserve exactly the filter response, use the following function to convert the old Q value to an equivalent Q value for the new filter formula:
// Convert the old Q parameter to the Qnew parameter for the new filter formulation.
function convertQToQnew(QdB) {
var Qlin = Math.pow(10, QdB / 20);
var Qnew = 1 / Math.sqrt((4 - Math.sqrt(16 - 16 / (Qlin * Qlin))) / 2);
Qnew = 20 * Math.log10(Qnew)
return Qnew;
}