| 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>Test Clamping of Distance for PannerNode</title> |
| 5 <script src="../../resources/testharness.js"></script> | 5 <script src="../../resources/testharness.js"></script> |
| 6 <script src="../../resources/testharnessreport.js"></script> | 6 <script src="../../resources/testharnessreport.js"></script> |
| 7 <script src="../resources/audit-util.js"></script> | 7 <script src="../resources/audit-util.js"></script> |
| 8 <script src="../resources/audio-testing.js"></script> | 8 <script src="../resources/audit.js"></script> |
| 9 </head> | 9 </head> |
| 10 | 10 |
| 11 <body> | 11 <body> |
| 12 <script> | 12 <script> |
| 13 // Arbitrary sample rate and render length. | 13 // Arbitrary sample rate and render length. |
| 14 var sampleRate = 48000; | 14 var sampleRate = 48000; |
| 15 var renderFrames = 128; | 15 var renderFrames = 128; |
| 16 | 16 |
| 17 var audit = Audit.createTaskRunner(); | 17 var audit = Audit.createTaskRunner(); |
| 18 | 18 |
| 19 audit.defineTask("ref-distance-error", function (taskDone) { | 19 audit.define("ref-distance-error", (task, should) => { |
| 20 testDistanceLimits({name: "refDistance", isZeroAllowed: true}); | 20 testDistanceLimits(should, {name: "refDistance", isZeroAllowed: true}); |
| 21 taskDone(); | 21 task.done(); |
| 22 }); | 22 }); |
| 23 | 23 |
| 24 audit.defineTask("max-distance-error", function (taskDone) { | 24 audit.define("max-distance-error", (task, should) => { |
| 25 testDistanceLimits({name: "maxDistance", isZeroAllowed: false}); | 25 testDistanceLimits(should, {name: "maxDistance", isZeroAllowed: false}); |
| 26 taskDone(); | 26 task.done(); |
| 27 }); | 27 }); |
| 28 | 28 |
| 29 function testDistanceLimits(options) { | 29 function testDistanceLimits(should, options) { |
| 30 // Verify that exceptions are thrown for invalid values of refDistance. | 30 // Verify that exceptions are thrown for invalid values of refDistance. |
| 31 var context = new OfflineAudioContext(1, renderFrames, sampleRate); | 31 var context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| 32 | 32 |
| 33 var attrName = options.name; | 33 var attrName = options.name; |
| 34 var prefix = "new PannerNode(c, {" + attrName + ": "; | 34 var prefix = "new PannerNode(c, {" + attrName + ": "; |
| 35 | 35 |
| 36 success = Should(prefix + "-1})", function () { | 36 should(function () { |
| 37 var nodeOptions = {}; | 37 var nodeOptions = {}; |
| 38 nodeOptions[attrName] = -1; | 38 nodeOptions[attrName] = -1; |
| 39 new PannerNode(context, nodeOptions); | 39 new PannerNode(context, nodeOptions); |
| 40 }).throw("RangeError"); | 40 }, prefix + "-1})").throw("RangeError"); |
| 41 | 41 |
| 42 if (options.isZeroAllowed) { | 42 if (options.isZeroAllowed) { |
| 43 success = Should(prefix + "0})", function () { | 43 should(function () { |
| 44 var nodeOptions = {}; | 44 var nodeOptions = {}; |
| 45 nodeOptions[attrName] = 0; | 45 nodeOptions[attrName] = 0; |
| 46 new PannerNode(context, nodeOptions); | 46 new PannerNode(context, nodeOptions); |
| 47 }).notThrow() && success; | 47 }, prefix + "0})").notThrow(); |
| 48 } else { | 48 } else { |
| 49 success = Should(prefix + "0})", function () { | 49 should(function () { |
| 50 var nodeOptions = {}; | 50 var nodeOptions = {}; |
| 51 nodeOptions[attrName] = 0; | 51 nodeOptions[attrName] = 0; |
| 52 new PannerNode(context, nodeOptions); | 52 new PannerNode(context, nodeOptions); |
| 53 }).throw("RangeError") && success; | 53 }, prefix + "0})").throw("RangeError"); |
| 54 } | 54 } |
| 55 | 55 |
| 56 // The smallest representable positive single float. | 56 // The smallest representable positive single float. |
| 57 var leastPositiveDoubleFloat = 4.9406564584124654e-324; | 57 var leastPositiveDoubleFloat = 4.9406564584124654e-324; |
| 58 | 58 |
| 59 success = Should(prefix + leastPositiveDoubleFloat + "})", | 59 should( |
| 60 function () { | 60 function () { |
| 61 var nodeOptions = {}; | 61 var nodeOptions = {}; |
| 62 nodeOptions[attrName] = leastPositiveDoubleFloat; | 62 nodeOptions[attrName] = leastPositiveDoubleFloat; |
| 63 new PannerNode(context, nodeOptions); | 63 new PannerNode(context, nodeOptions); |
| 64 }).notThrow() && success; | 64 }, prefix + leastPositiveDoubleFloat + "})") |
| 65 .notThrow(); |
| 65 | 66 |
| 66 prefix = "panner." + attrName + " = "; | 67 prefix = "panner." + attrName + " = "; |
| 67 panner = new PannerNode(context); | 68 panner = new PannerNode(context); |
| 68 success = Should(prefix + "-1", function () { | 69 should(function () { |
| 69 panner[attrName] = -1; | 70 panner[attrName] = -1; |
| 70 }).throw("RangeError") && success; | 71 }, prefix + "-1").throw("RangeError"); |
| 71 | 72 |
| 72 if (options.isZeroAllowed) { | 73 if (options.isZeroAllowed) { |
| 73 success = Should(prefix + "0", function () { | 74 should(function () { |
| 74 panner[attrName] = 0; | 75 panner[attrName] = 0; |
| 75 }).notThrow() && success; | 76 }, prefix + "0").notThrow(); |
| 76 } else { | 77 } else { |
| 77 success = Should(prefix + "0", function () { | 78 should(function () { |
| 78 panner[attrName] = 0; | 79 panner[attrName] = 0; |
| 79 }).throw("RangeError") && success; | 80 }, prefix + "0").throw("RangeError"); |
| 80 } | 81 } |
| 81 | 82 |
| 82 success = Should(prefix + leastPositiveDoubleFloat, function () { | 83 should(function () { |
| 83 panner[attrName] = leastPositiveDoubleFloat; | 84 panner[attrName] = leastPositiveDoubleFloat; |
| 84 }).notThrow() && success; | 85 }, prefix + leastPositiveDoubleFloat).notThrow(); |
| 85 | |
| 86 Should("Invalid " + attrName + " values handled", success) | |
| 87 .summarize("correctly", "incorrectly"); | |
| 88 | |
| 89 } | 86 } |
| 90 | 87 |
| 91 audit.defineTask("min-distance", function (taskDone) { | 88 audit.define("min-distance", (task, should) => { |
| 92 // Test clamping of panner distance to refDistance for all of the | 89 // Test clamping of panner distance to refDistance for all of the |
| 93 // distance models. The actual distance is arbitrary as long as it's | 90 // distance models. The actual distance is arbitrary as long as it's |
| 94 // less than refDistance. We test default and non-default values for | 91 // less than refDistance. We test default and non-default values for |
| 95 // the panner's refDistance and maxDistance. | 92 // the panner's refDistance and maxDistance. |
| 96 // correctly. | 93 // correctly. |
| 97 Promise.all([ | 94 Promise.all([ |
| 98 runTest({ | 95 runTest(should, { |
| 99 distance: 0.01, | 96 distance: 0.01, |
| 100 distanceModel: "linear", | 97 distanceModel: "linear", |
| 101 }), | 98 }), |
| 102 runTest({ | 99 runTest(should, { |
| 103 distance: 0.01, | 100 distance: 0.01, |
| 104 distanceModel: "exponential", | 101 distanceModel: "exponential", |
| 105 }), | 102 }), |
| 106 runTest({ | 103 runTest(should, { |
| 107 distance: 0.01, | 104 distance: 0.01, |
| 108 distanceModel: "inverse", | 105 distanceModel: "inverse", |
| 109 }), | 106 }), |
| 110 runTest({ | 107 runTest(should, { |
| 111 distance: 2, | 108 distance: 2, |
| 112 distanceModel: "linear", | 109 distanceModel: "linear", |
| 113 maxDistance: 1000, | 110 maxDistance: 1000, |
| 114 refDistance: 10, | 111 refDistance: 10, |
| 115 }), | 112 }), |
| 116 runTest({ | 113 runTest(should, { |
| 117 distance: 2, | 114 distance: 2, |
| 118 distanceModel: "exponential", | 115 distanceModel: "exponential", |
| 119 maxDistance: 1000, | 116 maxDistance: 1000, |
| 120 refDistance: 10, | 117 refDistance: 10, |
| 121 }), | 118 }), |
| 122 runTest({ | 119 runTest(should, { |
| 123 distance: 2, | 120 distance: 2, |
| 124 distanceModel: "inverse", | 121 distanceModel: "inverse", |
| 125 maxDistance: 1000, | 122 maxDistance: 1000, |
| 126 refDistance: 10, | 123 refDistance: 10, |
| 127 }), | 124 }), |
| 128 ]).then(taskDone); | 125 ]) |
| 126 .then(() => task.done()); |
| 129 }); | 127 }); |
| 130 | 128 |
| 131 audit.defineTask("max-distance", function (taskDone) { | 129 audit.define("max-distance", (task, should) => { |
| 132 // Like the "min-distance" task, but for clamping to the max | 130 // Like the "min-distance" task, but for clamping to the max |
| 133 // 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 |
| 134 // greater than maxDistance. | 132 // greater than maxDistance. |
| 135 Promise.all([ | 133 Promise.all([ |
| 136 runTest({ | 134 runTest(should, { |
| 137 distance: 20000, | 135 distance: 20000, |
| 138 distanceModel: "linear", | 136 distanceModel: "linear", |
| 139 }), | 137 }), |
| 140 runTest({ | 138 runTest(should, { |
| 141 distance: 21000, | 139 distance: 21000, |
| 142 distanceModel: "exponential", | 140 distanceModel: "exponential", |
| 143 }), | 141 }), |
| 144 runTest({ | 142 runTest(should, { |
| 145 distance: 23000, | 143 distance: 23000, |
| 146 distanceModel: "inverse", | 144 distanceModel: "inverse", |
| 147 }), | 145 }), |
| 148 runTest({ | 146 runTest(should, { |
| 149 distance: 5000, | 147 distance: 5000, |
| 150 distanceModel: "linear", | 148 distanceModel: "linear", |
| 151 maxDistance: 1000, | 149 maxDistance: 1000, |
| 152 refDistance: 10, | 150 refDistance: 10, |
| 153 }), | 151 }), |
| 154 runTest({ | 152 runTest(should, { |
| 155 distance: 5000, | 153 distance: 5000, |
| 156 distanceModel: "exponential", | 154 distanceModel: "exponential", |
| 157 maxDistance: 1000, | 155 maxDistance: 1000, |
| 158 refDistance: 10, | 156 refDistance: 10, |
| 159 }), | 157 }), |
| 160 runTest({ | 158 runTest(should, { |
| 161 distance: 5000, | 159 distance: 5000, |
| 162 distanceModel: "inverse", | 160 distanceModel: "inverse", |
| 163 maxDistance: 1000, | 161 maxDistance: 1000, |
| 164 refDistance: 10, | 162 refDistance: 10, |
| 165 }), | 163 }), |
| 166 ]).then(taskDone); | 164 ]) |
| 165 .then(() => task.done()); |
| 167 }); | 166 }); |
| 168 | 167 |
| 169 function runTest(options) { | 168 function runTest(should, options) { |
| 170 var context = new OfflineAudioContext(2, renderFrames, sampleRate); | 169 var context = new OfflineAudioContext(2, renderFrames, sampleRate); |
| 171 var src = new OscillatorNode(context, { | 170 var src = new OscillatorNode(context, { |
| 172 type: "sawtooth", | 171 type: "sawtooth", |
| 173 frequency: 20*440, | 172 frequency: 20*440, |
| 174 }); | 173 }); |
| 175 | 174 |
| 176 // Set panner options. Use a non-default rolloffFactor so that the | 175 // Set panner options. Use a non-default rolloffFactor so that the |
| 177 // various distance models look distinctly different. | 176 // various distance models look distinctly different. |
| 178 var pannerOptions = {}; | 177 var pannerOptions = {}; |
| 179 Object.assign(pannerOptions, options, {rolloffFactor: 0.5}); | 178 Object.assign(pannerOptions, options, {rolloffFactor: 0.5}); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 205 | 204 |
| 206 pannerRef.positionZ.setValueAtTime(xRef, 0); | 205 pannerRef.positionZ.setValueAtTime(xRef, 0); |
| 207 pannerTest.positionZ.setValueAtTime(xTest, 0); | 206 pannerTest.positionZ.setValueAtTime(xTest, 0); |
| 208 | 207 |
| 209 src.start(); | 208 src.start(); |
| 210 | 209 |
| 211 return context.startRendering().then(function (resultBuffer) { | 210 return context.startRendering().then(function (resultBuffer) { |
| 212 var actual = resultBuffer.getChannelData(0); | 211 var actual = resultBuffer.getChannelData(0); |
| 213 var expected = resultBuffer.getChannelData(1); | 212 var expected = resultBuffer.getChannelData(1); |
| 214 | 213 |
| 215 Should("Model: " + options.distanceModel + ": Distance (" + xTest + ")
is outside the range [" + | 214 should(xTest < pannerRef.refDistance || xTest > pannerRef.maxDistance, |
| 216 pannerRef.refDistance + ", " + pannerRef.maxDistance + "]", | 215 "Model: " + options.distanceModel + ": Distance (" + xTest + |
| 217 xTest < pannerRef.refDistance || xTest > pannerRef.maxDistance) | 216 ") is outside the range [" + pannerRef.refDistance + ", " + |
| 217 pannerRef.maxDistance + "]") |
| 218 .beEqualTo(true); | 218 .beEqualTo(true); |
| 219 Should("Test panner output " + JSON.stringify(options), actual) | 219 should(actual, "Test panner output " + JSON.stringify(options)) |
| 220 .beEqualToArray(expected); | 220 .beEqualToArray(expected); |
| 221 }); | 221 }); |
| 222 } | 222 } |
| 223 | 223 |
| 224 audit.runTasks(); | 224 audit.run(); |
| 225 </script> | 225 </script> |
| 226 </body> | 226 </body> |
| 227 </html> | 227 </html> |
| OLD | NEW |