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