Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(559)

Side by Side Diff: LayoutTests/webaudio/resources/waveshaper-testing.js

Issue 15619003: Add support for WaveShaperNode.oversample (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: change TestExpectations in middle of file Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « LayoutTests/TestExpectations ('k') | LayoutTests/webaudio/waveshaper-oversample-2x.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 var context;
2 var lengthInSeconds = 2;
3
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;
7
8 var numberOfCurveFrames = 65536;
9 var waveShapingCurve;
10
11 var waveshaper;
12
13 // FIXME: test at more frequencies.
14 // When using the up-sampling filters (2x, 4x) any significant aliasing componen ts
15 // should be at very high frequencies near Nyquist. These tests could be improv ed
16 // to allow for a higher acceptable amount of aliasing near Nyquist, but then
17 // become more stringent for lower frequencies.
18
19 // These test parameters are set in runWaveShaperOversamplingTest().
20 var sampleRate;
21 var nyquist;
22 var oversample;
23 var fundamentalFrequency;
24 var acceptableAliasingThresholdDecibels;
25
26 var kScale = 0.25;
27
28 // Chebyshev Polynomials.
29 // Given an input sinusoid, returns an output sinusoid of the given frequency mu ltiple.
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; }
35
36 function generateWaveShapingCurve() {
37 var n = 65536;
38 var n2 = n / 2;
39 var curve = new Float32Array(n);
40
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 }
50
51 return curve;
52 }
53
54 function checkShapedCurve(event) {
55 var buffer = event.renderedBuffer;
56
57 var outputData = buffer.getChannelData(0);
58 var n = buffer.length;
59
60 // The WaveShaperNode will have a processing latency if oversampling is used ,
61 // so we should account for it.
62
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 l atencies:
66 var waveShaperLatencyFrames = 0;
67 if (oversample == "2x")
68 waveShaperLatencyFrames = 128;
69 else if (oversample == "4x")
70 waveShaperLatencyFrames = 192;
71
72 var worstDeltaInDecibels = -1000;
73
74 for (var i = waveShaperLatencyFrames; i < n; ++i) {
75 var actual = outputData[i];
76
77 // Account for the expected processing latency.
78 var j = i - waveShaperLatencyFrames;
79
80 // Compute reference sinusoids.
81 var phaseInc = 2 * Math.PI * fundamentalFrequency / sampleRate;
82
83 // Generate an idealized reference based on the four generated frequenci es truncated
84 // to the Nyquist rate. Ideally, we'd like the waveshaper's oversamplin g to perfectly
85 // remove all frequencies above Nyquist to avoid aliasing. In reality t he oversampling filters are not
86 // quite perfect, so there will be a (hopefully small) amount of aliasin g. We should
87 // be close to the ideal.
88 var reference = 0;
89
90 // Sum in fundamental frequency.
91 if (fundamentalFrequency < nyquist)
92 reference += Math.sin(phaseInc * j);
93
94 // Note that the phase of each of the expected generated harmonics is di fferent.
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);
101
102 // Scale the reference the same as the waveshaping curve itself.
103 reference *= kScale;
104
105 var delta = Math.abs(actual - reference);
106 var deltaInDecibels = delta > 0 ? 20 * Math.log(delta)/Math.log(10) : -2 00;
107
108 if (j >= filterStabilizeSkipFrames) {
109 if (deltaInDecibels > worstDeltaInDecibels) {
110 worstDeltaInDecibels = deltaInDecibels;
111 }
112 }
113 }
114
115 // console.log("worstDeltaInDecibels: " + worstDeltaInDecibels);
116
117 var success = worstDeltaInDecibels < acceptableAliasingThresholdDecibels;
118
119 if (success) {
120 testPassed(oversample + " WaveShaperNode oversampling within acceptable tolerance.");
121 } else {
122 testFailed(oversample + " WaveShaperNode oversampling not within accepta ble tolerance. Error = " + worstDeltaInDecibels + " dBFS");
123 }
124
125 finishJSTest();
126 }
127
128 function createImpulseBuffer(context, sampleFrameLength) {
129 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleR ate);
130 var n = audioBuffer.length;
131 var dataL = audioBuffer.getChannelData(0);
132
133 for (var k = 0; k < n; ++k)
134 dataL[k] = 0;
135
136 dataL[0] = 1;
137
138 return audioBuffer;
139 }
140
141 function runWaveShaperOversamplingTest(testParams) {
142 sampleRate = testParams.sampleRate;
143 nyquist = 0.5 * sampleRate;
144 oversample = testParams.oversample;
145 fundamentalFrequency = testParams.fundamentalFrequency;
146 acceptableAliasingThresholdDecibels = testParams.acceptableAliasingThreshold Decibels;
147
148 if (window.testRunner) {
149 testRunner.dumpAsText();
150 testRunner.waitUntilDone();
151 }
152
153 window.jsTestIsAsync = true;
154
155 // Create offline audio context.
156 var numberOfRenderFrames = sampleRate * lengthInSeconds;
157 context = new webkitOfflineAudioContext(1, numberOfRenderFrames, sampleRate) ;
158
159 // source -> waveshaper -> destination
160 var source = context.createBufferSource();
161 source.buffer = createToneBuffer(context, fundamentalFrequency, lengthInSeco nds, 1);
162
163 // Apply a non-linear distortion curve.
164 waveshaper = context.createWaveShaper();
165 waveshaper.curve = generateWaveShapingCurve();
166 waveshaper.oversample = oversample;
167
168 source.connect(waveshaper);
169 waveshaper.connect(context.destination);
170
171 source.start(0);
172
173 context.oncomplete = checkShapedCurve;
174 context.startRendering();
175 }
OLDNEW
« no previous file with comments | « LayoutTests/TestExpectations ('k') | LayoutTests/webaudio/waveshaper-oversample-2x.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698