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