Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / webaudio / resources / waveshaper-testing.js
blob923bb7dd5cc99b7d481b30abe27d4bcac4672990
1 var context;
2 var lengthInSeconds = 2;
4 // Skip this many frames before comparing against reference to allow
5 // a steady-state to be reached in the up-sampling filters.
6 var filterStabilizeSkipFrames = 2048;
8 var numberOfCurveFrames = 65536;
9 var waveShapingCurve;
11 var waveshaper;
13 // FIXME: test at more frequencies.
14 // When using the up-sampling filters (2x, 4x) any significant aliasing components
15 // should be at very high frequencies near Nyquist.  These tests could be improved
16 // to allow for a higher acceptable amount of aliasing near Nyquist, but then
17 // become more stringent for lower frequencies.
19 // These test parameters are set in runWaveShaperOversamplingTest().
20 var sampleRate;
21 var nyquist;
22 var oversample;
23 var fundamentalFrequency;
24 var acceptableAliasingThresholdDecibels;
26 var kScale = 0.25;
28 // Chebyshev Polynomials.
29 // Given an input sinusoid, returns an output sinusoid of the given frequency multiple.
30 function T0(x) { return 1; }
31 function T1(x) { return x; }
32 function T2(x) { return 2*x*x - 1; }
33 function T3(x) { return 4*x*x*x - 3*x; }
34 function T4(x) { return 8*x*x*x*x - 8*x*x + 1; }
36 function generateWaveShapingCurve() {
37     var n = 65536;
38     var n2 = n / 2;
39     var curve = new Float32Array(n);
41     // The shaping curve uses Chebyshev Polynomial such that an input sinusoid
42     // at frequency f will generate an output of four sinusoids of frequencies:
43     // f, 2*f, 3*f, 4*f
44     // each of which is scaled.
45     for (var i = 0; i < n; ++i) {
46         var x = (i - n2) / n2;
47         var y = kScale * (T1(x) + T2(x) + T3(x) + T4(x));
48         curve[i] = y;
49     }
51     return curve;
54 function checkShapedCurve(event) {
55     var buffer = event.renderedBuffer;
57     var outputData = buffer.getChannelData(0);
58     var n = buffer.length;
60     // The WaveShaperNode will have a processing latency if oversampling is used,
61     // so we should account for it.
63     // FIXME: .latency should be exposed as an attribute of the node
64     // var waveShaperLatencyFrames = waveshaper.latency * sampleRate;
65     // But for now we'll use the hard-coded values corresponding to the actual latencies:
66     var waveShaperLatencyFrames = 0;
67     if (oversample == "2x")
68         waveShaperLatencyFrames = 128;
69     else if (oversample == "4x")
70         waveShaperLatencyFrames = 192;
72     var worstDeltaInDecibels = -1000;
74     for (var i = waveShaperLatencyFrames; i < n; ++i) {
75         var actual = outputData[i];
77         // Account for the expected processing latency.
78         var j = i - waveShaperLatencyFrames;
80         // Compute reference sinusoids.
81         var phaseInc = 2 * Math.PI * fundamentalFrequency / sampleRate;
83         // Generate an idealized reference based on the four generated frequencies truncated
84         // to the Nyquist rate.  Ideally, we'd like the waveshaper's oversampling to perfectly
85         // remove all frequencies above Nyquist to avoid aliasing.  In reality the oversampling filters are not
86         // quite perfect, so there will be a (hopefully small) amount of aliasing.  We should
87         // be close to the ideal.
88         var reference = 0;
90         // Sum in fundamental frequency.
91         if (fundamentalFrequency < nyquist)
92             reference += Math.sin(phaseInc * j);
94         // Note that the phase of each of the expected generated harmonics is different.
95         if (fundamentalFrequency * 2 < nyquist)
96             reference += -Math.cos(phaseInc * j * 2);
97         if (fundamentalFrequency * 3 < nyquist)
98             reference += -Math.sin(phaseInc * j * 3);
99         if (fundamentalFrequency * 4 < nyquist)
100             reference += Math.cos(phaseInc * j * 4);
102         // Scale the reference the same as the waveshaping curve itself.
103         reference *= kScale;
105         var delta = Math.abs(actual - reference);
106         var deltaInDecibels = delta > 0 ? 20 * Math.log(delta)/Math.log(10) : -200;
108         if (j >= filterStabilizeSkipFrames) {
109             if (deltaInDecibels > worstDeltaInDecibels) {
110                 worstDeltaInDecibels = deltaInDecibels;
111             }
112         }
113     }
115     // console.log("worstDeltaInDecibels: " + worstDeltaInDecibels);
117     var success = worstDeltaInDecibels < acceptableAliasingThresholdDecibels;
119     if (success) {
120         testPassed(oversample + " WaveShaperNode oversampling within acceptable tolerance.");
121     } else {
122         testFailed(oversample + " WaveShaperNode oversampling not within acceptable tolerance.  Error = " + worstDeltaInDecibels + " dBFS");
123     }
125     finishJSTest();
128 function createImpulseBuffer(context, sampleFrameLength) {
129     var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate);
130     var n = audioBuffer.length;
131     var dataL = audioBuffer.getChannelData(0);
133     for (var k = 0; k < n; ++k)
134         dataL[k] = 0;
136     dataL[0] = 1;
138     return audioBuffer;
141 function runWaveShaperOversamplingTest(testParams) {
142     sampleRate = testParams.sampleRate;
143     nyquist = 0.5 * sampleRate;
144     oversample = testParams.oversample;
145     fundamentalFrequency = testParams.fundamentalFrequency;
146     acceptableAliasingThresholdDecibels = testParams.acceptableAliasingThresholdDecibels;
148     if (window.testRunner) {
149         testRunner.dumpAsText();
150         testRunner.waitUntilDone();
151     }
153     window.jsTestIsAsync = true;
155     // Create offline audio context.
156     var numberOfRenderFrames = sampleRate * lengthInSeconds;
157     context = new OfflineAudioContext(1, numberOfRenderFrames, sampleRate);
159     // source -> waveshaper -> destination
160     var source = context.createBufferSource();
161     source.buffer = createToneBuffer(context, fundamentalFrequency, lengthInSeconds, 1);
163     // Apply a non-linear distortion curve.
164     waveshaper = context.createWaveShaper();
165     waveshaper.curve = generateWaveShapingCurve();
166     waveshaper.oversample = oversample;
168     source.connect(waveshaper);
169     waveshaper.connect(context.destination);
171     source.start(0);
173     context.oncomplete = checkShapedCurve;
174     context.startRendering();