OLD | NEW |
1 <!doctype html> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
4 <title>Test Clamping of Distance for PannerNode</title> | 4 <title> |
| 5 Test Clamping of Distance for PannerNode |
| 6 </title> |
5 <script src="../../resources/testharness.js"></script> | 7 <script src="../../resources/testharness.js"></script> |
6 <script src="../../resources/testharnessreport.js"></script> | 8 <script src="../../resources/testharnessreport.js"></script> |
7 <script src="../resources/audit-util.js"></script> | 9 <script src="../resources/audit-util.js"></script> |
8 <script src="../resources/audit.js"></script> | 10 <script src="../resources/audit.js"></script> |
9 </head> | 11 </head> |
| 12 <body> |
| 13 <script id="layout-test-code"> |
| 14 // Arbitrary sample rate and render length. |
| 15 let sampleRate = 48000; |
| 16 let renderFrames = 128; |
10 | 17 |
11 <body> | 18 let audit = Audit.createTaskRunner(); |
12 <script> | |
13 // Arbitrary sample rate and render length. | |
14 var sampleRate = 48000; | |
15 var renderFrames = 128; | |
16 | 19 |
17 var audit = Audit.createTaskRunner(); | 20 audit.define('ref-distance-error', (task, should) => { |
18 | 21 testDistanceLimits(should, {name: 'refDistance', isZeroAllowed: true}); |
19 audit.define("ref-distance-error", (task, should) => { | |
20 testDistanceLimits(should, {name: "refDistance", isZeroAllowed: true}); | |
21 task.done(); | 22 task.done(); |
22 }); | 23 }); |
23 | 24 |
24 audit.define("max-distance-error", (task, should) => { | 25 audit.define('max-distance-error', (task, should) => { |
25 testDistanceLimits(should, {name: "maxDistance", isZeroAllowed: false}); | 26 testDistanceLimits(should, {name: 'maxDistance', isZeroAllowed: false}); |
26 task.done(); | 27 task.done(); |
27 }); | 28 }); |
28 | 29 |
29 function testDistanceLimits(should, options) { | 30 function testDistanceLimits(should, options) { |
30 // Verify that exceptions are thrown for invalid values of refDistance. | 31 // Verify that exceptions are thrown for invalid values of refDistance. |
31 var context = new OfflineAudioContext(1, renderFrames, sampleRate); | 32 let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
32 | 33 |
33 var attrName = options.name; | 34 let attrName = options.name; |
34 var prefix = "new PannerNode(c, {" + attrName + ": "; | 35 let prefix = 'new PannerNode(c, {' + attrName + ': '; |
35 | 36 |
36 should(function () { | 37 should(function() { |
37 var nodeOptions = {}; | 38 let nodeOptions = {}; |
38 nodeOptions[attrName] = -1; | 39 nodeOptions[attrName] = -1; |
39 new PannerNode(context, nodeOptions); | 40 new PannerNode(context, nodeOptions); |
40 }, prefix + "-1})").throw("RangeError"); | 41 }, prefix + '-1})').throw('RangeError'); |
41 | 42 |
42 if (options.isZeroAllowed) { | 43 if (options.isZeroAllowed) { |
43 should(function () { | 44 should(function() { |
44 var nodeOptions = {}; | 45 let nodeOptions = {}; |
45 nodeOptions[attrName] = 0; | 46 nodeOptions[attrName] = 0; |
46 new PannerNode(context, nodeOptions); | 47 new PannerNode(context, nodeOptions); |
47 }, prefix + "0})").notThrow(); | 48 }, prefix + '0})').notThrow(); |
48 } else { | 49 } else { |
49 should(function () { | 50 should(function() { |
50 var nodeOptions = {}; | 51 let nodeOptions = {}; |
51 nodeOptions[attrName] = 0; | 52 nodeOptions[attrName] = 0; |
52 new PannerNode(context, nodeOptions); | 53 new PannerNode(context, nodeOptions); |
53 }, prefix + "0})").throw("RangeError"); | 54 }, prefix + '0})').throw('RangeError'); |
54 } | 55 } |
55 | 56 |
56 // The smallest representable positive single float. | 57 // The smallest representable positive single float. |
57 var leastPositiveDoubleFloat = 4.9406564584124654e-324; | 58 let leastPositiveDoubleFloat = 4.9406564584124654e-324; |
58 | 59 |
59 should( | 60 should(function() { |
60 function () { | 61 let nodeOptions = {}; |
61 var nodeOptions = {}; | 62 nodeOptions[attrName] = leastPositiveDoubleFloat; |
62 nodeOptions[attrName] = leastPositiveDoubleFloat; | 63 new PannerNode(context, nodeOptions); |
63 new PannerNode(context, nodeOptions); | 64 }, prefix + leastPositiveDoubleFloat + '})').notThrow(); |
64 }, prefix + leastPositiveDoubleFloat + "})") | |
65 .notThrow(); | |
66 | 65 |
67 prefix = "panner." + attrName + " = "; | 66 prefix = 'panner.' + attrName + ' = '; |
68 panner = new PannerNode(context); | 67 panner = new PannerNode(context); |
69 should(function () { | 68 should(function() { |
70 panner[attrName] = -1; | 69 panner[attrName] = -1; |
71 }, prefix + "-1").throw("RangeError"); | 70 }, prefix + '-1').throw('RangeError'); |
72 | 71 |
73 if (options.isZeroAllowed) { | 72 if (options.isZeroAllowed) { |
74 should(function () { | 73 should(function() { |
75 panner[attrName] = 0; | 74 panner[attrName] = 0; |
76 }, prefix + "0").notThrow(); | 75 }, prefix + '0').notThrow(); |
77 } else { | 76 } else { |
78 should(function () { | 77 should(function() { |
79 panner[attrName] = 0; | 78 panner[attrName] = 0; |
80 }, prefix + "0").throw("RangeError"); | 79 }, prefix + '0').throw('RangeError'); |
81 } | 80 } |
82 | 81 |
83 should(function () { | 82 should(function() { |
84 panner[attrName] = leastPositiveDoubleFloat; | 83 panner[attrName] = leastPositiveDoubleFloat; |
85 }, prefix + leastPositiveDoubleFloat).notThrow(); | 84 }, prefix + leastPositiveDoubleFloat).notThrow(); |
86 } | 85 } |
87 | 86 |
88 audit.define("min-distance", (task, should) => { | 87 audit.define('min-distance', (task, should) => { |
89 // Test clamping of panner distance to refDistance for all of the | 88 // Test clamping of panner distance to refDistance for all of the |
90 // distance models. The actual distance is arbitrary as long as it's | 89 // distance models. The actual distance is arbitrary as long as it's |
91 // less than refDistance. We test default and non-default values for | 90 // less than refDistance. We test default and non-default values for |
92 // the panner's refDistance and maxDistance. | 91 // the panner's refDistance and maxDistance. |
93 // correctly. | 92 // correctly. |
94 Promise.all([ | 93 Promise |
95 runTest(should, { | 94 .all([ |
96 distance: 0.01, | 95 runTest(should, { |
97 distanceModel: "linear", | 96 distance: 0.01, |
98 }), | 97 distanceModel: 'linear', |
99 runTest(should, { | 98 }), |
100 distance: 0.01, | 99 runTest(should, { |
101 distanceModel: "exponential", | 100 distance: 0.01, |
102 }), | 101 distanceModel: 'exponential', |
103 runTest(should, { | 102 }), |
104 distance: 0.01, | 103 runTest(should, { |
105 distanceModel: "inverse", | 104 distance: 0.01, |
106 }), | 105 distanceModel: 'inverse', |
107 runTest(should, { | 106 }), |
108 distance: 2, | 107 runTest(should, { |
109 distanceModel: "linear", | 108 distance: 2, |
110 maxDistance: 1000, | 109 distanceModel: 'linear', |
111 refDistance: 10, | 110 maxDistance: 1000, |
112 }), | 111 refDistance: 10, |
113 runTest(should, { | 112 }), |
114 distance: 2, | 113 runTest(should, { |
115 distanceModel: "exponential", | 114 distance: 2, |
116 maxDistance: 1000, | 115 distanceModel: 'exponential', |
117 refDistance: 10, | 116 maxDistance: 1000, |
118 }), | 117 refDistance: 10, |
119 runTest(should, { | 118 }), |
120 distance: 2, | 119 runTest(should, { |
121 distanceModel: "inverse", | 120 distance: 2, |
122 maxDistance: 1000, | 121 distanceModel: 'inverse', |
123 refDistance: 10, | 122 maxDistance: 1000, |
124 }), | 123 refDistance: 10, |
125 ]) | 124 }), |
126 .then(() => task.done()); | 125 ]) |
| 126 .then(() => task.done()); |
127 }); | 127 }); |
128 | 128 |
129 audit.define("max-distance", (task, should) => { | 129 audit.define('max-distance', (task, should) => { |
130 // Like the "min-distance" task, but for clamping to the max | 130 // Like the "min-distance" task, but for clamping to the max |
131 // distance. The actual distance is again arbitrary as long as it is | 131 // distance. The actual distance is again arbitrary as long as it is |
132 // greater than maxDistance. | 132 // greater than maxDistance. |
133 Promise.all([ | 133 Promise |
134 runTest(should, { | 134 .all([ |
135 distance: 20000, | 135 runTest(should, { |
136 distanceModel: "linear", | 136 distance: 20000, |
137 }), | 137 distanceModel: 'linear', |
138 runTest(should, { | 138 }), |
139 distance: 21000, | 139 runTest(should, { |
140 distanceModel: "exponential", | 140 distance: 21000, |
141 }), | 141 distanceModel: 'exponential', |
142 runTest(should, { | 142 }), |
143 distance: 23000, | 143 runTest(should, { |
144 distanceModel: "inverse", | 144 distance: 23000, |
145 }), | 145 distanceModel: 'inverse', |
146 runTest(should, { | 146 }), |
147 distance: 5000, | 147 runTest(should, { |
148 distanceModel: "linear", | 148 distance: 5000, |
149 maxDistance: 1000, | 149 distanceModel: 'linear', |
150 refDistance: 10, | 150 maxDistance: 1000, |
151 }), | 151 refDistance: 10, |
152 runTest(should, { | 152 }), |
153 distance: 5000, | 153 runTest(should, { |
154 distanceModel: "exponential", | 154 distance: 5000, |
155 maxDistance: 1000, | 155 distanceModel: 'exponential', |
156 refDistance: 10, | 156 maxDistance: 1000, |
157 }), | 157 refDistance: 10, |
158 runTest(should, { | 158 }), |
159 distance: 5000, | 159 runTest(should, { |
160 distanceModel: "inverse", | 160 distance: 5000, |
161 maxDistance: 1000, | 161 distanceModel: 'inverse', |
162 refDistance: 10, | 162 maxDistance: 1000, |
163 }), | 163 refDistance: 10, |
164 ]) | 164 }), |
165 .then(() => task.done()); | 165 ]) |
| 166 .then(() => task.done()); |
166 }); | 167 }); |
167 | 168 |
168 function runTest(should, options) { | 169 function runTest(should, options) { |
169 var context = new OfflineAudioContext(2, renderFrames, sampleRate); | 170 let context = new OfflineAudioContext(2, renderFrames, sampleRate); |
170 var src = new OscillatorNode(context, { | 171 let src = new OscillatorNode(context, { |
171 type: "sawtooth", | 172 type: 'sawtooth', |
172 frequency: 20*440, | 173 frequency: 20 * 440, |
173 }); | 174 }); |
174 | 175 |
175 // Set panner options. Use a non-default rolloffFactor so that the | 176 // Set panner options. Use a non-default rolloffFactor so that the |
176 // various distance models look distinctly different. | 177 // various distance models look distinctly different. |
177 var pannerOptions = {}; | 178 let pannerOptions = {}; |
178 Object.assign(pannerOptions, options, {rolloffFactor: 0.5}); | 179 Object.assign(pannerOptions, options, {rolloffFactor: 0.5}); |
179 | 180 |
180 var pannerRef = new PannerNode(context, pannerOptions); | 181 let pannerRef = new PannerNode(context, pannerOptions); |
181 var pannerTest = new PannerNode(context, pannerOptions); | 182 let pannerTest = new PannerNode(context, pannerOptions); |
182 | 183 |
183 // Split the panner output so we can grab just one of the output | 184 // Split the panner output so we can grab just one of the output |
184 // channels. | 185 // channels. |
185 var splitRef = new ChannelSplitterNode(context, {numberOfOutputs: 2}); | 186 let splitRef = new ChannelSplitterNode(context, {numberOfOutputs: 2}); |
186 var splitTest = new ChannelSplitterNode(context, {numberOfOutputs: 2}); | 187 let splitTest = new ChannelSplitterNode(context, {numberOfOutputs: 2}); |
187 | 188 |
188 // Merge the panner outputs back into one stereo stream for the | 189 // Merge the panner outputs back into one stereo stream for the |
189 // destination. | 190 // destination. |
190 var merger = new ChannelMergerNode(context, {numberOfInputs: 2}); | 191 let merger = new ChannelMergerNode(context, {numberOfInputs: 2}); |
191 | 192 |
192 src.connect(pannerTest).connect(splitTest).connect(merger, 0, 0); | 193 src.connect(pannerTest).connect(splitTest).connect(merger, 0, 0); |
193 src.connect(pannerRef).connect(splitRef).connect(merger, 0, 1); | 194 src.connect(pannerRef).connect(splitRef).connect(merger, 0, 1); |
194 | 195 |
195 merger.connect(context.destination); | 196 merger.connect(context.destination); |
196 | 197 |
197 // Move the panner some distance away. Arbitrarily select the x | 198 // Move the panner some distance away. Arbitrarily select the x |
198 // direction. For the reference panner, manually clamp the distance. | 199 // direction. For the reference panner, manually clamp the distance. |
199 // All models clamp the distance to a minimum of refDistance. Only the | 200 // All models clamp the distance to a minimum of refDistance. Only the |
200 // linear model also clamps to a maximum of maxDistance. | 201 // linear model also clamps to a maximum of maxDistance. |
201 var xRef = Math.max(options.distance, pannerRef.refDistance); | 202 let xRef = Math.max(options.distance, pannerRef.refDistance); |
202 | 203 |
203 if (pannerRef.distanceModel === "linear") { | 204 if (pannerRef.distanceModel === 'linear') { |
204 xRef = Math.min(xRef, pannerRef.maxDistance); | 205 xRef = Math.min(xRef, pannerRef.maxDistance); |
205 } | 206 } |
206 | 207 |
207 var xTest = options.distance; | 208 let xTest = options.distance; |
208 | 209 |
209 pannerRef.positionZ.setValueAtTime(xRef, 0); | 210 pannerRef.positionZ.setValueAtTime(xRef, 0); |
210 pannerTest.positionZ.setValueAtTime(xTest, 0); | 211 pannerTest.positionZ.setValueAtTime(xTest, 0); |
211 | 212 |
212 src.start(); | 213 src.start(); |
213 | 214 |
214 return context.startRendering().then(function (resultBuffer) { | 215 return context.startRendering().then(function(resultBuffer) { |
215 var actual = resultBuffer.getChannelData(0); | 216 let actual = resultBuffer.getChannelData(0); |
216 var expected = resultBuffer.getChannelData(1); | 217 let expected = resultBuffer.getChannelData(1); |
217 | 218 |
218 should(xTest < pannerRef.refDistance || xTest > pannerRef.maxDistance, | 219 should( |
219 "Model: " + options.distanceModel + ": Distance (" + xTest + | 220 xTest < pannerRef.refDistance || xTest > pannerRef.maxDistance, |
220 ") is outside the range [" + pannerRef.refDistance + ", " + | 221 'Model: ' + options.distanceModel + ': Distance (' + xTest + |
221 pannerRef.maxDistance + "]") | 222 ') is outside the range [' + pannerRef.refDistance + ', ' + |
222 .beEqualTo(true); | 223 pannerRef.maxDistance + ']') |
223 should(actual, "Test panner output " + JSON.stringify(options)) | 224 .beEqualTo(true); |
224 .beEqualToArray(expected); | 225 should(actual, 'Test panner output ' + JSON.stringify(options)) |
| 226 .beEqualToArray(expected); |
225 }); | 227 }); |
226 } | 228 } |
227 | 229 |
228 audit.run(); | 230 audit.run(); |
229 </script> | 231 </script> |
230 </body> | 232 </body> |
231 </html> | 233 </html> |
OLD | NEW |