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