Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / webaudio / resources / panner-model-testing.js
blobf96857f8dd181410f17b33026eee231fee027133
1 var sampleRate = 44100.0;
3 var numberOfChannels = 1;
5 // Time step when each panner node starts.
6 var timeStep = 0.001;
8 // Length of the impulse signal.
9 var pulseLengthFrames = Math.round(timeStep * sampleRate);
11 // How many panner nodes to create for the test
12 var nodesToCreate = 100;
14 // Be sure we render long enough for all of our nodes.
15 var renderLengthSeconds = timeStep * (nodesToCreate + 1);
17 // These are global mostly for debugging.
18 var context;
19 var impulse;
20 var bufferSource;
21 var panner;
22 var position;
23 var time;
25 var renderedBuffer;
26 var renderedLeft;
27 var renderedRight;
29 function createGraph(context, nodeCount) {
30 bufferSource = new Array(nodeCount);
31 panner = new Array(nodeCount);
32 position = new Array(nodeCount);
33 time = new Array(nodeCount);
34 // Angle between panner locations. (nodeCount - 1 because we want
35 // to include both 0 and 180 deg.
36 var angleStep = Math.PI / (nodeCount - 1);
38 if (numberOfChannels == 2) {
39 impulse = createStereoImpulseBuffer(context, pulseLengthFrames);
41 else
42 impulse = createImpulseBuffer(context, pulseLengthFrames);
44 for (var k = 0; k < nodeCount; ++k) {
45 bufferSource[k] = context.createBufferSource();
46 bufferSource[k].buffer = impulse;
48 panner[k] = context.createPanner();
49 panner[k].panningModel = "equalpower";
50 panner[k].distanceModel = "linear";
52 var angle = angleStep * k;
53 position[k] = {angle : angle, x : Math.cos(angle), z : Math.sin(angle)};
54 panner[k].setPosition(position[k].x, 0, position[k].z);
56 bufferSource[k].connect(panner[k]);
57 panner[k].connect(context.destination);
59 // Start the source
60 time[k] = k * timeStep;
61 bufferSource[k].start(time[k]);
65 function createTestAndRun(context, nodeCount, numberOfSourceChannels) {
66 numberOfChannels = numberOfSourceChannels;
68 createGraph(context, nodeCount);
70 context.oncomplete = checkResult;
71 context.startRendering();
74 // Map our position angle to the azimuth angle (in degrees).
76 // An angle of 0 corresponds to an azimuth of 90 deg; pi, to -90 deg.
77 function angleToAzimuth(angle) {
78 return 90 - angle * 180 / Math.PI;
81 // The gain caused by the EQUALPOWER panning model
82 function equalPowerGain(angle) {
83 var azimuth = angleToAzimuth(angle);
85 if (numberOfChannels == 1) {
86 var panPosition = (azimuth + 90) / 180;
88 var gainL = Math.cos(0.5 * Math.PI * panPosition);
89 var gainR = Math.sin(0.5 * Math.PI * panPosition);
91 return { left : gainL, right : gainR };
92 } else {
93 if (azimuth <= 0) {
94 var panPosition = (azimuth + 90) / 90;
96 var gainL = 1 + Math.cos(0.5 * Math.PI * panPosition);
97 var gainR = Math.sin(0.5 * Math.PI * panPosition);
99 return { left : gainL, right : gainR };
100 } else {
101 var panPosition = azimuth / 90;
103 var gainL = Math.cos(0.5 * Math.PI * panPosition);
104 var gainR = 1 + Math.sin(0.5 * Math.PI * panPosition);
106 return { left : gainL, right : gainR };
111 function checkResult(event) {
112 renderedBuffer = event.renderedBuffer;
113 renderedLeft = renderedBuffer.getChannelData(0);
114 renderedRight = renderedBuffer.getChannelData(1);
116 // The max error we allow between the rendered impulse and the
117 // expected value. This value is experimentally determined. Set
118 // to 0 to make the test fail to see what the actual error is.
119 var maxAllowedError = 1.3e-6;
121 var success = true;
123 // Number of impulses found in the rendered result.
124 var impulseCount = 0;
126 // Max (relative) error and the index of the maxima for the left
127 // and right channels.
128 var maxErrorL = 0;
129 var maxErrorIndexL = 0;
130 var maxErrorR = 0;
131 var maxErrorIndexR = 0;
133 // Number of impulses that don't match our expected locations.
134 var timeCount = 0;
136 // Locations of where the impulses aren't at the expected locations.
137 var timeErrors = new Array();
139 for (var k = 0; k < renderedLeft.length; ++k) {
140 // We assume that the left and right channels start at the same instant.
141 if (renderedLeft[k] != 0 || renderedRight[k] != 0) {
142 // The expected gain for the left and right channels.
143 var pannerGain = equalPowerGain(position[impulseCount].angle);
144 var expectedL = pannerGain.left;
145 var expectedR = pannerGain.right;
147 // Absolute error in the gain.
148 var errorL = Math.abs(renderedLeft[k] - expectedL);
149 var errorR = Math.abs(renderedRight[k] - expectedR);
151 if (Math.abs(errorL) > maxErrorL) {
152 maxErrorL = Math.abs(errorL);
153 maxErrorIndexL = impulseCount;
155 if (Math.abs(errorR) > maxErrorR) {
156 maxErrorR = Math.abs(errorR);
157 maxErrorIndexR = impulseCount;
160 // Keep track of the impulses that didn't show up where we
161 // expected them to be.
162 var expectedOffset = timeToSampleFrame(time[impulseCount], sampleRate);
163 if (k != expectedOffset) {
164 timeErrors[timeCount] = { actual : k, expected : expectedOffset};
165 ++timeCount;
167 ++impulseCount;
171 if (impulseCount == nodesToCreate) {
172 testPassed("Number of impulses matches the number of panner nodes.");
173 } else {
174 testFailed("Number of impulses is incorrect. (Found " + impulseCount + " but expected " + nodesToCreate + ")");
175 success = false;
178 if (timeErrors.length > 0) {
179 success = false;
180 testFailed(timeErrors.length + " timing errors found in " + nodesToCreate + " panner nodes.");
181 for (var k = 0; k < timeErrors.length; ++k) {
182 testFailed("Impulse at sample " + timeErrors[k].actual + " but expected " + timeErrors[k].expected);
184 } else {
185 testPassed("All impulses at expected offsets.");
188 if (maxErrorL <= maxAllowedError) {
189 testPassed("Left channel gain values are correct.");
190 } else {
191 testFailed("Left channel gain values are incorrect. Max error = " + maxErrorL + " at time " + time[maxErrorIndexL] + " (threshold = " + maxAllowedError + ")");
192 success = false;
195 if (maxErrorR <= maxAllowedError) {
196 testPassed("Right channel gain values are correct.");
197 } else {
198 testFailed("Right channel gain values are incorrect. Max error = " + maxErrorR + " at time " + time[maxErrorIndexR] + " (threshold = " + maxAllowedError + ")");
199 success = false;
202 if (success) {
203 testPassed("EqualPower panner test passed");
204 } else {
205 testFailed("EqualPower panner test failed");
208 finishJSTest();