| OLD | NEW |
| 1 <!doctype html> | 1 <!doctype html> |
| 2 <html> | 2 <html> |
| 3 <head> | 3 <head> |
| 4 <script src="../../resources/testharness.js"></script> | 4 <script src="../../resources/testharness.js"></script> |
| 5 <script src="../../resources/testharnessreport.js"></script> | 5 <script src="../../resources/testharnessreport.js"></script> |
| 6 <script src="../resources/audit-util.js"></script> | 6 <script src="../resources/audit-util.js"></script> |
| 7 <script src="../resources/audio-testing.js"></script> | 7 <script src="../resources/audit.js"></script> |
| 8 <title>Test Clamping of Automations</title> | 8 <title>Test Clamping of Automations</title> |
| 9 </head> | 9 </head> |
| 10 | 10 |
| 11 <body> | 11 <body> |
| 12 <script> | 12 <script> |
| 13 | 13 |
| 14 // Some arbitrary sample rate for the offline context. | 14 // Some arbitrary sample rate for the offline context. |
| 15 var sampleRate = 48000; | 15 var sampleRate = 48000; |
| 16 | 16 |
| 17 // Duration of test (fairly arbitrary). | 17 // Duration of test (fairly arbitrary). |
| 18 var renderDuration = 1; | 18 var renderDuration = 1; |
| 19 var renderFrames = renderDuration * sampleRate; | 19 var renderFrames = renderDuration * sampleRate; |
| 20 | 20 |
| 21 var audit = Audit.createTaskRunner(); | 21 var audit = Audit.createTaskRunner(); |
| 22 | 22 |
| 23 audit.defineTask("clamp", function (done) { | 23 audit.define("clamp", (task, should) => { |
| 24 // Test clamping of automations. Most AudioParam limits are essentially | 24 // Test clamping of automations. Most AudioParam limits are essentially |
| 25 // unbounded, so clamping doesn't happen. For most other AudioParams, | 25 // unbounded, so clamping doesn't happen. For most other AudioParams, |
| 26 // the behavior is sufficiently complicated with complicated outputs | 26 // the behavior is sufficiently complicated with complicated outputs |
| 27 // that testing them is hard. However the output behavior of the | 27 // that testing them is hard. However the output behavior of the |
| 28 // frequency parameter for a BiquadFilter is relatively simple. Use | 28 // frequency parameter for a BiquadFilter is relatively simple. Use |
| 29 // that as the test. | 29 // that as the test. |
| 30 var context = new OfflineAudioContext(1, renderFrames, sampleRate); | 30 var context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| 31 | 31 |
| 32 var source = context.createBufferSource(); | 32 var source = context.createBufferSource(); |
| 33 source.buffer = createConstantBuffer(context, 1, 1); | 33 source.buffer = createConstantBuffer(context, 1, 1); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 48 filter.frequency.linearRampToValueAtTime(V1, T1); | 48 filter.frequency.linearRampToValueAtTime(V1, T1); |
| 49 | 49 |
| 50 var V2 = 880; | 50 var V2 = 880; |
| 51 var T2 = renderDuration / 2; | 51 var T2 = renderDuration / 2; |
| 52 filter.frequency.linearRampToValueAtTime(V2, T2); | 52 filter.frequency.linearRampToValueAtTime(V2, T2); |
| 53 | 53 |
| 54 source.start(); | 54 source.start(); |
| 55 | 55 |
| 56 context.startRendering().then(function (buffer) { | 56 context.startRendering().then(function (buffer) { |
| 57 var result = buffer.getChannelData(0); | 57 var result = buffer.getChannelData(0); |
| 58 var success = true; | |
| 59 | 58 |
| 60 // When the cutoff frequency of a lowpass filter is 0, nothing gets | 59 // When the cutoff frequency of a lowpass filter is 0, nothing gets |
| 61 // through. Hence the output of the filter between the clamping | 60 // through. Hence the output of the filter between the clamping |
| 62 // period should be exactly zero. This tests passes if the output is 0 | 61 // period should be exactly zero. This tests passes if the output is 0 |
| 63 // during the expected range. | 62 // during the expected range. |
| 64 // | 63 // |
| 65 // Compute when the frequency value of the biquad goes to 0. In | 64 // Compute when the frequency value of the biquad goes to 0. In |
| 66 // general, t = (T0*V1 -T1*V0)/(V1-V0) (using the notation from the | 65 // general, t = (T0*V1 -T1*V0)/(V1-V0) (using the notation from the |
| 67 // spec.) | 66 // spec.) |
| 68 var clampStartTime = solveLinearRamp(0, V0, T0, V1, T1); | 67 var clampStartTime = solveLinearRamp(0, V0, T0, V1, T1); |
| 69 var clampEndTime = solveLinearRamp(0, V1, T1, V2, T2); | 68 var clampEndTime = solveLinearRamp(0, V1, T1, V2, T2); |
| 70 | 69 |
| 71 var clampStartFrame = Math.ceil(clampStartTime * sampleRate); | 70 var clampStartFrame = Math.ceil(clampStartTime * sampleRate); |
| 72 var clampEndFrame = Math.floor(clampEndTime * sampleRate); | 71 var clampEndFrame = Math.floor(clampEndTime * sampleRate); |
| 73 | 72 |
| 74 var clampedSignal = result.slice(clampStartFrame, clampEndFrame + 1); | 73 var clampedSignal = result.slice(clampStartFrame, clampEndFrame + 1); |
| 75 var expectedSignal = new Float32Array(clampedSignal.length); | 74 var expectedSignal = new Float32Array(clampedSignal.length); |
| 76 expectedSignal.fill(0); | 75 expectedSignal.fill(0); |
| 77 | 76 |
| 78 // Output should be zero. | 77 // Output should be zero. |
| 79 success = Should("Clamped signal in frame range [" + clampStartFrame +
", " + | 78 should(clampedSignal, |
| 80 clampEndFrame + "]", | 79 "Clamped signal in frame range [" + clampStartFrame + ", " + |
| 81 clampedSignal, { | 80 clampEndFrame + "]") |
| 82 verbose: true, | 81 .beCloseToArray(expectedSignal, 0); |
| 83 }).beCloseToArray(expectedSignal, 0); | |
| 84 | 82 |
| 85 // Find the actual clamp range based on the output values. | 83 // Find the actual clamp range based on the output values. |
| 86 var actualClampStart = result.findIndex(x => x === 0); | 84 var actualClampStart = result.findIndex(x => x === 0); |
| 87 var actualClampEnd = actualClampStart + result.slice(actualClampStart)
.findIndex( | 85 var actualClampEnd = actualClampStart + result.slice(actualClampStart)
.findIndex( |
| 88 x => x != 0); | 86 x => x != 0); |
| 89 | 87 |
| 90 // Verify that the expected clamping range is a subset of the actual r
ange. | 88 // Verify that the expected clamping range is a subset of the actual r
ange. |
| 91 success = Should("Actual Clamp start", | 89 should(actualClampStart, "Actual Clamp start") |
| 92 actualClampStart).beLessThanOrEqualTo(clampStartFrame) && success; | 90 .beLessThanOrEqualTo(clampStartFrame); |
| 93 success == Should("Actual Clamp end", | 91 should(actualClampEnd, "Actual Clamp end") |
| 94 actualClampEnd).beGreaterThanOrEqualTo(clampEndFrame) && success; | 92 .beGreaterThanOrEqualTo(clampEndFrame); |
| 95 | 93 |
| 96 Should("Clamping of BiquadFilter.frequency automation performed", | 94 }).then(() => task.done()); |
| 97 success) | |
| 98 .summarize("correctly", "incorrectly"); | |
| 99 }).then(done); | |
| 100 }); | 95 }); |
| 101 | 96 |
| 102 // All done! | 97 audit.run(); |
| 103 audit.defineTask("finish", function (done) { | |
| 104 done(); | |
| 105 }); | |
| 106 | |
| 107 audit.runTasks(); | |
| 108 | 98 |
| 109 function solveLinearRamp(v, v0, t0, v1, t1) { | 99 function solveLinearRamp(v, v0, t0, v1, t1) { |
| 110 // Solve the linear ramp equation for the time t at which the ramp | 100 // Solve the linear ramp equation for the time t at which the ramp |
| 111 // reaches the value v. The linear ramp equation (from the spec) is | 101 // reaches the value v. The linear ramp equation (from the spec) is |
| 112 // | 102 // |
| 113 // v(t) = v0 + (v1 - v0) * (t - t0)/(t1 - t0) | 103 // v(t) = v0 + (v1 - v0) * (t - t0)/(t1 - t0) |
| 114 // | 104 // |
| 115 // Find t such that | 105 // Find t such that |
| 116 // | 106 // |
| 117 // v = v0 + (v1 - v0) * (t - t0)/(t1 - t0) | 107 // v = v0 + (v1 - v0) * (t - t0)/(t1 - t0) |
| 118 // | 108 // |
| 119 // Then | 109 // Then |
| 120 // | 110 // |
| 121 // t = (t0 * v1 - t1 * v0 + (t1 - t0) * v) / (v1 - v0) | 111 // t = (t0 * v1 - t1 * v0 + (t1 - t0) * v) / (v1 - v0) |
| 122 // | 112 // |
| 123 return (t0 * v1 - t1 * v0 + (t1 - t0) * v) / (v1 - v0); | 113 return (t0 * v1 - t1 * v0 + (t1 - t0) * v) / (v1 - v0); |
| 124 } | 114 } |
| 125 </script> | 115 </script> |
| 126 </body> | 116 </body> |
| 127 </html> | 117 </html> |
| OLD | NEW |