| OLD | NEW |
| (Empty) | |
| 1 <!doctype html> |
| 2 <html> |
| 3 <head> |
| 4 <script src="../resources/js-test.js"></script> |
| 5 <script src="resources/compatibility.js"></script> |
| 6 <script src="resources/audio-testing.js"></script> |
| 7 <script src="resources/panner-formulas.js"></script> |
| 8 <title>Test Basic PannerNode with Automation Position Properties</title> |
| 9 </head> |
| 10 |
| 11 <body> |
| 12 <script> |
| 13 description("Test Basic PannerNode with Automation Position Properties."); |
| 14 window.jsTestIsAsync = true; |
| 15 |
| 16 var sampleRate = 48000; |
| 17 |
| 18 // These tests are quite slow, so don't run for many frames. 256 frames s
hould be enough to |
| 19 // demonstrate that automations are working. |
| 20 var renderFrames = 256; |
| 21 var renderDuration = renderFrames / sampleRate; |
| 22 |
| 23 var audit = Audit.createTaskRunner(); |
| 24 |
| 25 // Array of tests for setting the panner positions. These tests basically
verify that the |
| 26 // position setters for the panner and listener are working correctly. |
| 27 var testConfig = [{ |
| 28 setter: "positionX", |
| 29 }, { |
| 30 setter: "positionY", |
| 31 }, { |
| 32 setter: "positionZ", |
| 33 }]; |
| 34 |
| 35 // Create tests for the panner position setters. Both mono and steroe sou
rces are tested. |
| 36 for (var k = 0; k < testConfig.length; ++k) { |
| 37 var config = testConfig[k]; |
| 38 // Function to create the test to define the test. |
| 39 var tester = function (config, channelCount) { |
| 40 return function (done) { |
| 41 var nodes = createGraph(channelCount); |
| 42 var {context, source, panner} = nodes; |
| 43 |
| 44 var message = channelCount == 1 ? "Mono" : "Stereo"; |
| 45 message += " panner." + config.setter; |
| 46 |
| 47 testPositionSetter({ |
| 48 nodes: nodes, |
| 49 pannerSetter: panner[config.setter], |
| 50 message: message |
| 51 }).then(done); |
| 52 } |
| 53 } |
| 54 |
| 55 audit.defineTask("Stereo panner." + config.setter, tester(config, 2)); |
| 56 audit.defineTask("Mono panner." + config.setter, tester(config, 1)); |
| 57 } |
| 58 |
| 59 // Create tests for the listener position setters. Both mono and steroe s
ources are tested. |
| 60 for (var k = 0; k < testConfig.length; ++k) { |
| 61 var config = testConfig[k]; |
| 62 // Function to create the test to define the test. |
| 63 var tester = function (config, channelCount) { |
| 64 return function (done) { |
| 65 var nodes = createGraph(channelCount); |
| 66 var {context, source, panner} = nodes; |
| 67 |
| 68 var message = channelCount == 1 ? "Mono" : "Stereo"; |
| 69 message += " listener." + config.setter; |
| 70 |
| 71 // Some relatively arbitrary (non-default) position for the source l
ocation. |
| 72 panner.setPosition(1,0,1); |
| 73 |
| 74 testPositionSetter({ |
| 75 nodes: nodes, |
| 76 pannerSetter: context.listener[config.setter], |
| 77 message: message |
| 78 }).then(done); |
| 79 } |
| 80 } |
| 81 |
| 82 audit.defineTask("Stereo listener." + config.setter, tester(config, 2)); |
| 83 audit.defineTask("Mono listener." + config.setter, tester(config, 1)); |
| 84 } |
| 85 |
| 86 // Test setPosition method. |
| 87 audit.defineTask("setPosition", function (done) { |
| 88 var {context, panner, source} = createGraph(2); |
| 89 |
| 90 // Initialize source position (values don't really matter). |
| 91 panner.setPosition(1,1,1); |
| 92 |
| 93 // After some (unimportant) time, move the panner to a (any) new locatio
n. |
| 94 var suspendFrame = 128; |
| 95 context.suspend(suspendFrame / sampleRate).then(function () { |
| 96 panner.setPosition(-100, 2000, 8000); |
| 97 }).then(context.resume.bind(context)); |
| 98 |
| 99 context.startRendering().then(function (resultBuffer) { |
| 100 verifyPannerOutputChanged(resultBuffer, {message: "setPosition", suspe
ndFrame: suspendFrame}); |
| 101 }).then(done); |
| 102 }); |
| 103 |
| 104 audit.defineTask("orientation setter", function (done) { |
| 105 var {context, panner, source} = createGraph(2); |
| 106 |
| 107 // For orientation to matter, we need to make the source directional, an
d also move away |
| 108 // from the listener (because the default location is 0,0,0). |
| 109 panner.setPosition(0,0,1); |
| 110 panner.coneInnerAngle = 0; |
| 111 panner.coneOuterAngle = 360; |
| 112 panner.coneOuterGain = .001; |
| 113 |
| 114 // After some (unimportant) time, change the panner orientation to a new
orientation. The |
| 115 // only constraint is that the orientation changes from before. |
| 116 var suspendFrame = 128; |
| 117 context.suspend(suspendFrame / sampleRate).then(function () { |
| 118 panner.orientationX.value = -100; |
| 119 panner.orientationY.value = 2000; |
| 120 panner.orientationZ.value = 8000; |
| 121 }).then(context.resume.bind(context)); |
| 122 |
| 123 context.startRendering().then(function (resultBuffer) { |
| 124 verifyPannerOutputChanged(resultBuffer, {message: "panner.orientation{
XYZ}", suspendFrame: suspendFrame}); |
| 125 }).then(done); |
| 126 }); |
| 127 |
| 128 audit.defineTask("forward setter", function (done) { |
| 129 var {context, panner, source} = createGraph(2); |
| 130 |
| 131 // For orientation to matter, we need to make the source directional, an
d also move away |
| 132 // from the listener (because the default location is 0,0,0). |
| 133 panner.setPosition(0,0,1); |
| 134 panner.coneInnerAngle = 0; |
| 135 panner.coneOuterAngle = 360; |
| 136 panner.coneOuterGain = .001; |
| 137 |
| 138 // After some (unimportant) time, change the panner orientation to a new
orientation. The |
| 139 // only constraint is that the orientation changes from before. |
| 140 var suspendFrame = 128; |
| 141 context.suspend(suspendFrame / sampleRate).then(function () { |
| 142 context.listener.forwardX.value = -100; |
| 143 context.listener.forwardY.value = 2000; |
| 144 context.listener.forwardZ.value = 8000; |
| 145 }).then(context.resume.bind(context)); |
| 146 |
| 147 context.startRendering().then(function (resultBuffer) { |
| 148 verifyPannerOutputChanged(resultBuffer, {message: "listener.forward{XY
Z}", suspendFrame: suspendFrame}); |
| 149 }).then(done); |
| 150 }); |
| 151 |
| 152 audit.defineTask("up setter", function (done) { |
| 153 var {context, panner, source} = createGraph(2); |
| 154 |
| 155 // For orientation to matter, we need to make the source directional, an
d also move away |
| 156 // from the listener (because the default location is 0,0,0). |
| 157 panner.setPosition(0,0,1); |
| 158 panner.coneInnerAngle = 0; |
| 159 panner.coneOuterAngle = 360; |
| 160 panner.coneOuterGain = .001; |
| 161 panner.setPosition(1,0,1); |
| 162 |
| 163 // After some (unimportant) time, change the panner orientation to a new
orientation. The |
| 164 // only constraint is that the orientation changes from before. |
| 165 var suspendFrame = 128; |
| 166 context.suspend(suspendFrame / sampleRate).then(function () { |
| 167 context.listener.upX.value = 100; |
| 168 context.listener.upY.value = 100; |
| 169 context.listener.upZ.value = 100;; |
| 170 }).then(context.resume.bind(context)); |
| 171 |
| 172 context.startRendering().then(function (resultBuffer) { |
| 173 verifyPannerOutputChanged(resultBuffer, {message: "listener.up{XYZ}",
suspendFrame: suspendFrame}); |
| 174 }).then(done); |
| 175 }); |
| 176 |
| 177 audit.defineTask("finish", function (done) { |
| 178 finishJSTest(); |
| 179 done(); |
| 180 }); |
| 181 |
| 182 audit.runTasks(); |
| 183 |
| 184 function createGraph(channelCount) { |
| 185 var context = new OfflineAudioContext(2, renderFrames, sampleRate); |
| 186 var panner = context.createPanner(); |
| 187 var source = context.createBufferSource(); |
| 188 source.buffer = createConstantBuffer(context, 1, channelCount == 1 ? 1 :
[1, 2]); |
| 189 source.loop = true; |
| 190 |
| 191 source.connect(panner); |
| 192 panner.connect(context.destination); |
| 193 |
| 194 source.start(); |
| 195 return { |
| 196 context: context, |
| 197 source: source, |
| 198 panner: panner |
| 199 }; |
| 200 } |
| 201 |
| 202 function testPositionSetter(options) { |
| 203 var {nodes, pannerSetter, message} = options; |
| 204 |
| 205 var {context, source, panner} = nodes; |
| 206 |
| 207 // Set panner x position. (Value doesn't matter); |
| 208 pannerSetter.value = 1; |
| 209 |
| 210 // Wait a bit and set a new position. (Actual time and position doesn't
matter). |
| 211 var suspendFrame = 128; |
| 212 context.suspend(suspendFrame / sampleRate).then(function () { |
| 213 pannerSetter.value = 10000; |
| 214 }).then(context.resume.bind(context)); |
| 215 |
| 216 return context.startRendering().then(function (resultBuffer) { |
| 217 verifyPannerOutputChanged(resultBuffer, {message: message, suspendFram
e: suspendFrame}); |
| 218 }); |
| 219 } |
| 220 |
| 221 function verifyPannerOutputChanged(resultBuffer, options) { |
| 222 var {message, suspendFrame} = options; |
| 223 // Verify that the first part of output is constant. (Doesn't matter w
hat.) |
| 224 var success = true; |
| 225 var data0 = resultBuffer.getChannelData(0); |
| 226 var data1 = resultBuffer.getChannelData(1); |
| 227 |
| 228 var middle = "[0, " + suspendFrame + ") "; |
| 229 success = Should(message + ".value frame " + middle + "channel 0", dat
a0.slice(0, suspendFrame)) |
| 230 .beConstantValueOf(data0[0]) && success; |
| 231 success = Should(message + ".value frame " + middle + "channel 1", dat
a1.slice(0, suspendFrame)) |
| 232 .beConstantValueOf(data1[0]) && success; |
| 233 |
| 234 // The rest after suspendTime should be constant and different from th
e first part. |
| 235 middle = "[" + suspendFrame + ", " + renderFrames + ") "; |
| 236 success = Should(message + ".value frame " + middle + "channel 0", |
| 237 data0.slice(suspendFrame)) |
| 238 .beConstantValueOf(data0[suspendFrame]) && success; |
| 239 success = Should(message + ".value frame " + middle + "channel 0", |
| 240 data1.slice(suspendFrame)) |
| 241 .beConstantValueOf(data1[suspendFrame]) && success; |
| 242 success = Should("Output at frame " + suspendFrame + " channel 0", dat
a0[suspendFrame]) |
| 243 .notBeEqualTo(data0[0]) && success; |
| 244 success = Should("Output at frame " + suspendFrame + " channel 1", dat
a1[suspendFrame]) |
| 245 .notBeEqualTo(data1[0]) && success; |
| 246 |
| 247 var prefix = "Directly setting " + message + ".value"; |
| 248 if (success) |
| 249 testPassed(prefix + " worked.\n"); |
| 250 else |
| 251 testFailed(prefix + " failed.\n"); |
| 252 } |
| 253 </script> |
| 254 </body> |
| 255 </html> |
| OLD | NEW |