summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html')
-rw-r--r--testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html184
1 files changed, 184 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html b/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html
new file mode 100644
index 0000000000..ccca103a3b
--- /dev/null
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/no-dezippering.html
@@ -0,0 +1,184 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test DelayNode Has No Dezippering
+ </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>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ // The sample rate must be a power of two to avoid any round-off errors in
+ // computing when to suspend a context on a rendering quantum boundary.
+ // Otherwise this is pretty arbitrary.
+ let sampleRate = 16384;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define(
+ {label: 'test0', description: 'Test DelayNode has no dezippering'},
+ (task, should) => {
+ let context = new OfflineAudioContext(1, sampleRate, sampleRate);
+
+ // Simple integer ramp for testing delay node
+ let buffer = new AudioBuffer(
+ {length: context.length, sampleRate: context.sampleRate});
+ let rampData = buffer.getChannelData(0);
+ for (let k = 0; k < rampData.length; ++k) {
+ rampData[k] = k + 1;
+ }
+
+ // |delay0Frame| is the initial delay in frames. |delay1Frame| is
+ // the new delay in frames. These must be integers.
+ let delay0Frame = 64;
+ let delay1Frame = 16;
+
+ let src = new AudioBufferSourceNode(context, {buffer: buffer});
+ let delay = new DelayNode(
+ context, {delayTime: delay0Frame / context.sampleRate});
+
+ src.connect(delay).connect(context.destination);
+
+ // After a render quantum, change the delay to |delay1Frame|.
+ context.suspend(RENDER_QUANTUM_FRAMES / context.sampleRate)
+ .then(() => {
+ delay.delayTime.value = delay1Frame / context.sampleRate;
+ })
+ .then(() => context.resume());
+
+ src.start();
+ context.startRendering()
+ .then(renderedBuffer => {
+ let renderedData = renderedBuffer.getChannelData(0);
+
+ // The first |delay0Frame| frames should be zero.
+ should(
+ renderedData.slice(0, delay0Frame),
+ 'output[0:' + (delay0Frame - 1) + ']')
+ .beConstantValueOf(0);
+
+ // Now we have the ramp should show up from the delay.
+ let ramp0 =
+ new Float32Array(RENDER_QUANTUM_FRAMES - delay0Frame);
+ for (let k = 0; k < ramp0.length; ++k) {
+ ramp0[k] = rampData[k];
+ }
+
+ should(
+ renderedData.slice(delay0Frame, RENDER_QUANTUM_FRAMES),
+ 'output[' + delay0Frame + ':' +
+ (RENDER_QUANTUM_FRAMES - 1) + ']')
+ .beEqualToArray(ramp0);
+
+ // After one rendering quantum, the delay is changed to
+ // |delay1Frame|.
+ let ramp1 =
+ new Float32Array(context.length - RENDER_QUANTUM_FRAMES);
+ for (let k = 0; k < ramp1.length; ++k) {
+ // ramp1[k] = 1 + k + RENDER_QUANTUM_FRAMES - delay1Frame;
+ ramp1[k] =
+ rampData[k + RENDER_QUANTUM_FRAMES - delay1Frame];
+ }
+ should(
+ renderedData.slice(RENDER_QUANTUM_FRAMES),
+ 'output[' + RENDER_QUANTUM_FRAMES + ':]')
+ .beEqualToArray(ramp1);
+ })
+ .then(() => task.done());
+ });
+
+ audit.define(
+ {label: 'test1', description: 'Test value setter and setValueAtTime'},
+ (task, should) => {
+ testWithAutomation(should, {prefix: '', threshold: 6.5819e-5})
+ .then(() => task.done());
+ });
+
+ audit.define(
+ {label: 'test2', description: 'Test value setter and modulation'},
+ (task, should) => {
+ testWithAutomation(should, {
+ prefix: 'With modulation: ',
+ modulator: true
+ }).then(() => task.done());
+ });
+
+ // Compare .value setter with setValueAtTime, Optionally allow modulation
+ // of |delayTime|.
+ function testWithAutomation(should, options) {
+ let prefix = options.prefix;
+ // Channel 0 is the output of delay node using the setter and channel 1
+ // is the output using setValueAtTime.
+ let context = new OfflineAudioContext(2, sampleRate, sampleRate);
+
+ let merger = new ChannelMergerNode(
+ context, {numberOfInputs: context.destination.channelCount});
+ merger.connect(context.destination);
+
+ let src = new OscillatorNode(context);
+
+ // |delay0Frame| is the initial delay value in frames. |delay1Frame| is
+ // the new delay in frames. The values here are constrained only by the
+ // constraints for a DelayNode. These are pretty arbitrary except we
+ // wanted them to be fractional so as not be on a frame boundary to
+ // test interpolation compared with |setValueAtTime()|..
+ let delay0Frame = 3.1;
+ let delay1Frame = 47.2;
+
+ let delayTest = new DelayNode(
+ context, {delayTime: delay0Frame / context.sampleRate});
+ let delayRef = new DelayNode(
+ context, {delayTime: delay0Frame / context.sampleRate});
+
+ src.connect(delayTest).connect(merger, 0, 0);
+ src.connect(delayRef).connect(merger, 0, 1);
+
+ if (options.modulator) {
+ // Fairly arbitrary modulation of the delay time, with a peak
+ // variation of 10 ms.
+ let mod = new OscillatorNode(context, {frequency: 1000});
+ let modGain = new GainNode(context, {gain: .01});
+ mod.connect(modGain);
+ modGain.connect(delayTest.delayTime);
+ modGain.connect(delayRef.delayTime);
+ mod.start();
+ }
+
+ // The time at which the delay time of |delayTest| node will be
+ // changed. This MUST be on a render quantum boundary, but is
+ // otherwise arbitrary.
+ let changeTime = 3 * RENDER_QUANTUM_FRAMES / context.sampleRate;
+
+ // Schedule the delay change on |delayRef| and also apply the value
+ // setter for |delayTest| at |changeTime|.
+ delayRef.delayTime.setValueAtTime(
+ delay1Frame / context.sampleRate, changeTime);
+ context.suspend(changeTime)
+ .then(() => {
+ delayTest.delayTime.value = delay1Frame / context.sampleRate;
+ })
+ .then(() => context.resume());
+
+ src.start();
+
+ return context.startRendering().then(renderedBuffer => {
+ let actual = renderedBuffer.getChannelData(0);
+ let expected = renderedBuffer.getChannelData(1);
+
+ let match = should(actual, prefix + '.value setter output')
+ .beCloseToArray(
+ expected, {absoluteThreshold: options.threshold});
+ should(
+ match,
+ prefix + '.value setter output matches setValueAtTime output')
+ .beTrue();
+ });
+ }
+
+ audit.run();
+ </script>
+ </body>
+</html>