| Index: third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
|
| diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html b/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
|
| deleted file mode 100644
|
| index 961c56b99681ad20aef0088c6c8c48e3e1f3e1a7..0000000000000000000000000000000000000000
|
| --- a/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
|
| +++ /dev/null
|
| @@ -1,316 +0,0 @@
|
| -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
| -<html>
|
| -<head>
|
| -<script src="../resources/js-test.js"></script>
|
| -<script src="resources/compatibility.js"></script>
|
| -<script src="resources/audit-util.js"></script>
|
| -<script src="resources/audio-testing.js"></script>
|
| -<script src="resources/biquad-filters.js"></script>
|
| -<script src="resources/biquad-testing.js"></script>
|
| -</head>
|
| -
|
| -<body>
|
| -<div id="description"></div>
|
| -<div id="console"></div>
|
| -
|
| -<script>
|
| -description("Test Biquad getFrequencyResponse() functionality.");
|
| -
|
| -// 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.
|
| -
|
| -var context;
|
| -
|
| -// The biquad filter node.
|
| -var filter;
|
| -
|
| -// The magnitude response of the biquad filter.
|
| -var magResponse;
|
| -
|
| -// The phase response of the biquad filter.
|
| -var phaseResponse;
|
| -
|
| -// Number of frequency samples to take.
|
| -var numberOfFrequencies = 1000;
|
| -
|
| -// The filter parameters.
|
| -var filterCutoff = 1000; // Hz.
|
| -var filterQ = 1;
|
| -var filterGain = 5; // Decibels.
|
| -
|
| -// The maximum allowed error in the magnitude response.
|
| -var maxAllowedMagError = 5.7e-7;
|
| -
|
| -// The maximum allowed error in the phase response.
|
| -var maxAllowedPhaseError = 4.7e-8;
|
| -
|
| -// The magnitudes and phases of the reference frequency response.
|
| -var magResponse;
|
| -var phaseResponse;
|
| -
|
| -// The magnitudes and phases of the reference frequency response.
|
| -var expectedMagnitudes;
|
| -var expectedPhases;
|
| -
|
| -// Convert frequency in Hz to a normalized frequency between 0 to 1 with 1 corresponding to the
|
| -// Nyquist frequency.
|
| -function normalizedFrequency(freqHz, sampleRate)
|
| -{
|
| - var 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)
|
| -{
|
| - var b0 = coef.b0;
|
| - var b1 = coef.b1;
|
| - var b2 = coef.b2;
|
| - var a1 = coef.a1;
|
| - var 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.
|
| -
|
| - var omega = Math.PI * f;
|
| - var numeratorReal = b0 + b1 * Math.cos(omega) + b2 * Math.cos(2 * omega);
|
| - var numeratorImag = -(b1 * Math.sin(omega) + b2 * Math.sin(2 * omega));
|
| - var denominatorReal = 1 + a1 * Math.cos(omega) + a2 * Math.cos(2 * omega);
|
| - var denominatorImag = -(a1 * Math.sin(omega) + a2 * Math.sin(2 * omega));
|
| -
|
| - var magnitude = Math.sqrt((numeratorReal * numeratorReal + numeratorImag * numeratorImag)
|
| - / (denominatorReal * denominatorReal + denominatorImag * denominatorImag));
|
| - var 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)
|
| -{
|
| - var sampleRate = filter.context.sampleRate;
|
| - var normalizedFreq = normalizedFrequency(filter.frequency.value, sampleRate);
|
| - var filterCoefficients = createFilter(filter.type, normalizedFreq, filter.Q.value, filter.gain.value);
|
| -
|
| - var magnitudes = [];
|
| - var phases = [];
|
| -
|
| - for (var k = 0; k < frequencies.length; ++k) {
|
| - var 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)
|
| -{
|
| - var frequencies = new Float32Array(nFrequencies);
|
| - var nyquist = sampleRate / 2;
|
| - var freqDelta = nyquist / nFrequencies;
|
| -
|
| - for (var 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 (var 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)
|
| -{
|
| - var 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(filter, frequencies, magResponse, phaseResponse)
|
| -{
|
| - var expectedResponse = frequencyResponseReference(filter, frequencies);
|
| -
|
| - expectedMagnitudes = expectedResponse.magnitudes;
|
| - expectedPhases = expectedResponse.phases;
|
| -
|
| - var n = magResponse.length;
|
| - var success = true;
|
| - var badResponse = false;
|
| -
|
| - var maxMagError = -1;
|
| - var maxMagErrorIndex = -1;
|
| -
|
| - var k;
|
| - var hasBadNumber;
|
| -
|
| - hasBadNumber = findBadNumber(magResponse);
|
| - if (hasBadNumber >= 0) {
|
| - testFailed("Magnitude response has NaN or infinity at " + hasBadNumber);
|
| - success = false;
|
| - badResponse = true;
|
| - }
|
| -
|
| - hasBadNumber = findBadNumber(phaseResponse);
|
| - if (hasBadNumber >= 0) {
|
| - testFailed("Phase response has NaN or infinity at " + hasBadNumber);
|
| - success = false;
|
| - badResponse = true;
|
| - }
|
| -
|
| - // 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);
|
| - if (hasBadNumber >= 0) {
|
| - testFailed("Expected magnitude response has NaN or infinity at " + hasBadNumber);
|
| - success = false;
|
| - badResponse = true;
|
| - }
|
| -
|
| - hasBadNumber = findBadNumber(expectedPhases);
|
| - if (hasBadNumber >= 0) {
|
| - testFailed("Expected phase response has NaN or infinity at " + hasBadNumber);
|
| - success = false;
|
| - badResponse = true;
|
| - }
|
| -
|
| - // 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.
|
| -
|
| - if (badResponse) {
|
| - testFailed("NaN or infinity in the actual or expected results makes the following test results suspect.");
|
| - success = false;
|
| - }
|
| -
|
| - for (k = 0; k < n; ++k) {
|
| - var error = Math.abs(linearToDecibels(magResponse[k]) - linearToDecibels(expectedMagnitudes[k]));
|
| - if (error > maxMagError) {
|
| - maxMagError = error;
|
| - maxMagErrorIndex = k;
|
| - }
|
| - }
|
| -
|
| - if (maxMagError > maxAllowedMagError) {
|
| - var message = "Magnitude error (" + maxMagError + " dB)";
|
| - message += " exceeded threshold at " + frequencies[maxMagErrorIndex];
|
| - message += " Hz. Actual: " + linearToDecibels(magResponse[maxMagErrorIndex]);
|
| - message += " dB, expected: " + linearToDecibels(expectedMagnitudes[maxMagErrorIndex]) + " dB.";
|
| - testFailed(message);
|
| - success = false;
|
| - } else {
|
| - testPassed("Magnitude response within acceptable threshold.");
|
| - }
|
| -
|
| - var maxPhaseError = -1;
|
| - var maxPhaseErrorIndex = -1;
|
| -
|
| - for (k = 0; k < n; ++k) {
|
| - var error = absolutePhaseDifference(phaseResponse[k], expectedPhases[k]);
|
| - if (error > maxPhaseError) {
|
| - maxPhaseError = error;
|
| - maxPhaseErrorIndex = k;
|
| - }
|
| - }
|
| -
|
| - if (maxPhaseError > maxAllowedPhaseError) {
|
| - var message = "Phase error (radians) (" + maxPhaseError;
|
| - message += ") exceeded threshold at " + frequencies[maxPhaseErrorIndex];
|
| - message += " Hz. Actual: " + phaseResponse[maxPhaseErrorIndex];
|
| - message += " expected: " + expectedPhases[maxPhaseErrorIndex];
|
| - testFailed(message);
|
| - success = false;
|
| - } else {
|
| - testPassed("Phase response within acceptable threshold.");
|
| - }
|
| -
|
| -
|
| - return success;
|
| -}
|
| -
|
| -function runTest()
|
| -{
|
| - if (window.testRunner) {
|
| - testRunner.dumpAsText();
|
| - testRunner.waitUntilDone();
|
| - }
|
| -
|
| - window.jsTestIsAsync = true;
|
| -
|
| - 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;
|
| -
|
| - var frequencies = createFrequencies(numberOfFrequencies, context.sampleRate);
|
| - magResponse = new Float32Array(numberOfFrequencies);
|
| - phaseResponse = new Float32Array(numberOfFrequencies);
|
| -
|
| - filter.getFrequencyResponse(frequencies, magResponse, phaseResponse);
|
| - var success = compareResponses(filter, frequencies, magResponse, phaseResponse);
|
| -
|
| - if (success) {
|
| - testPassed("Frequency response was correct.");
|
| - } else {
|
| - testFailed("Frequency response was incorrect.");
|
| - }
|
| -
|
| - finishJSTest();
|
| -}
|
| -
|
| -runTest();
|
| -successfullyParsed = true;
|
| -
|
| -</script>
|
| -
|
| -</body>
|
| -</html>
|
|
|