Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / webaudio / resources / distance-model-testing.js
blob933cc146496c9f5dc6c158cda53256432232d052
1 var sampleRate = 44100.0;
3 // How many panner nodes to create for the test.
4 var nodesToCreate = 100;
6 // Time step when each panner node starts.
7 var timeStep = 0.001;
9 // Make sure we render long enough to get all of our nodes.
10 var renderLengthSeconds = timeStep * (nodesToCreate + 1);
12 // Length of an impulse signal.
13 var pulseLengthFrames = Math.round(timeStep * sampleRate);
15 // Globals to make debugging a little easier.
16 var context;
17 var impulse;
18 var bufferSource;
19 var panner;
20 var position;
21 var time;
22       
23 // For the record, these distance formulas were taken from the OpenAL
24 // spec
25 // (http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.pdf),
26 // not the code.  The Web Audio spec follows the OpenAL formulas.
28 function linearDistance(panner, x, y, z) {
29     var distance = Math.sqrt(x * x + y * y + z * z);
30     distance = Math.min(distance, panner.maxDistance);
31     var rolloff = panner.rolloffFactor;
32     var gain = (1 - rolloff * (distance - panner.refDistance) / (panner.maxDistance - panner.refDistance));
34     return gain;
37 function inverseDistance(panner, x, y, z) {
38     var distance = Math.sqrt(x * x + y * y + z * z);
39     distance = Math.min(distance, panner.maxDistance);
40     var rolloff = panner.rolloffFactor;
41     var gain = panner.refDistance / (panner.refDistance + rolloff * (distance - panner.refDistance));
43     return gain;
46 function exponentialDistance(panner, x, y, z) {
47     var distance = Math.sqrt(x * x + y * y + z * z);
48     distance = Math.min(distance, panner.maxDistance);
49     var rolloff = panner.rolloffFactor;
50     var gain = Math.pow(distance / panner.refDistance, -rolloff);
52     return gain;
55 // Map the distance model to the function that implements the model
56 var distanceModelFunction = {"linear": linearDistance,
57                              "inverse": inverseDistance,
58                              "exponential": exponentialDistance};
60 function createGraph(context, distanceModel, nodeCount) {
61     bufferSource = new Array(nodeCount);
62     panner = new Array(nodeCount);
63     position = new Array(nodeCount);
64     time = new Array(nodesToCreate);
66     impulse = createImpulseBuffer(context, pulseLengthFrames);
68     // Create all the sources and panners.
69     //
70     // We MUST use the EQUALPOWER panning model so that we can easily
71     // figure out the gain introduced by the panner.
72     //
73     // We want to stay in the middle of the panning range, which means
74     // we want to stay on the z-axis.  If we don't, then the effect of
75     // panning model will be much more complicated.  We're not testing
76     // the panner, but the distance model, so we want the panner effect
77     // to be simple.
78     //
79     // The panners are placed at a uniform intervals between the panner
80     // reference distance and the panner max distance.  The source is
81     // also started at regular intervals.
82     for (var k = 0; k < nodeCount; ++k) {
83         bufferSource[k] = context.createBufferSource();
84         bufferSource[k].buffer = impulse;
86         panner[k] = context.createPanner();
87         panner[k].panningModel = "equalpower";
88         panner[k].distanceModel = distanceModel;
90         var distanceStep = (panner[k].maxDistance - panner[k].refDistance) / nodeCount;
91         position[k] = distanceStep * k + panner[k].refDistance;
92         panner[k].setPosition(0, 0, position[k]);
94         bufferSource[k].connect(panner[k]);
95         panner[k].connect(context.destination);
97         time[k] = k * timeStep;
98         bufferSource[k].start(time[k]);
99     }
102 // distanceModel should be the distance model string like
103 // "linear", "inverse", or "exponential".
104 function createTestAndRun(context, distanceModel) {
105     // To test the distance models, we create a number of panners at
106     // uniformly spaced intervals on the z-axis.  Each of these are
107     // started at equally spaced time intervals.  After rendering the
108     // signals, we examine where each impulse is located and the
109     // attenuation of the impulse.  The attenuation is compared
110     // against our expected attenuation.
112     createGraph(context, distanceModel, nodesToCreate);
114     context.oncomplete = checkDistanceResult(distanceModel);
115     context.startRendering();
118 // The gain caused by the EQUALPOWER panning model, if we stay on the
119 // z axis, with the default orientations.
120 function equalPowerGain() {
121     return Math.SQRT1_2;
124 function checkDistanceResult(model) {
125     return function(event) {
126         renderedBuffer = event.renderedBuffer;
127         renderedData = renderedBuffer.getChannelData(0);
129         // The max allowed error between the actual gain and the expected
130         // value.  This is determined experimentally.  Set to 0 to see what
131         // the actual errors are.
132         var maxAllowedError = 3.3e-6;
133    
134         var success = true;
136         // Number of impulses we found in the rendered result.
137         var impulseCount = 0;
139         // Maximum relative error in the gain of the impulses.
140         var maxError = 0;
142         // Array of locations of the impulses that were not at the
143         // expected location.  (Contains the actual and expected frame
144         // of the impulse.)
145         var impulsePositionErrors = new Array();
147         // Step through the rendered data to find all the non-zero points
148         // so we can find where our distance-attenuated impulses are.
149         // These are tested against the expected attenuations at that
150         // distance.
151         for (var k = 0; k < renderedData.length; ++k) {
152             if (renderedData[k] != 0) {
153                 // Convert from string to index.
154                 var distanceFunction = distanceModelFunction[model];
155                 var expected = distanceFunction(panner[impulseCount], 0, 0, position[impulseCount]);
157                 // Adjust for the center-panning of the EQUALPOWER panning
158                 // model that we're using.
159                 expected *= equalPowerGain();
161                 var error = Math.abs(renderedData[k] - expected) / Math.abs(expected);
163                 maxError = Math.max(maxError, Math.abs(error));
165                 // Keep track of any impulses that aren't where we expect them
166                 // to be.
167                 var expectedOffset = timeToSampleFrame(time[impulseCount], sampleRate);
168                 if (k != expectedOffset) {
169                     impulsePositionErrors.push({ actual : k, expected : expectedOffset});
170                 }
171                 ++impulseCount;
172             }
173         }
175         if (impulseCount == nodesToCreate) {
176             testPassed("Number of impulses found matches number of panner nodes.");
177         } else {
178             testFailed("Number of impulses is incorrect.  Found " + impulseCount + " but expected " + nodesToCreate + ".");
179             success = false;
180         }
182         if (maxError <= maxAllowedError) {
183             testPassed("Distance gains are correct.");
184         } else {
185             testFailed("Distance gains are incorrect.  Max rel error = " + maxError + " (maxAllowedError = " + maxAllowedError + ")");
186             success = false;
187         }
189         // Display any timing errors that we found.
190         if (impulsePositionErrors.length > 0) {
191             success = false;
192             testFailed(impulsePositionErrors.length + " timing errors found");
193             for (var k = 0; k < impulsePositionErrors.length; ++k) {
194                 testFailed("Sample at frame " + impulsePositionErrors[k].actual + " but expected " + impulsePositionErrors[k].expected);
195             }
196         }
198         if (success) {
199             testPassed("Distance test passed for distance model " + model);
200         } else {
201             testFailed("Distance test failed for distance model " + model);
202         }
204         finishJSTest();
205     }