OLD | NEW |
(Empty) | |
| 1 <!doctype html> |
| 2 <html> |
| 3 <head> |
| 4 <script src="resources/compatibility.js"></script> |
| 5 <script src="resources/audio-testing.js"></script> |
| 6 <script src="resources/audio-param.js"></script> |
| 7 <script src="../resources/js-test.js"></script> |
| 8 <title>Updating of Value Attribute from Timeline</title> |
| 9 </head> |
| 10 |
| 11 <body> |
| 12 <script> |
| 13 description("Test Updating of Value Attribute from Timeline"); |
| 14 window.jsTestIsAsync = true; |
| 15 |
| 16 // This should be a power of two so that all time computations have no rou
nd-off errors. |
| 17 var sampleRate = 32768; |
| 18 var renderQuantumSize = 128; |
| 19 // How many tests to run. |
| 20 var renderLoops = 20; |
| 21 var renderFrames = renderLoops * renderQuantumSize; |
| 22 var renderDuration = renderFrames / sampleRate; |
| 23 |
| 24 var audit = Audit.createTaskRunner(); |
| 25 |
| 26 audit.defineTask("linear", function (done) { |
| 27 // Test the value attribute from a linearRamp event |
| 28 runTest(function (g, v0, t0, v1, t1) { |
| 29 g.gain.linearRampToValueAtTime(v1, t1); |
| 30 return { |
| 31 expectedValue: function (testTime) { |
| 32 return audioParamLinearRamp(testTime, v0, t0, v1, t1); |
| 33 }, |
| 34 message: "linearRamp(" + v1 + ", " + t1 + ")", |
| 35 errorThreshold: 1.1650e-6 |
| 36 }; |
| 37 }).then(done); |
| 38 }); |
| 39 |
| 40 audit.defineTask("exponential", function (done) { |
| 41 // Test the value attribute from an exponentialRamp event |
| 42 runTest(function (g, v0, t0, v1, t1) { |
| 43 g.gain.exponentialRampToValueAtTime(v1, t1); |
| 44 return { |
| 45 expectedValue: function (testTime) { |
| 46 return audioParamExponentialRamp(testTime, v0, t0, v1, t1); |
| 47 }, |
| 48 message: "exponentialRamp(" + v1 + ", " + t1 + ")", |
| 49 errorThreshold: 7.4601e-7 |
| 50 }; |
| 51 }).then(done); |
| 52 }); |
| 53 |
| 54 audit.defineTask("setTarget", function (done) { |
| 55 // Test the value attribute from a setTargetAtTime event |
| 56 runTest(function (g, v0, t0, v1, t1) { |
| 57 var timeConstant = 0.1; |
| 58 var vFinal = 0; |
| 59 g.gain.setTargetAtTime(vFinal, t0, timeConstant); |
| 60 return { |
| 61 expectedValue: function (testTime) { |
| 62 return audioParamSetTarget(testTime, v0, t0, vFinal, timeConstant)
; |
| 63 }, |
| 64 message: "setTargetAtTime(" + vFinal + ", " + t0 + ", " + timeConsta
nt + ")", |
| 65 errorThreshold: 1.2869e-6 |
| 66 }; |
| 67 }).then(done); |
| 68 }); |
| 69 |
| 70 audit.defineTask("setValueCurve", function (done) { |
| 71 // Test the value attribute from a setValueCurve event |
| 72 runTest(function (g, v0, t0, v1, t1) { |
| 73 var curve = [1, 1.5, 4]; |
| 74 var duration = t1 - t0; |
| 75 g.gain.setValueCurveAtTime(Float32Array.from(curve), t0, duration); |
| 76 return { |
| 77 expectedValue: function (testTime) { |
| 78 return audioParamSetValueCurve(testTime, curve, t0, duration); |
| 79 }, |
| 80 message: "setValueCurveAtTime([" + curve + "], " + t0 + ", " + durat
ion + ")", |
| 81 errorThreshold: 7.9577e-8 |
| 82 }; |
| 83 }).then(done); |
| 84 }); |
| 85 |
| 86 audit.defineTask("finish", function (done) { |
| 87 finishJSTest(); |
| 88 done(); |
| 89 }); |
| 90 |
| 91 audit.runTasks(); |
| 92 |
| 93 // Test that the .value getter has the correct value when a timeline is ru
nning. |
| 94 // The |testFunction| is the underlying test to be run. |
| 95 function runTest(testFunction) { |
| 96 // Create a simple graph consisting of a constant source and a gain node
where the |
| 97 // automations are run. A setValueAtTime event starts things off. |
| 98 var context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| 99 var source = context.createBufferSource(); |
| 100 source.buffer = createConstantBuffer(context, 1, 1); |
| 101 source.loop = true; |
| 102 var gain = context.createGain(); |
| 103 |
| 104 source.connect(gain); |
| 105 gain.connect(context.destination); |
| 106 |
| 107 // Start the timeline with setValueAtTime(v0, t0). |
| 108 var v0 = 0.25; |
| 109 var t0 = 0; |
| 110 // End value and time, for those that need it. The end time is less tha
n the rendering |
| 111 // duration so we can test that the final values of the automation (if a
ny) are also |
| 112 // correct. |
| 113 var v1 = 100; |
| 114 var t1 = renderDuration - 5 * renderQuantumSize / sampleRate; |
| 115 |
| 116 gain.gain.setValueAtTime(v0, t0); |
| 117 |
| 118 // Run the desired automation test. The test function returns a diction
ary consisting of |
| 119 // the following properties: |
| 120 // |
| 121 // |message| an informative message about the automation being te
sted. |
| 122 // |errorThreshold| error threshold to determine if the test passes or n
ot. |
| 123 // |expectedValue| a function that compute the expected value at time |
t|. |
| 124 var test = testFunction(gain, v0, t0, v1, t1); |
| 125 |
| 126 // Print an informative message about the test being run. |
| 127 testPassed("Initialize " + test.message + " with setValueAtTime(" + v0 +
", " + t0 + ")."); |
| 128 |
| 129 var success = true; |
| 130 |
| 131 // Max relative error found for this test. This is printed if the test f
ails so that setting |
| 132 // the thresholds is easier. |
| 133 var maxError = 0; |
| 134 |
| 135 // For every rendering quantum (except the first), suspend the context s
o the we can inspect |
| 136 // the value attribute and compare it with the expected value. |
| 137 for (var k = 1; k < renderLoops; ++k) { |
| 138 var time = k * renderQuantumSize / sampleRate; |
| 139 context.suspend(time).then(function () { |
| 140 // The context is supsended at time |time|, which is just before the
rendering quantum |
| 141 // starts. Thus, the value of the attribute is actually 1 frame bef
ore the current |
| 142 // context time. |
| 143 var sampleTime = context.currentTime - 1 / sampleRate; |
| 144 |
| 145 // Compute the max relative error |
| 146 var expected = test.expectedValue(sampleTime); |
| 147 var relError = Math.abs(expected - gain.gain.value) / Math.abs(expec
ted); |
| 148 maxError = Math.max(relError, maxError); |
| 149 |
| 150 success = Should(test.message + " at frame " + (sampleRate * sampleT
ime), |
| 151 gain.gain.value, { |
| 152 precision: 7 |
| 153 }) |
| 154 .beCloseTo(expected, test.errorThreshold || 0) && success; |
| 155 }).then(context.resume.bind(context)); |
| 156 } |
| 157 |
| 158 source.start(); |
| 159 |
| 160 return context.startRendering().then(function (resultBuffer) { |
| 161 // Just print a final pass (or fail) message. |
| 162 if (success) |
| 163 testPassed("Gain .value attribute correctly updated during automatio
n.\n"); |
| 164 else |
| 165 testFailed( |
| 166 "Gain .value attribute not correctly updated during automation; ma
x error = " + |
| 167 maxError + ".\n"); |
| 168 }); |
| 169 } |
| 170 </script> |
| 171 </body> |
| 172 </html> |
OLD | NEW |