Index: third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html |
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html |
index e36561da5dead53d52e641b4c26b82ae95aded51..14b0580ff4a6e00706b2ccb7a64f7bbee81ad591 100644 |
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html |
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-getFrequencyResponse.html |
@@ -1,272 +1,298 @@ |
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
+<!DOCTYPE html> |
<html> |
-<head> |
-<script src="../../resources/testharness.js"></script> |
-<script src="../../resources/testharnessreport.js"></script> |
-<script src="../resources/audit-util.js"></script> |
-<script src="../resources/audit.js"></script> |
-<script src="../resources/biquad-filters.js"></script> |
-<script src="../resources/biquad-testing.js"></script> |
-</head> |
- |
-<body> |
-<script> |
-let audit = Audit.createTaskRunner(); |
- |
-// Test the frequency response of a biquad filter. We compute the frequency response for a simple |
-// peaking biquad filter and compare it with the expected frequency response. The actual filter |
-// used doesn't matter since we're testing getFrequencyResponse and not the actual filter output. |
-// The filters are extensively tested in other biquad tests. |
- |
-// The magnitude response of the biquad filter. |
-let magResponse; |
- |
-// The phase response of the biquad filter. |
-let phaseResponse; |
- |
-// Number of frequency samples to take. |
-let numberOfFrequencies = 1000; |
- |
-// The filter parameters. |
-let filterCutoff = 1000; // Hz. |
-let filterQ = 1; |
-let filterGain = 5; // Decibels. |
- |
-// The maximum allowed error in the magnitude response. |
-let maxAllowedMagError = 5.7e-7; |
- |
-// The maximum allowed error in the phase response. |
-let maxAllowedPhaseError = 4.7e-8; |
- |
-// The magnitudes and phases of the reference frequency response. |
-let expectedMagnitudes; |
-let expectedPhases; |
- |
-// Convert frequency in Hz to a normalized frequency between 0 to 1 with 1 corresponding to the |
-// Nyquist frequency. |
-function normalizedFrequency(freqHz, sampleRate) |
-{ |
- let nyquist = sampleRate / 2; |
- return freqHz / nyquist; |
-} |
- |
-// Get the filter response at a (normalized) frequency |f| for the filter with coefficients |coef|. |
-function getResponseAt(coef, f) |
-{ |
- let b0 = coef.b0; |
- let b1 = coef.b1; |
- let b2 = coef.b2; |
- let a1 = coef.a1; |
- let a2 = coef.a2; |
- |
- // H(z) = (b0 + b1 / z + b2 / z^2) / (1 + a1 / z + a2 / z^2) |
- // |
- // Compute H(exp(i * pi * f)). No native complex numbers in javascript, so break H(exp(i * pi * // f)) |
- // in to the real and imaginary parts of the numerator and denominator. Let omega = pi * f. |
- // Then the numerator is |
- // |
- // b0 + b1 * cos(omega) + b2 * cos(2 * omega) - i * (b1 * sin(omega) + b2 * sin(2 * omega)) |
- // |
- // and the denominator is |
- // |
- // 1 + a1 * cos(omega) + a2 * cos(2 * omega) - i * (a1 * sin(omega) + a2 * sin(2 * omega)) |
- // |
- // Compute the magnitude and phase from the real and imaginary parts. |
- |
- let omega = Math.PI * f; |
- let numeratorReal = b0 + b1 * Math.cos(omega) + b2 * Math.cos(2 * omega); |
- let numeratorImag = -(b1 * Math.sin(omega) + b2 * Math.sin(2 * omega)); |
- let denominatorReal = 1 + a1 * Math.cos(omega) + a2 * Math.cos(2 * omega); |
- let denominatorImag = -(a1 * Math.sin(omega) + a2 * Math.sin(2 * omega)); |
- |
- let magnitude = Math.sqrt((numeratorReal * numeratorReal + numeratorImag * numeratorImag) |
- / (denominatorReal * denominatorReal + denominatorImag * denominatorImag)); |
- let phase = Math.atan2(numeratorImag, numeratorReal) - Math.atan2(denominatorImag, denominatorReal); |
- |
- if (phase >= Math.PI) { |
- phase -= 2 * Math.PI; |
- } else if (phase <= -Math.PI) { |
- phase += 2 * Math.PI; |
- } |
- |
- return {magnitude : magnitude, phase : phase}; |
-} |
- |
-// Compute the reference frequency response for the biquad filter |filter| at the frequency samples |
-// given by |frequencies|. |
-function frequencyResponseReference(filter, frequencies) |
-{ |
- let sampleRate = filter.context.sampleRate; |
- let normalizedFreq = normalizedFrequency(filter.frequency.value, sampleRate); |
- let filterCoefficients = createFilter(filter.type, normalizedFreq, filter.Q.value, filter.gain.value); |
- |
- let magnitudes = []; |
- let phases = []; |
- |
- for (let k = 0; k < frequencies.length; ++k) { |
- let response = getResponseAt(filterCoefficients, normalizedFrequency(frequencies[k], sampleRate)); |
- magnitudes.push(response.magnitude); |
- phases.push(response.phase); |
- } |
- |
- return {magnitudes : magnitudes, phases : phases}; |
-} |
- |
-// Compute a set of linearly spaced frequencies. |
-function createFrequencies(nFrequencies, sampleRate) |
-{ |
- let frequencies = new Float32Array(nFrequencies); |
- let nyquist = sampleRate / 2; |
- let freqDelta = nyquist / nFrequencies; |
- |
- for (let k = 0; k < nFrequencies; ++k) { |
- frequencies[k] = k * freqDelta; |
- } |
- |
- return frequencies; |
-} |
- |
-function linearToDecibels(x) |
-{ |
- if (x) { |
- return 20 * Math.log(x) / Math.LN10; |
- } else { |
- return -1000; |
- } |
-} |
- |
-// Look through the array and find any NaN or infinity. Returns the index of the first occurence or |
-// -1 if none. |
-function findBadNumber(signal) |
-{ |
- for (let k = 0; k < signal.length; ++k) { |
- if (!isValidNumber(signal[k])) { |
- return k; |
+ <head> |
+ <title> |
+ biquad-getFrequencyResponse.html |
+ </title> |
+ <script src="../../resources/testharness.js"></script> |
+ <script src="../../resources/testharnessreport.js"></script> |
+ <script src="../resources/audit-util.js"></script> |
+ <script src="../resources/audit.js"></script> |
+ <script src="../resources/biquad-filters.js"></script> |
+ <script src="../resources/biquad-testing.js"></script> |
+ </head> |
+ <body> |
+ <script id="layout-test-code"> |
+ let audit = Audit.createTaskRunner(); |
+ |
+ // Test the frequency response of a biquad filter. We compute the |
+ // frequency response for a simple peaking biquad filter and compare it |
+ // with the expected frequency response. The actual filter used doesn't |
+ // matter since we're testing getFrequencyResponse and not the actual |
+ // filter output. The filters are extensively tested in other biquad |
+ // tests. |
+ |
+ // The magnitude response of the biquad filter. |
+ let magResponse; |
+ |
+ // The phase response of the biquad filter. |
+ let phaseResponse; |
+ |
+ // Number of frequency samples to take. |
+ let numberOfFrequencies = 1000; |
+ |
+ // The filter parameters. |
+ let filterCutoff = 1000; // Hz. |
+ let filterQ = 1; |
+ let filterGain = 5; // Decibels. |
+ |
+ // The maximum allowed error in the magnitude response. |
+ let maxAllowedMagError = 5.7e-7; |
+ |
+ // The maximum allowed error in the phase response. |
+ let maxAllowedPhaseError = 4.7e-8; |
+ |
+ // The magnitudes and phases of the reference frequency response. |
+ let expectedMagnitudes; |
+ let expectedPhases; |
+ |
+ // Convert frequency in Hz to a normalized frequency between 0 to 1 with 1 |
+ // corresponding to the Nyquist frequency. |
+ function normalizedFrequency(freqHz, sampleRate) { |
+ let nyquist = sampleRate / 2; |
+ return freqHz / nyquist; |
+ } |
+ |
+ // Get the filter response at a (normalized) frequency |f| for the filter |
+ // with coefficients |coef|. |
+ function getResponseAt(coef, f) { |
+ let b0 = coef.b0; |
+ let b1 = coef.b1; |
+ let b2 = coef.b2; |
+ let a1 = coef.a1; |
+ let a2 = coef.a2; |
+ |
+ // H(z) = (b0 + b1 / z + b2 / z^2) / (1 + a1 / z + a2 / z^2) |
+ // |
+ // Compute H(exp(i * pi * f)). No native complex numbers in javascript, |
+ // so break H(exp(i * pi * // f)) in to the real and imaginary parts of |
+ // the numerator and denominator. Let omega = pi * f. Then the |
+ // numerator is |
+ // |
+ // b0 + b1 * cos(omega) + b2 * cos(2 * omega) - i * (b1 * sin(omega) + |
+ // b2 * sin(2 * omega)) |
+ // |
+ // and the denominator is |
+ // |
+ // 1 + a1 * cos(omega) + a2 * cos(2 * omega) - i * (a1 * sin(omega) + a2 |
+ // * sin(2 * omega)) |
+ // |
+ // Compute the magnitude and phase from the real and imaginary parts. |
+ |
+ let omega = Math.PI * f; |
+ let numeratorReal = |
+ b0 + b1 * Math.cos(omega) + b2 * Math.cos(2 * omega); |
+ let numeratorImag = -(b1 * Math.sin(omega) + b2 * Math.sin(2 * omega)); |
+ let denominatorReal = |
+ 1 + a1 * Math.cos(omega) + a2 * Math.cos(2 * omega); |
+ let denominatorImag = |
+ -(a1 * Math.sin(omega) + a2 * Math.sin(2 * omega)); |
+ |
+ let magnitude = Math.sqrt( |
+ (numeratorReal * numeratorReal + numeratorImag * numeratorImag) / |
+ (denominatorReal * denominatorReal + |
+ denominatorImag * denominatorImag)); |
+ let phase = Math.atan2(numeratorImag, numeratorReal) - |
+ Math.atan2(denominatorImag, denominatorReal); |
+ |
+ if (phase >= Math.PI) { |
+ phase -= 2 * Math.PI; |
+ } else if (phase <= -Math.PI) { |
+ phase += 2 * Math.PI; |
} |
- } |
- return -1; |
-} |
- |
-// Compute absolute value of the difference between phase angles, taking into account the wrapping |
-// of phases. |
-function absolutePhaseDifference(x, y) |
-{ |
- let diff = Math.abs(x - y); |
- |
- if (diff > Math.PI) { |
- diff = 2 * Math.PI - diff; |
- } |
- return diff; |
-} |
- |
-// Compare the frequency response with our expected response. |
-function compareResponses(should, filter, frequencies, magResponse, phaseResponse) |
-{ |
- let expectedResponse = frequencyResponseReference(filter, frequencies); |
- |
- expectedMagnitudes = expectedResponse.magnitudes; |
- expectedPhases = expectedResponse.phases; |
- |
- let n = magResponse.length; |
- let badResponse = false; |
- |
- let maxMagError = -1; |
- let maxMagErrorIndex = -1; |
- |
- let k; |
- let hasBadNumber; |
- |
- hasBadNumber = findBadNumber(magResponse); |
- badResponse = !should(hasBadNumber >= 0 ? 1 : 0, |
- "Number of non-finite values in magnitude response") |
- .beEqualTo(0); |
- |
- hasBadNumber = findBadNumber(phaseResponse); |
- badResponse = !should(hasBadNumber >= 0 ? 1 : 0, |
- "Number of non-finte values in phase response") |
- .beEqualTo(0); |
- |
- // These aren't testing the implementation itself. Instead, these are sanity checks on the |
- // reference. Failure here does not imply an error in the implementation. |
- hasBadNumber = findBadNumber(expectedMagnitudes); |
- badResponse = !should(hasBadNumber >= 0 ? 1 : 0, |
- "Number of non-finite values in the expected magnitude response") |
- .beEqualTo(0); |
- |
- hasBadNumber = findBadNumber(expectedPhases); |
- badResponse = !should(hasBadNumber >= 0 ? 1 : 0, |
- "Number of non-finite values in expected phase response") |
- .beEqualTo(0); |
- |
- // If we found a NaN or infinity, the following tests aren't very helpful, especially for NaN. |
- // We run them anyway, after printing a warning message. |
- should(!badResponse, |
- "Actual and expected results contained only finite values") |
- .beTrue(); |
- |
- for (k = 0; k < n; ++k) { |
- let error = Math.abs(linearToDecibels(magResponse[k]) - linearToDecibels(expectedMagnitudes[k])); |
- if (error > maxMagError) { |
+ |
+ return {magnitude: magnitude, phase: phase}; |
+ } |
+ |
+ // Compute the reference frequency response for the biquad filter |filter| |
+ // at the frequency samples given by |frequencies|. |
+ function frequencyResponseReference(filter, frequencies) { |
+ let sampleRate = filter.context.sampleRate; |
+ let normalizedFreq = |
+ normalizedFrequency(filter.frequency.value, sampleRate); |
+ let filterCoefficients = createFilter( |
+ filter.type, normalizedFreq, filter.Q.value, filter.gain.value); |
+ |
+ let magnitudes = []; |
+ let phases = []; |
+ |
+ for (let k = 0; k < frequencies.length; ++k) { |
+ let response = getResponseAt( |
+ filterCoefficients, |
+ normalizedFrequency(frequencies[k], sampleRate)); |
+ magnitudes.push(response.magnitude); |
+ phases.push(response.phase); |
+ } |
+ |
+ return {magnitudes: magnitudes, phases: phases}; |
+ } |
+ |
+ // Compute a set of linearly spaced frequencies. |
+ function createFrequencies(nFrequencies, sampleRate) { |
+ let frequencies = new Float32Array(nFrequencies); |
+ let nyquist = sampleRate / 2; |
+ let freqDelta = nyquist / nFrequencies; |
+ |
+ for (let k = 0; k < nFrequencies; ++k) { |
+ frequencies[k] = k * freqDelta; |
+ } |
+ |
+ return frequencies; |
+ } |
+ |
+ function linearToDecibels(x) { |
+ if (x) { |
+ return 20 * Math.log(x) / Math.LN10; |
+ } else { |
+ return -1000; |
+ } |
+ } |
+ |
+ // Look through the array and find any NaN or infinity. Returns the index |
+ // of the first occurence or -1 if none. |
+ function findBadNumber(signal) { |
+ for (let k = 0; k < signal.length; ++k) { |
+ if (!isValidNumber(signal[k])) { |
+ return k; |
+ } |
+ } |
+ return -1; |
+ } |
+ |
+ // Compute absolute value of the difference between phase angles, taking |
+ // into account the wrapping of phases. |
+ function absolutePhaseDifference(x, y) { |
+ let diff = Math.abs(x - y); |
+ |
+ if (diff > Math.PI) { |
+ diff = 2 * Math.PI - diff; |
+ } |
+ return diff; |
+ } |
+ |
+ // Compare the frequency response with our expected response. |
+ function compareResponses( |
+ should, filter, frequencies, magResponse, phaseResponse) { |
+ let expectedResponse = frequencyResponseReference(filter, frequencies); |
+ |
+ expectedMagnitudes = expectedResponse.magnitudes; |
+ expectedPhases = expectedResponse.phases; |
+ |
+ let n = magResponse.length; |
+ let badResponse = false; |
+ |
+ let maxMagError = -1; |
+ let maxMagErrorIndex = -1; |
+ |
+ let k; |
+ let hasBadNumber; |
+ |
+ hasBadNumber = findBadNumber(magResponse); |
+ badResponse = !should( |
+ hasBadNumber >= 0 ? 1 : 0, |
+ 'Number of non-finite values in magnitude response') |
+ .beEqualTo(0); |
+ |
+ hasBadNumber = findBadNumber(phaseResponse); |
+ badResponse = !should( |
+ hasBadNumber >= 0 ? 1 : 0, |
+ 'Number of non-finte values in phase response') |
+ .beEqualTo(0); |
+ |
+ // These aren't testing the implementation itself. Instead, these are |
+ // sanity checks on the reference. Failure here does not imply an error |
+ // in the implementation. |
+ hasBadNumber = findBadNumber(expectedMagnitudes); |
+ badResponse = |
+ !should( |
+ hasBadNumber >= 0 ? 1 : 0, |
+ 'Number of non-finite values in the expected magnitude response') |
+ .beEqualTo(0); |
+ |
+ hasBadNumber = findBadNumber(expectedPhases); |
+ badResponse = |
+ !should( |
+ hasBadNumber >= 0 ? 1 : 0, |
+ 'Number of non-finite values in expected phase response') |
+ .beEqualTo(0); |
+ |
+ // If we found a NaN or infinity, the following tests aren't very |
+ // helpful, especially for NaN. We run them anyway, after printing a |
+ // warning message. |
+ should( |
+ !badResponse, |
+ 'Actual and expected results contained only finite values') |
+ .beTrue(); |
+ |
+ for (k = 0; k < n; ++k) { |
+ let error = Math.abs( |
+ linearToDecibels(magResponse[k]) - |
+ linearToDecibels(expectedMagnitudes[k])); |
+ if (error > maxMagError) { |
maxMagError = error; |
maxMagErrorIndex = k; |
+ } |
} |
- } |
- |
- should( |
- linearToDecibels(maxMagError), 'Max error (' + |
- linearToDecibels(maxMagError) + |
- ' dB) of magnitude response at frequency ' + |
- frequencies[maxMagErrorIndex] + ' Hz') |
- .beLessThanOrEqualTo(linearToDecibels(maxAllowedMagError)); |
- let maxPhaseError = -1; |
- let maxPhaseErrorIndex = -1; |
- |
- for (k = 0; k < n; ++k) { |
- let error = absolutePhaseDifference(phaseResponse[k], expectedPhases[k]); |
- if (error > maxPhaseError) { |
+ |
+ should( |
+ linearToDecibels(maxMagError), |
+ 'Max error (' + linearToDecibels(maxMagError) + |
+ ' dB) of magnitude response at frequency ' + |
+ frequencies[maxMagErrorIndex] + ' Hz') |
+ .beLessThanOrEqualTo(linearToDecibels(maxAllowedMagError)); |
+ let maxPhaseError = -1; |
+ let maxPhaseErrorIndex = -1; |
+ |
+ for (k = 0; k < n; ++k) { |
+ let error = |
+ absolutePhaseDifference(phaseResponse[k], expectedPhases[k]); |
+ if (error > maxPhaseError) { |
maxPhaseError = error; |
maxPhaseErrorIndex = k; |
+ } |
} |
- } |
- |
- should( |
- radToDegree(maxPhaseError), 'Max error (' + radToDegree(maxPhaseError) + |
- ' deg) in phase response at frequency ' + |
- frequencies[maxPhaseErrorIndex] + ' Hz') |
- .beLessThanOrEqualTo(radToDegree(maxAllowedPhaseError)); |
-} |
- |
-function radToDegree(rad) { |
- // Radians to degrees |
- return rad * 180 / Math.PI; |
-} |
- |
-audit.define({ |
- label: "test", |
- description: "Biquad frequency response" |
-}, function (task, should) { |
- context = new AudioContext(); |
- |
- filter = context.createBiquadFilter(); |
- |
- // Arbitrarily test a peaking filter, but any kind of filter can be tested. |
- filter.type = "peaking"; |
- filter.frequency.value = filterCutoff; |
- filter.Q.value = filterQ; |
- filter.gain.value = 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); |
- |
- task.done(); |
-}); |
- |
-audit.run(); |
-</script> |
- |
-</body> |
+ |
+ should( |
+ radToDegree(maxPhaseError), |
+ 'Max error (' + radToDegree(maxPhaseError) + |
+ ' deg) in phase response at frequency ' + |
+ frequencies[maxPhaseErrorIndex] + ' Hz') |
+ .beLessThanOrEqualTo(radToDegree(maxAllowedPhaseError)); |
+ } |
+ |
+ function radToDegree(rad) { |
+ // Radians to degrees |
+ return rad * 180 / Math.PI; |
+ } |
+ |
+ audit.define( |
+ {label: 'test', description: 'Biquad frequency response'}, |
+ function(task, should) { |
+ context = new AudioContext(); |
+ |
+ filter = context.createBiquadFilter(); |
+ |
+ // Arbitrarily test a peaking filter, but any kind of filter can be |
+ // tested. |
+ filter.type = 'peaking'; |
+ filter.frequency.value = filterCutoff; |
+ filter.Q.value = filterQ; |
+ filter.gain.value = 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); |
+ |
+ task.done(); |
+ }); |
+ |
+ audit.run(); |
+ </script> |
+ </body> |
</html> |