diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /testing/web-platform/tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html')
-rw-r--r-- | testing/web-platform/tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html b/testing/web-platform/tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html new file mode 100644 index 0000000000..8668e9d5ac --- /dev/null +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html @@ -0,0 +1,149 @@ +<!DOCTYPE html> +<html> + <head> + <title> + Test Convolver on Real-time Context + </title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/webaudio/resources/audit-util.js"></script> + <script src="/webaudio/resources/audit.js"></script> + <script src="/webaudio/resources/convolution-testing.js"></script> + </head> + <body> + <script id="layout-test-code"> + const audit = Audit.createTaskRunner(); + // Choose a length that is larger enough to cause multiple threads to be + // used in the convolver. For browsers that don't support this, this + // value doesn't matter. + const pulseLength = 16384; + + // The computed SNR should be at least this large. This value depends on + // teh platform and browser. Don't set this value to be to much lower + // than this. It probably indicates a fairly inaccurate convolver or + // constant source node automations that should be fixed instead. + const minRequiredSNR = 77.03; + + // To test the real-time convolver, we convolve two square pulses together + // to produce a triangular pulse. To verify the result is correct we + // compare it against a constant source node configured to generate the + // expected ramp. + audit.define( + {label: 'test', description: 'Test convolver with real-time context'}, + (task, should) => { + // Use a power of two for the sample rate to eliminate round-off in + // computing times from frames. + const context = new AudioContext({sampleRate: 16384}); + + // Square pulse for the convolver impulse response. + const squarePulse = new AudioBuffer( + {length: pulseLength, sampleRate: context.sampleRate}); + squarePulse.getChannelData(0).fill(1); + + const convolver = new ConvolverNode( + context, {buffer: squarePulse, disableNormalization: true}); + + // Square pulse for testing + const srcSquare = new ConstantSourceNode(context, {offset: 0}); + srcSquare.connect(convolver); + + // Reference ramp. Automations on this constant source node will + // generate the desired ramp. + const srcRamp = new ConstantSourceNode(context, {offset: 0}); + + // Use these gain nodes to compute the difference between the + // convolver output and the expected ramp to create the error + // signal. + const inverter = new GainNode(context, {gain: -1}); + const sum = new GainNode(context, {gain: 1}); + convolver.connect(sum); + srcRamp.connect(inverter).connect(sum); + + // Square the error signal using this gain node. + const squarer = new GainNode(context, {gain: 0}); + sum.connect(squarer); + sum.connect(squarer.gain); + + // Merge the error signal and the square source so we can integrate + // the error signal to find an SNR. + const merger = new ChannelMergerNode(context, {numberOfInputs: 2}); + + squarer.connect(merger, 0, 0); + srcSquare.connect(merger, 0, 1); + + // For simplicity, use a ScriptProcessor to integrate the error + // signal. The square pulse signal is used as a gate over which the + // integration is done. When the pulse ends, the SNR is computed + // and the test ends. + + // |doSum| is used to determine when to integrate and when it + // becomes false, it signals the end of integration. + let doSum = false; + + // |signalSum| is the energy in the square pulse. |errorSum| is the + // energy in the error signal. + let signalSum = 0; + let errorSum = 0; + + let spn = context.createScriptProcessor(0, 2, 1); + spn.onaudioprocess = (event) => { + // Sum the values on the first channel when the second channel is + // not zero. When the second channel goes from non-zero to 0, + // dump the value out and terminate the test. + let c0 = event.inputBuffer.getChannelData(0); + let c1 = event.inputBuffer.getChannelData(1); + + for (let k = 0; k < c1.length; ++k) { + if (c1[k] == 0) { + if (doSum) { + doSum = false; + // Square wave is now silent and we were integration, so we + // can stop now and verify the SNR. + should(10 * Math.log10(signalSum / errorSum), 'SNR') + .beGreaterThanOrEqualTo(minRequiredSNR); + spn.onaudioprocess = null; + task.done(); + } + } else { + // Signal is non-zero so sum up the values. + doSum = true; + errorSum += c0[k]; + signalSum += c1[k] * c1[k]; + } + } + }; + + merger.connect(spn).connect(context.destination); + + // Schedule everything to start a bit in the futurefrom now, and end + // pulseLength frames later. + let now = context.currentTime; + + // |startFrame| is the number of frames to schedule ahead for + // testing. + const startFrame = 512; + const startTime = startFrame / context.sampleRate; + const pulseDuration = pulseLength / context.sampleRate; + + // Create a square pulse in the constant source node. + srcSquare.offset.setValueAtTime(1, now + startTime); + srcSquare.offset.setValueAtTime(0, now + startTime + pulseDuration); + + // Create the reference ramp. + srcRamp.offset.setValueAtTime(1, now + startTime); + srcRamp.offset.linearRampToValueAtTime( + pulseLength, + now + startTime + pulseDuration - 1 / context.sampleRate); + srcRamp.offset.linearRampToValueAtTime( + 0, + now + startTime + 2 * pulseDuration - 1 / context.sampleRate); + + // Start the ramps! + srcRamp.start(); + srcSquare.start(); + }); + + audit.run(); + </script> + </body> +</html> |