| OLD | NEW |
| (Empty) |
| 1 <!doctype html> | |
| 2 <html> | |
| 3 <head> | |
| 4 <title>Test setTargetAtTime Approach to Limit</title> | |
| 5 <script src="../resources/js-test.js"></script> | |
| 6 <script src="resources/compatibility.js"></script> | |
| 7 <script src="resources/audit-util.js"></script> | |
| 8 <script src="resources/audio-testing.js"></script> | |
| 9 <script src="resources/audioparam-testing.js"></script> | |
| 10 </head> | |
| 11 | |
| 12 <body> | |
| 13 <script> | |
| 14 description("Test setTargetAtTime Approach to Limit"); | |
| 15 window.jsTestIsAsync = true; | |
| 16 | |
| 17 var audit = Audit.createTaskRunner(); | |
| 18 | |
| 19 audit.defineTask("approach 1", function(done) { | |
| 20 var sampleRate = 48000; | |
| 21 | |
| 22 // A really short time constant so that setTargetAtTime approaches the l
imiting value well | |
| 23 // before the end of the test. | |
| 24 var timeConstant = 0.001; | |
| 25 | |
| 26 // Find the time where setTargetAtTime is close enough to the limit. Si
nce we're | |
| 27 // approaching 1, use a value of eps smaller than kSetTargetThreshold (5
e-7) in | |
| 28 // AudioParamTimeline.cpp. This is to account for round-off in the actu
al implementation | |
| 29 // (which uses a filter and not the formula.) | |
| 30 var limitThreshold = 1e-7; | |
| 31 | |
| 32 runTest({ | |
| 33 sampleRate: sampleRate, | |
| 34 v0: 0, | |
| 35 v1: 1, | |
| 36 timeConstant: timeConstant, | |
| 37 eps: limitThreshold, | |
| 38 // Experimentally determined | |
| 39 threshold: 2.4e-5 | |
| 40 }).then(done); | |
| 41 }) | |
| 42 | |
| 43 audit.defineTask("approach 0", function(done) { | |
| 44 // Use the equation for setTargetAtTime to figure out when we are close
to 0: | |
| 45 // | |
| 46 // v(t) = exp(-t/tau) | |
| 47 // | |
| 48 // So find t such that exp(-t/tau) <= eps. Thus t >= - tau * log(eps). | |
| 49 // | |
| 50 // For eps, use 1e-20 (kSetTargetZeroThreshold in AudioParamTimeline.cpp
). | |
| 51 | |
| 52 var sampleRate = 48000; | |
| 53 | |
| 54 // A really short time constant so that setTargetAtTime approaches the l
imiting value well | |
| 55 // before the end of the test. | |
| 56 var timeConstant = 0.001; | |
| 57 | |
| 58 // Find the time where setTargetAtTime is close enough to the limit. Si
nce we're | |
| 59 // approaching 0, use a value of eps smaller than kSetTargetZeroThreshol
d (1e-20) in | |
| 60 // AudioParamTimeline.cpp. This is to account for round-off in the actu
al implementation | |
| 61 // (which uses a filter and not the formula.) | |
| 62 var limitThreshold = 1e-21; | |
| 63 | |
| 64 runTest({ | |
| 65 sampleRate: sampleRate, | |
| 66 v0: 1, | |
| 67 v1: 0, | |
| 68 timeConstant: timeConstant, | |
| 69 eps: limitThreshold, | |
| 70 // Experimentally determined | |
| 71 threshold: 1.3e-7 | |
| 72 }).then(done); | |
| 73 }); | |
| 74 | |
| 75 function findLimitTime(v0, v1, timeConstant, eps) { | |
| 76 // Find the time at which the setTargetAtTime is close enough to the tar
get value |v1| where | |
| 77 // we can consider the curve to have reached its limiting value. | |
| 78 // | |
| 79 // If v1 = 0, |eps| is the absolute error between the actual value and | |
| 80 // |v1|. Otherwise, |eps| is the relative error between the actual valu
e and |v1|. | |
| 81 // | |
| 82 // The curve is | |
| 83 // | |
| 84 // v(t) = v1 - (v1 - v0) * exp(-t/timeConstant) | |
| 85 // | |
| 86 // If v1 = 0, | |
| 87 // | |
| 88 // v(t) = v0 * exp(-t/timeConstant) | |
| 89 // | |
| 90 // Solve this for when |v(t)| <= eps: | |
| 91 // | |
| 92 // t >= timeConstant * log(v0/eps) | |
| 93 // | |
| 94 // For v1 not zero, we want |v(t) - v1|/|v1| <= eps: | |
| 95 // | |
| 96 // t >= timeConstant * log(abs(v1-v0)/eps/v1) | |
| 97 | |
| 98 if (v1) | |
| 99 return timeConstant * Math.log(Math.abs(v1-v0)/eps/v1); | |
| 100 else | |
| 101 return timeConstant * Math.log(v0/eps); | |
| 102 } | |
| 103 | |
| 104 function runTest(options) { | |
| 105 var renderLength = 1; | |
| 106 | |
| 107 var context = new OfflineAudioContext(1, renderLength * sampleRate, opti
ons.sampleRate); | |
| 108 | |
| 109 // A constant source | |
| 110 var source = context.createBufferSource(); | |
| 111 source.buffer = createConstantBuffer(context, 1, 1); | |
| 112 source.loop = true; | |
| 113 | |
| 114 var gain = context.createGain(); | |
| 115 gain.gain.setValueAtTime(options.v0, 0); | |
| 116 gain.gain.setTargetAtTime(options.v1, 0, options.timeConstant); | |
| 117 | |
| 118 source.connect(gain); | |
| 119 gain.connect(context.destination); | |
| 120 | |
| 121 source.start(); | |
| 122 | |
| 123 return context.startRendering().then(function (resultBuffer) { | |
| 124 var actual = resultBuffer.getChannelData(0); | |
| 125 var expected = createExponentialApproachArray(0, renderLength, | |
| 126 options.v0, options.v1, | |
| 127 options.sampleRate, options.timeConstant); | |
| 128 | |
| 129 var message = "setTargetAtTime(" + options.v1 + ", 0, " + options.time
Constant + ")"; | |
| 130 | |
| 131 // Determine where the tail of the curve begins. (Where the curve has
basically reached | |
| 132 // the limit value.) | |
| 133 var tailTime = findLimitTime(options.v0, options.v1, options.timeConst
ant, options.eps); | |
| 134 var tailFrame = Math.ceil(tailTime * options.sampleRate); | |
| 135 | |
| 136 var success = true; | |
| 137 success = Should("Initial output of " + tailFrame + " samples for " +
message, | |
| 138 actual.slice(0, tailFrame), { numberOfArrayLog: 8 }) | |
| 139 .beCloseToArray(expected.slice(0, tailFrame), options.threshold) &&
success; | |
| 140 | |
| 141 success = Should("Tail output for " + message, | |
| 142 actual.slice(tailFrame)) | |
| 143 .containValues([options.v1]) && success; | |
| 144 | |
| 145 if (success) | |
| 146 testPassed(message + " had the expected values.\n"); | |
| 147 else | |
| 148 testFailed(message + " did not have the expected values.\n"); | |
| 149 }); | |
| 150 } | |
| 151 | |
| 152 audit.defineTask("finish", function (done) { | |
| 153 finishJSTest(); | |
| 154 done(); | |
| 155 }); | |
| 156 | |
| 157 audit.runTasks(); | |
| 158 </script> | |
| 159 </body> | |
| 160 </html> | |
| OLD | NEW |