summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface')
-rw-r--r--testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html131
-rw-r--r--testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html261
-rw-r--r--testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-basic.html54
-rw-r--r--testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-panning.html34
4 files changed, 480 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html
new file mode 100644
index 0000000000..9409f1ffce
--- /dev/null
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test Constructor: StereoPanner
+ </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/audionodeoptions.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let context;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define('initialize', (task, should) => {
+ context = initializeContext(should);
+ task.done();
+ });
+
+ audit.define('invalid constructor', (task, should) => {
+ testInvalidConstructor(should, 'StereoPannerNode', context);
+ task.done();
+ });
+
+ audit.define('default constructor', (task, should) => {
+ let prefix = 'node0';
+ let node = testDefaultConstructor(should, 'StereoPannerNode', context, {
+ prefix: prefix,
+ numberOfInputs: 1,
+ numberOfOutputs: 1,
+ channelCount: 2,
+ channelCountMode: 'clamped-max',
+ channelInterpretation: 'speakers'
+ });
+
+ testDefaultAttributes(should, node, prefix, [{name: 'pan', value: 0}]);
+
+ task.done();
+ });
+
+ audit.define('test AudioNodeOptions', (task, should) => {
+ // Can't use testAudioNodeOptions because the constraints for this node
+ // are not supported there.
+ let node;
+
+ // An array of tests.
+ [{
+ // Test that we can set the channel count to 1 or 2 and that other
+ // channel counts throw an error.
+ attribute: 'channelCount',
+ tests: [
+ {value: 1}, {value: 2}, {value: 0, error: 'NotSupportedError'},
+ {value: 3, error: 'NotSupportedError'},
+ {value: 99, error: 'NotSupportedError'}
+ ]
+ },
+ {
+ // Test channelCountMode. A mode of "max" is illegal, but others are
+ // ok. But also throw an error of unknown values.
+ attribute: 'channelCountMode',
+ tests: [
+ {value: 'clamped-max'}, {value: 'explicit'},
+ {value: 'max', error: 'NotSupportedError'},
+ {value: 'foobar', error: TypeError}
+ ]
+ },
+ {
+ // Test channelInterpretation can be set for valid values and an
+ // error is thrown for others.
+ attribute: 'channelInterpretation',
+ tests: [
+ {value: 'speakers'}, {value: 'discrete'},
+ {value: 'foobar', error: TypeError}
+ ]
+ }].forEach(entry => {
+ entry.tests.forEach(testItem => {
+ let options = {};
+ options[entry.attribute] = testItem.value;
+
+ const testFunction = () => {
+ node = new StereoPannerNode(context, options);
+ };
+ const testDescription =
+ `new StereoPannerNode(c, ${JSON.stringify(options)})`;
+
+ if (testItem.error) {
+ testItem.error === TypeError
+ ? should(testFunction, testDescription).throw(TypeError)
+ : should(testFunction, testDescription)
+ .throw(DOMException, 'NotSupportedError');
+ } else {
+ should(testFunction, testDescription).notThrow();
+ should(node[entry.attribute], `node.${entry.attribute}`)
+ .beEqualTo(options[entry.attribute]);
+ }
+ });
+ });
+
+ task.done();
+ });
+
+ audit.define('constructor with options', (task, should) => {
+ let node;
+ let options = {
+ pan: 0.75,
+ };
+
+ should(
+ () => {
+ node = new StereoPannerNode(context, options);
+ },
+ 'node1 = new StereoPannerNode(, ' + JSON.stringify(options) + ')')
+ .notThrow();
+ should(
+ node instanceof StereoPannerNode,
+ 'node1 instanceof StereoPannerNode')
+ .beEqualTo(true);
+
+ should(node.pan.value, 'node1.pan.value').beEqualTo(options.pan);
+
+ task.done();
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html
new file mode 100644
index 0000000000..355db8b9dc
--- /dev/null
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html
@@ -0,0 +1,261 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ Test StereoPannerNode Has No Dezippering
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ // Arbitrary sample rate except that it should be a power of two to
+ // eliminate any round-off in computing frame boundaries.
+ let sampleRate = 16384;
+
+ let audit = Audit.createTaskRunner();
+
+ audit.define(
+ {
+ label: 'test mono input',
+ description: 'Test StereoPanner with mono input has no dezippering'
+ },
+ (task, should) => {
+ let context = new OfflineAudioContext(2, sampleRate, sampleRate);
+ let src = new ConstantSourceNode(context, {offset: 1});
+ let p = new StereoPannerNode(context, {pan: -1});
+
+ src.connect(p).connect(context.destination);
+ src.start();
+
+ // Frame at which to change pan value.
+ let panFrame = 256;
+ context.suspend(panFrame / context.sampleRate)
+ .then(() => p.pan.value = 1)
+ .then(() => context.resume());
+
+ context.startRendering()
+ .then(renderedBuffer => {
+ let c0 = renderedBuffer.getChannelData(0);
+ let c1 = renderedBuffer.getChannelData(1);
+
+ // The first part should be full left.
+ should(
+ c0.slice(0, panFrame), 'Mono: Left channel, pan = -1: ')
+ .beConstantValueOf(1);
+ should(
+ c1.slice(0, panFrame), 'Mono: Right channel, pan = -1:')
+ .beConstantValueOf(0);
+
+ // The second part should be full right, but due to roundoff,
+ // the left channel won't be exactly zero. Compare the left
+ // channel against zero with a threshold instead.
+ let tail = c0.slice(panFrame);
+ let zero = new Float32Array(tail.length);
+
+ should(c0.slice(panFrame), 'Mono: Left channel, pan = 1: ')
+ .beCloseToArray(zero, {absoluteThreshold: 6.1233e-17});
+ should(c1.slice(panFrame), 'Mono: Right channel, pan = 1:')
+ .beConstantValueOf(1);
+ })
+ .then(() => task.done());
+ });
+
+ audit.define(
+ {
+ label: 'test stereo input',
+ description:
+ 'Test StereoPanner with stereo input has no dezippering'
+ },
+ (task, should) => {
+ let context = new OfflineAudioContext(2, sampleRate, sampleRate);
+
+ // Create stereo source from two constant source nodes.
+ let s0 = new ConstantSourceNode(context, {offset: 1});
+ let s1 = new ConstantSourceNode(context, {offset: 2});
+ let merger = new ChannelMergerNode(context, {numberOfInputs: 2});
+
+ s0.connect(merger, 0, 0);
+ s1.connect(merger, 0, 1);
+
+ let p = new StereoPannerNode(context, {pan: -1});
+
+ merger.connect(p).connect(context.destination);
+ s0.start();
+ s1.start();
+
+ // Frame at which to change pan value.
+ let panFrame = 256;
+ context.suspend(panFrame / context.sampleRate)
+ .then(() => p.pan.value = 1)
+ .then(() => context.resume());
+
+ context.startRendering()
+ .then(renderedBuffer => {
+ let c0 = renderedBuffer.getChannelData(0);
+ let c1 = renderedBuffer.getChannelData(1);
+
+ // The first part should be full left.
+ should(
+ c0.slice(0, panFrame), 'Stereo: Left channel, pan = -1: ')
+ .beConstantValueOf(3);
+ should(
+ c1.slice(0, panFrame), 'Stereo: Right channel, pan = -1:')
+ .beConstantValueOf(0);
+
+ // The second part should be full right, but due to roundoff,
+ // the left channel won't be exactly zero. Compare the left
+ // channel against zero with a threshold instead.
+ let tail = c0.slice(panFrame);
+ let zero = new Float32Array(tail.length);
+
+ should(c0.slice(panFrame), 'Stereo: Left channel, pan = 1: ')
+ .beCloseToArray(zero, {absoluteThreshold: 6.1233e-17});
+ should(c1.slice(panFrame), 'Stereo: Right channel, pan = 1:')
+ .beConstantValueOf(3);
+ })
+ .then(() => task.done());
+ });
+
+ audit.define(
+ {
+ label: 'test mono input setValue',
+ description: 'Test StereoPanner with mono input value setter ' +
+ 'vs setValueAtTime'
+ },
+ (task, should) => {
+ let context = new OfflineAudioContext(4, sampleRate, sampleRate);
+
+ let src = new OscillatorNode(context);
+
+ src.start();
+ testWithSetValue(context, src, should, {
+ prefix: 'Mono'
+ }).then(() => task.done());
+ });
+
+ audit.define(
+ {
+ label: 'test stereo input setValue',
+ description: 'Test StereoPanner with mono input value setter ' +
+ ' vs setValueAtTime'
+ },
+ (task, should) => {
+ let context = new OfflineAudioContext(4, sampleRate, sampleRate);
+
+ let src0 = new OscillatorNode(context, {frequency: 800});
+ let src1 = new OscillatorNode(context, {frequency: 250});
+ let merger = new ChannelMergerNode(context, {numberOfChannels: 2});
+
+ src0.connect(merger, 0, 0);
+ src1.connect(merger, 0, 1);
+
+ src0.start();
+ src1.start();
+
+ testWithSetValue(context, merger, should, {
+ prefix: 'Stereo'
+ }).then(() => task.done());
+ });
+
+ audit.define(
+ {
+ label: 'test mono input automation',
+ description: 'Test StereoPanner with mono input and automation'
+ },
+ (task, should) => {
+ let context = new OfflineAudioContext(4, sampleRate, sampleRate);
+
+ let src0 = new OscillatorNode(context, {frequency: 800});
+ let src1 = new OscillatorNode(context, {frequency: 250});
+ let merger = new ChannelMergerNode(context, {numberOfChannels: 2});
+
+ src0.connect(merger, 0, 0);
+ src1.connect(merger, 0, 1);
+
+ src0.start();
+ src1.start();
+
+ let mod = new OscillatorNode(context, {frequency: 100});
+ mod.start();
+
+ testWithSetValue(context, merger, should, {
+ prefix: 'Modulated Stereo',
+ modulator: (testNode, refNode) => {
+ mod.connect(testNode.pan);
+ mod.connect(refNode.pan);
+ }
+ }).then(() => task.done());
+ });
+
+
+ function testWithSetValue(context, src, should, options) {
+ let merger = new ChannelMergerNode(
+ context, {numberOfInputs: context.destination.channelCount});
+ merger.connect(context.destination);
+
+ let pannerRef = new StereoPannerNode(context, {pan: -0.3});
+ let pannerTest =
+ new StereoPannerNode(context, {pan: pannerRef.pan.value});
+
+ let refSplitter =
+ new ChannelSplitterNode(context, {numberOfOutputs: 2});
+ let testSplitter =
+ new ChannelSplitterNode(context, {numberOfOutputs: 2});
+
+ pannerRef.connect(refSplitter);
+ pannerTest.connect(testSplitter);
+
+ testSplitter.connect(merger, 0, 0);
+ testSplitter.connect(merger, 1, 1);
+ refSplitter.connect(merger, 0, 2);
+ refSplitter.connect(merger, 1, 3);
+
+ src.connect(pannerRef);
+ src.connect(pannerTest);
+
+ let changeTime = 3 * RENDER_QUANTUM_FRAMES / context.sampleRate;
+ // An arbitrary position, different from the default pan value.
+ let newPanPosition = .71;
+
+ pannerRef.pan.setValueAtTime(newPanPosition, changeTime);
+ context.suspend(changeTime)
+ .then(() => pannerTest.pan.value = newPanPosition)
+ .then(() => context.resume());
+
+ if (options.modulator) {
+ options.modulator(pannerTest, pannerRef);
+ }
+ return context.startRendering().then(renderedBuffer => {
+ let actual = new Array(2);
+ let expected = new Array(2);
+
+ actual[0] = renderedBuffer.getChannelData(0);
+ actual[1] = renderedBuffer.getChannelData(1);
+ expected[0] = renderedBuffer.getChannelData(2);
+ expected[1] = renderedBuffer.getChannelData(3);
+
+ let label = ['Left', 'Right'];
+
+ for (let k = 0; k < 2; ++k) {
+ let match =
+ should(
+ actual[k],
+ options.prefix + ' ' + label[k] + ' .value setter output')
+ .beCloseToArray(expected[k], {absoluteThreshold: 1.192094e-7});
+ should(
+ match,
+ options.prefix + ' ' + label[k] +
+ ' .value setter output matches setValueAtTime output')
+ .beTrue();
+ }
+
+ });
+ }
+
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-basic.html b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-basic.html
new file mode 100644
index 0000000000..48bacb08c6
--- /dev/null
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-basic.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ stereopannernode-basic.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ audit.define(
+ {
+ label: 'test',
+ description:
+ 'Attributes and basic functionality of StereoPannerNode'
+ },
+ (task, should) => {
+
+ let context = new AudioContext();
+ let panner = context.createStereoPanner();
+
+ should(panner.numberOfInputs, 'panner.numberOfInputs').beEqualTo(1);
+ should(panner.numberOfOutputs, 'panner.numberOfOutputs')
+ .beEqualTo(1);
+ should(panner.pan.defaultValue, 'panner.pan.defaultValue')
+ .beEqualTo(0.0);
+ should(() => panner.pan.value = 1.0, 'panner.pan.value = 1.0')
+ .notThrow();
+ should(panner.pan.value, 'panner.pan.value').beEqualTo(1.0);
+
+ should(() => panner.channelCount = 1, 'panner.channelCount = 1')
+ .notThrow();
+ should(() => panner.channelCount = 3, 'panner.channelCount = 3')
+ .throw();
+ should(
+ () => panner.channelCountMode = 'explicit',
+ 'panner.channelCountMode = "explicit"')
+ .notThrow();
+ should(
+ () => panner.channelCountMode = 'max',
+ 'panner.channelCountMode = "max"')
+ .throw();
+
+ task.done();
+ });
+ audit.run();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-panning.html b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-panning.html
new file mode 100644
index 0000000000..f683fd78bf
--- /dev/null
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-stereopanner-interface/stereopannernode-panning.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>
+ stereopannernode-panning.html
+ </title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="../../resources/audit-util.js"></script>
+ <script src="../../resources/audit.js"></script>
+ <script src="../../resources/stereopanner-testing.js"></script>
+ </head>
+ <body>
+ <script id="layout-test-code">
+ let audit = Audit.createTaskRunner();
+
+ audit.define('mono-test', (task, should) => {
+ StereoPannerTest
+ .create(should, {numberOfInputChannels: 1, prefix: 'Mono: '})
+ .run()
+ .then(() => task.done());
+ });
+
+ audit.define('stereo-test', (task, should) => {
+ StereoPannerTest
+ .create(should, {numberOfInputChannels: 2, prefix: 'Stereo: '})
+ .run()
+ .then(() => task.done());
+ });
+
+ audit.run();
+ </script>
+ </body>
+</html>