Index: third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js |
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js |
index 4d9c88111cf1f51353bf17be809de6915424b306..6633650c61d93839739fccec1dd7043e6c625a4c 100644 |
--- a/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js |
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js |
@@ -11,10 +11,10 @@ var waveShapingCurve; |
var waveshaper; |
// FIXME: test at more frequencies. |
-// When using the up-sampling filters (2x, 4x) any significant aliasing components |
-// should be at very high frequencies near Nyquist. These tests could be improved |
-// to allow for a higher acceptable amount of aliasing near Nyquist, but then |
-// become more stringent for lower frequencies. |
+// When using the up-sampling filters (2x, 4x) any significant aliasing |
+// components should be at very high frequencies near Nyquist. These tests |
+// could be improved to allow for a higher acceptable amount of aliasing near |
+// Nyquist, but then become more stringent for lower frequencies. |
// These test parameters are set in runWaveShaperOversamplingTest(). |
var sampleRate; |
@@ -26,133 +26,149 @@ var acceptableAliasingThresholdDecibels; |
var kScale = 0.25; |
// Chebyshev Polynomials. |
-// Given an input sinusoid, returns an output sinusoid of the given frequency multiple. |
-function T0(x) { return 1; } |
-function T1(x) { return x; } |
-function T2(x) { return 2*x*x - 1; } |
-function T3(x) { return 4*x*x*x - 3*x; } |
-function T4(x) { return 8*x*x*x*x - 8*x*x + 1; } |
+// Given an input sinusoid, returns an output sinusoid of the given frequency |
+// multiple. |
+function T0(x) { |
+ return 1; |
+} |
+function T1(x) { |
+ return x; |
+} |
+function T2(x) { |
+ return 2 * x * x - 1; |
+} |
+function T3(x) { |
+ return 4 * x * x * x - 3 * x; |
+} |
+function T4(x) { |
+ return 8 * x * x * x * x - 8 * x * x + 1; |
+} |
function generateWaveShapingCurve() { |
- var n = 65536; |
- var n2 = n / 2; |
- var curve = new Float32Array(n); |
- |
- // The shaping curve uses Chebyshev Polynomial such that an input sinusoid |
- // at frequency f will generate an output of four sinusoids of frequencies: |
- // f, 2*f, 3*f, 4*f |
- // each of which is scaled. |
- for (var i = 0; i < n; ++i) { |
- var x = (i - n2) / n2; |
- var y = kScale * (T1(x) + T2(x) + T3(x) + T4(x)); |
- curve[i] = y; |
- } |
- |
- return curve; |
+ let n = 65536; |
+ let n2 = n / 2; |
+ let curve = new Float32Array(n); |
+ |
+ // The shaping curve uses Chebyshev Polynomial such that an input sinusoid |
+ // at frequency f will generate an output of four sinusoids of frequencies: |
+ // f, 2*f, 3*f, 4*f |
+ // each of which is scaled. |
+ for (let i = 0; i < n; ++i) { |
+ let x = (i - n2) / n2; |
+ let y = kScale * (T1(x) + T2(x) + T3(x) + T4(x)); |
+ curve[i] = y; |
+ } |
+ |
+ return curve; |
} |
function checkShapedCurve(buffer, should) { |
- var outputData = buffer.getChannelData(0); |
- var n = buffer.length; |
- |
- // The WaveShaperNode will have a processing latency if oversampling is used, |
- // so we should account for it. |
- |
- // FIXME: .latency should be exposed as an attribute of the node |
- // var waveShaperLatencyFrames = waveshaper.latency * sampleRate; |
- // But for now we'll use the hard-coded values corresponding to the actual latencies: |
- var waveShaperLatencyFrames = 0; |
- if (oversample == "2x") |
- waveShaperLatencyFrames = 128; |
- else if (oversample == "4x") |
- waveShaperLatencyFrames = 192; |
- |
- var worstDeltaInDecibels = -1000; |
- |
- for (var i = waveShaperLatencyFrames; i < n; ++i) { |
- var actual = outputData[i]; |
- |
- // Account for the expected processing latency. |
- var j = i - waveShaperLatencyFrames; |
- |
- // Compute reference sinusoids. |
- var phaseInc = 2 * Math.PI * fundamentalFrequency / sampleRate; |
- |
- // Generate an idealized reference based on the four generated frequencies truncated |
- // to the Nyquist rate. Ideally, we'd like the waveshaper's oversampling to perfectly |
- // remove all frequencies above Nyquist to avoid aliasing. In reality the oversampling filters are not |
- // quite perfect, so there will be a (hopefully small) amount of aliasing. We should |
- // be close to the ideal. |
- var reference = 0; |
- |
- // Sum in fundamental frequency. |
- if (fundamentalFrequency < nyquist) |
- reference += Math.sin(phaseInc * j); |
- |
- // Note that the phase of each of the expected generated harmonics is different. |
- if (fundamentalFrequency * 2 < nyquist) |
- reference += -Math.cos(phaseInc * j * 2); |
- if (fundamentalFrequency * 3 < nyquist) |
- reference += -Math.sin(phaseInc * j * 3); |
- if (fundamentalFrequency * 4 < nyquist) |
- reference += Math.cos(phaseInc * j * 4); |
- |
- // Scale the reference the same as the waveshaping curve itself. |
- reference *= kScale; |
- |
- var delta = Math.abs(actual - reference); |
- var deltaInDecibels = delta > 0 ? 20 * Math.log(delta)/Math.log(10) : -200; |
- |
- if (j >= filterStabilizeSkipFrames) { |
- if (deltaInDecibels > worstDeltaInDecibels) { |
- worstDeltaInDecibels = deltaInDecibels; |
- } |
- } |
+ let outputData = buffer.getChannelData(0); |
+ let n = buffer.length; |
+ |
+ // The WaveShaperNode will have a processing latency if oversampling is used, |
+ // so we should account for it. |
+ |
+ // FIXME: .latency should be exposed as an attribute of the node |
+ // var waveShaperLatencyFrames = waveshaper.latency * sampleRate; |
+ // But for now we'll use the hard-coded values corresponding to the actual |
+ // latencies: |
+ let waveShaperLatencyFrames = 0; |
+ if (oversample == '2x') |
+ waveShaperLatencyFrames = 128; |
+ else if (oversample == '4x') |
+ waveShaperLatencyFrames = 192; |
+ |
+ let worstDeltaInDecibels = -1000; |
+ |
+ for (let i = waveShaperLatencyFrames; i < n; ++i) { |
+ let actual = outputData[i]; |
+ |
+ // Account for the expected processing latency. |
+ let j = i - waveShaperLatencyFrames; |
+ |
+ // Compute reference sinusoids. |
+ let phaseInc = 2 * Math.PI * fundamentalFrequency / sampleRate; |
+ |
+ // Generate an idealized reference based on the four generated frequencies |
+ // truncated to the Nyquist rate. Ideally, we'd like the waveshaper's |
+ // oversampling to perfectly remove all frequencies above Nyquist to avoid |
+ // aliasing. In reality the oversampling filters are not quite perfect, so |
+ // there will be a (hopefully small) amount of aliasing. We should be close |
+ // to the ideal. |
+ let reference = 0; |
+ |
+ // Sum in fundamental frequency. |
+ if (fundamentalFrequency < nyquist) |
+ reference += Math.sin(phaseInc * j); |
+ |
+ // Note that the phase of each of the expected generated harmonics is |
+ // different. |
+ if (fundamentalFrequency * 2 < nyquist) |
+ reference += -Math.cos(phaseInc * j * 2); |
+ if (fundamentalFrequency * 3 < nyquist) |
+ reference += -Math.sin(phaseInc * j * 3); |
+ if (fundamentalFrequency * 4 < nyquist) |
+ reference += Math.cos(phaseInc * j * 4); |
+ |
+ // Scale the reference the same as the waveshaping curve itself. |
+ reference *= kScale; |
+ |
+ let delta = Math.abs(actual - reference); |
+ let deltaInDecibels = |
+ delta > 0 ? 20 * Math.log(delta) / Math.log(10) : -200; |
+ |
+ if (j >= filterStabilizeSkipFrames) { |
+ if (deltaInDecibels > worstDeltaInDecibels) { |
+ worstDeltaInDecibels = deltaInDecibels; |
+ } |
} |
+ } |
- // console.log("worstDeltaInDecibels: " + worstDeltaInDecibels); |
+ // console.log("worstDeltaInDecibels: " + worstDeltaInDecibels); |
- should(worstDeltaInDecibels, oversample + |
- " WaveshaperNode oversampling error (in dBFS)") |
- .beLessThan(acceptableAliasingThresholdDecibels); |
+ should( |
+ worstDeltaInDecibels, |
+ oversample + ' WaveshaperNode oversampling error (in dBFS)') |
+ .beLessThan(acceptableAliasingThresholdDecibels); |
} |
function createImpulseBuffer(context, sampleFrameLength) { |
- var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate); |
- var n = audioBuffer.length; |
- var dataL = audioBuffer.getChannelData(0); |
+ let audioBuffer = |
+ context.createBuffer(1, sampleFrameLength, context.sampleRate); |
+ let n = audioBuffer.length; |
+ let dataL = audioBuffer.getChannelData(0); |
- for (var k = 0; k < n; ++k) |
- dataL[k] = 0; |
+ for (let k = 0; k < n; ++k) |
+ dataL[k] = 0; |
- dataL[0] = 1; |
+ dataL[0] = 1; |
- return audioBuffer; |
+ return audioBuffer; |
} |
function runWaveShaperOversamplingTest(testParams) { |
- sampleRate = testParams.sampleRate; |
- nyquist = 0.5 * sampleRate; |
- oversample = testParams.oversample; |
- fundamentalFrequency = testParams.fundamentalFrequency; |
- acceptableAliasingThresholdDecibels = testParams.acceptableAliasingThresholdDecibels; |
+ sampleRate = testParams.sampleRate; |
+ nyquist = 0.5 * sampleRate; |
+ oversample = testParams.oversample; |
+ fundamentalFrequency = testParams.fundamentalFrequency; |
+ acceptableAliasingThresholdDecibels = |
+ testParams.acceptableAliasingThresholdDecibels; |
- let audit = Audit.createTaskRunner(); |
+ let audit = Audit.createTaskRunner(); |
- audit.define({ |
- label: "test", |
- description: testParams.description |
- }, function (task, should) { |
+ audit.define( |
+ {label: 'test', description: testParams.description}, |
+ function(task, should) { |
// Create offline audio context. |
- var numberOfRenderFrames = sampleRate * lengthInSeconds; |
- context = new OfflineAudioContext(1, numberOfRenderFrames, |
- sampleRate); |
+ let numberOfRenderFrames = sampleRate * lengthInSeconds; |
+ context = new OfflineAudioContext(1, numberOfRenderFrames, sampleRate); |
// source -> waveshaper -> destination |
- var source = context.createBufferSource(); |
- source.buffer = createToneBuffer(context, fundamentalFrequency, |
- lengthInSeconds, 1); |
+ let source = context.createBufferSource(); |
+ source.buffer = |
+ createToneBuffer(context, fundamentalFrequency, lengthInSeconds, 1); |
// Apply a non-linear distortion curve. |
waveshaper = context.createWaveShaper(); |
@@ -167,7 +183,7 @@ function runWaveShaperOversamplingTest(testParams) { |
context.startRendering() |
.then(buffer => checkShapedCurve(buffer, should)) |
.then(() => task.done()); |
- }); |
+ }); |
- audit.run(); |
+ audit.run(); |
} |