Commit 9d8569bf authored by Raymond Toy's avatar Raymond Toy Committed by Commit Bot

Test getFreguencyResponse for all BiquadFilter types

Previously we only tested the result of getFreqencyResponse for
peaking filters.  Add test for all the other filters as well.

Bug: 390266
Change-Id: I7cba2a0dbcfaf3e6c0fec0a92eaedf8779f2d361
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1584368
Commit-Queue: Raymond Toy <rtoy@chromium.org>
Reviewed-by: default avatarHongchan Choi <hongchan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#654482}
parent 0ca1a7f5
...@@ -36,12 +36,6 @@ ...@@ -36,12 +36,6 @@
let filterQ = 1; let filterQ = 1;
let filterGain = 5; // Decibels. let filterGain = 5; // Decibels.
// The maximum allowed error in the magnitude response.
let maxAllowedMagError = 1.09931e-6;
// The maximum allowed error in the phase response.
let maxAllowedPhaseError = 6.4724e-8;
// The magnitudes and phases of the reference frequency response. // The magnitudes and phases of the reference frequency response.
let expectedMagnitudes; let expectedMagnitudes;
let expectedPhases; let expectedPhases;
...@@ -148,6 +142,10 @@ ...@@ -148,6 +142,10 @@
} }
} }
function decibelsToLinear(x) {
return Math.pow(10, x/20);
}
// Look through the array and find any NaN or infinity. Returns the index // Look through the array and find any NaN or infinity. Returns the index
// of the first occurence or -1 if none. // of the first occurence or -1 if none.
function findBadNumber(signal) { function findBadNumber(signal) {
...@@ -171,8 +169,17 @@ ...@@ -171,8 +169,17 @@
} }
// Compare the frequency response with our expected response. // Compare the frequency response with our expected response.
//
// should - The |should| method provided by audit.define
// filter - The filter node used in the test
// frequencies - array of frequencies provided to |getFrequencyResponse|
// magResponse - mag response from |getFrequencyResponse|
// phaseResponse - phase response from |getFrequencyResponse|
// maxAllowedMagError - error threshold for mag response, in dB
// maxAllowedPhaseError - error threshold for phase response, in rad.
function compareResponses( function compareResponses(
should, filter, frequencies, magResponse, phaseResponse) { should, filter, frequencies, magResponse, phaseResponse,
maxAllowedMagError, maxAllowedPhaseError) {
let expectedResponse = frequencyResponseReference(filter, frequencies); let expectedResponse = frequencyResponseReference(filter, frequencies);
expectedMagnitudes = expectedResponse.magnitudes; expectedMagnitudes = expectedResponse.magnitudes;
...@@ -188,16 +195,19 @@ ...@@ -188,16 +195,19 @@
let hasBadNumber; let hasBadNumber;
hasBadNumber = findBadNumber(magResponse); hasBadNumber = findBadNumber(magResponse);
badResponse = !should( badResponse =
hasBadNumber >= 0 ? 1 : 0, !should(
'Number of non-finite values in magnitude response') hasBadNumber >= 0 ? 1 : 0,
.beEqualTo(0); filter.type +
': Number of non-finite values in magnitude response')
.beEqualTo(0);
hasBadNumber = findBadNumber(phaseResponse); hasBadNumber = findBadNumber(phaseResponse);
badResponse = !should( badResponse =
hasBadNumber >= 0 ? 1 : 0, !should(
'Number of non-finte values in phase response') hasBadNumber >= 0 ? 1 : 0,
.beEqualTo(0); filter.type + ': Number of non-finte values in phase response')
.beEqualTo(0);
// These aren't testing the implementation itself. Instead, these are // These aren't testing the implementation itself. Instead, these are
// sanity checks on the reference. Failure here does not imply an error // sanity checks on the reference. Failure here does not imply an error
...@@ -206,14 +216,16 @@ ...@@ -206,14 +216,16 @@
badResponse = badResponse =
!should( !should(
hasBadNumber >= 0 ? 1 : 0, hasBadNumber >= 0 ? 1 : 0,
'Number of non-finite values in the expected magnitude response') filter.type +
': Number of non-finite values in the expected magnitude response')
.beEqualTo(0); .beEqualTo(0);
hasBadNumber = findBadNumber(expectedPhases); hasBadNumber = findBadNumber(expectedPhases);
badResponse = badResponse =
!should( !should(
hasBadNumber >= 0 ? 1 : 0, hasBadNumber >= 0 ? 1 : 0,
'Number of non-finite values in expected phase response') filter.type +
': Number of non-finite values in expected phase response')
.beEqualTo(0); .beEqualTo(0);
// If we found a NaN or infinity, the following tests aren't very // If we found a NaN or infinity, the following tests aren't very
...@@ -221,7 +233,8 @@ ...@@ -221,7 +233,8 @@
// warning message. // warning message.
should( should(
!badResponse, !badResponse,
'Actual and expected results contained only finite values') filter.type +
': Actual and expected results contained only finite values')
.beTrue(); .beTrue();
for (k = 0; k < n; ++k) { for (k = 0; k < n; ++k) {
...@@ -236,7 +249,7 @@ ...@@ -236,7 +249,7 @@
should( should(
linearToDecibels(maxMagError), linearToDecibels(maxMagError),
'Max error (' + linearToDecibels(maxMagError) + filter.type + ': Max error (' + linearToDecibels(maxMagError) +
' dB) of magnitude response at frequency ' + ' dB) of magnitude response at frequency ' +
frequencies[maxMagErrorIndex] + ' Hz') frequencies[maxMagErrorIndex] + ' Hz')
.beLessThanOrEqualTo(linearToDecibels(maxAllowedMagError)); .beLessThanOrEqualTo(linearToDecibels(maxAllowedMagError));
...@@ -254,7 +267,7 @@ ...@@ -254,7 +267,7 @@
should( should(
radToDegree(maxPhaseError), radToDegree(maxPhaseError),
'Max error (' + radToDegree(maxPhaseError) + filter.type + ': Max error (' + radToDegree(maxPhaseError) +
' deg) in phase response at frequency ' + ' deg) in phase response at frequency ' +
frequencies[maxPhaseErrorIndex] + ' Hz') frequencies[maxPhaseErrorIndex] + ' Hz')
.beLessThanOrEqualTo(radToDegree(maxAllowedPhaseError)); .beLessThanOrEqualTo(radToDegree(maxAllowedPhaseError));
...@@ -265,32 +278,78 @@ ...@@ -265,32 +278,78 @@
return rad * 180 / Math.PI; return rad * 180 / Math.PI;
} }
audit.define( // Test the getFrequencyResponse for each of filter types. Each entry in
{label: 'test', description: 'Biquad frequency response'}, // this array is a dictionary with these elements:
function(task, should) { //
context = new AudioContext(); // type: filter type to be tested
// maxErrorInMagnitude: Allowed error in computed magnitude response
filter = context.createBiquadFilter(); // maxErrorInPhase: Allowed error in computed magnitude phase
[{
// Arbitrarily test a peaking filter, but any kind of filter can be type: 'lowpass',
// tested. maxErrorInMagnitude: decibelsToLinear(-73.0178),
filter.type = 'peaking'; maxErrorInPhase: 8.04360e-6
filter.frequency.value = filterCutoff; },
filter.Q.value = filterQ; {
filter.gain.value = filterGain; type: 'highpass',
maxErrorInMagnitude: decibelsToLinear(-117.5461),
let frequencies = maxErrorInPhase: 6.9691e-6
createFrequencies(numberOfFrequencies, context.sampleRate); },
magResponse = new Float32Array(numberOfFrequencies); {
phaseResponse = new Float32Array(numberOfFrequencies); type: 'bandpass',
maxErrorInMagnitude: decibelsToLinear(-79.0139),
filter.getFrequencyResponse( maxErrorInPhase: 4.9371e-6
frequencies, magResponse, phaseResponse); },
compareResponses( {
should, filter, frequencies, magResponse, phaseResponse); type: 'lowshelf',
maxErrorInMagnitude: decibelsToLinear(-120.4038),
task.done(); maxErrorInPhase: 4.0724e-6
}); },
{
type: 'highshelf',
maxErrorInMagnitude: decibelsToLinear(-120, 1303),
maxErrorInPhase: 4.0724e-6
},
{
type: 'peaking',
maxErrorInMagnitude: decibelsToLinear(-119.1176),
maxErrorInPhase: 6.4724e-8
},
{
type: 'notch',
maxErrorInMagnitude: decibelsToLinear(-87.0808),
maxErrorInPhase: 6.6300e-6
},
{
type: 'allpass',
maxErrorInMagnitude: decibelsToLinear(-265.3517),
maxErrorInPhase: 1.3260e-5
}].forEach(test => {
audit.define(
{label: test.type, description: 'Frequency response'},
(task, should) => {
let context = new AudioContext();
let filter = new BiquadFilterNode(context, {
type: test.type,
frequency: filterCutoff,
Q: filterQ,
gain: filterGain
});
let frequencies =
createFrequencies(numberOfFrequencies, context.sampleRate);
magResponse = new Float32Array(numberOfFrequencies);
phaseResponse = new Float32Array(numberOfFrequencies);
filter.getFrequencyResponse(
frequencies, magResponse, phaseResponse);
compareResponses(
should, filter, frequencies, magResponse, phaseResponse,
test.maxErrorInMagnitude, test.maxErrorInPhase);
task.done();
});
});
audit.define( audit.define(
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment