mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-22 09:12:13 -05:00
LibWeb/WebAudio: Manage channelCountMode and channelCount for PannerNode
This commit is contained in:
parent
15a96e841b
commit
884599f1df
Notes:
github-actions[bot]
2024-12-18 09:21:00 +00:00
Author: https://github.com/shlyakpavel Commit: https://github.com/LadybirdBrowser/ladybird/commit/884599f1df4 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2944 Reviewed-by: https://github.com/gmta
7 changed files with 2555 additions and 0 deletions
|
@ -163,4 +163,24 @@ WebIDL::ExceptionOr<void> PannerNode::set_orientation(float x, float y, float z)
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audionode-channelcountmode
|
||||
WebIDL::ExceptionOr<void> PannerNode::set_channel_count_mode(Bindings::ChannelCountMode mode)
|
||||
{
|
||||
if (mode == Bindings::ChannelCountMode::Max) {
|
||||
return WebIDL::NotSupportedError::create(realm(), "PannerNode does not support 'max' as channelCountMode."_string);
|
||||
}
|
||||
|
||||
return AudioNode::set_channel_count_mode(mode);
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audionode-channelcount
|
||||
WebIDL::ExceptionOr<void> PannerNode::set_channel_count(WebIDL::UnsignedLong channel_count)
|
||||
{
|
||||
if (channel_count > 2) {
|
||||
return WebIDL::NotSupportedError::create(realm(), "PannerNode does not support channel count greater than 2"_string);
|
||||
}
|
||||
|
||||
return AudioNode::set_channel_count(channel_count);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -77,6 +77,10 @@ public:
|
|||
WebIDL::ExceptionOr<void> set_position(float x, float y, float z);
|
||||
WebIDL::ExceptionOr<void> set_orientation(float x, float y, float z);
|
||||
|
||||
// ^AudioNode
|
||||
virtual WebIDL::ExceptionOr<void> set_channel_count(WebIDL::UnsignedLong) override;
|
||||
virtual WebIDL::ExceptionOr<void> set_channel_count_mode(Bindings::ChannelCountMode) override;
|
||||
|
||||
protected:
|
||||
PannerNode(JS::Realm&, GC::Ref<BaseAudioContext>, PannerOptions const& = {});
|
||||
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 125 tests
|
||||
|
||||
121 Pass
|
||||
4 Fail
|
||||
Pass # AUDIT TASK RUNNER STARTED.
|
||||
Pass Executing "initialize"
|
||||
Pass Executing "invalid constructor"
|
||||
Pass Executing "default constructor"
|
||||
Pass Executing "test AudioNodeOptions"
|
||||
Pass Executing "constructor with options"
|
||||
Pass Audit report
|
||||
Pass > [initialize]
|
||||
Pass context = new OfflineAudioContext(...) did not throw an exception.
|
||||
Pass < [initialize] All assertions passed. (total 1 assertions)
|
||||
Pass > [invalid constructor]
|
||||
Pass new PannerNode() threw TypeError: "PannerNode() needs one argument".
|
||||
Pass new PannerNode(1) threw TypeError: "Not an object of type BaseAudioContext".
|
||||
Pass new PannerNode(context, 42) threw TypeError: "Not an object of type PannerOptions".
|
||||
Pass < [invalid constructor] All assertions passed. (total 3 assertions)
|
||||
Pass > [default constructor]
|
||||
Pass node0 = new PannerNode(context) did not throw an exception.
|
||||
Pass node0 instanceof PannerNode is equal to true.
|
||||
Pass node0.numberOfInputs is equal to 1.
|
||||
Pass node0.numberOfOutputs is equal to 1.
|
||||
Pass node0.channelCount is equal to 2.
|
||||
Pass node0.channelCountMode is equal to clamped-max.
|
||||
Pass node0.channelInterpretation is equal to speakers.
|
||||
Pass node0.panningModel is equal to equalpower.
|
||||
Pass node0.positionX.value is equal to 0.
|
||||
Pass node0.positionY.value is equal to 0.
|
||||
Pass node0.positionZ.value is equal to 0.
|
||||
Pass node0.orientationX.value is equal to 1.
|
||||
Pass node0.orientationY.value is equal to 0.
|
||||
Pass node0.orientationZ.value is equal to 0.
|
||||
Pass node0.distanceModel is equal to inverse.
|
||||
Pass node0.refDistance is equal to 1.
|
||||
Pass node0.maxDistance is equal to 10000.
|
||||
Pass node0.rolloffFactor is equal to 1.
|
||||
Pass node0.coneInnerAngle is equal to 360.
|
||||
Pass node0.coneOuterAngle is equal to 360.
|
||||
Pass node0.coneOuterGain is equal to 0.
|
||||
Pass context.listener.positionX.value is equal to 0.
|
||||
Pass context.listener.positionY.value is equal to 0.
|
||||
Pass context.listener.positionZ.value is equal to 0.
|
||||
Pass context.listener.forwardX.value is equal to 0.
|
||||
Pass context.listener.forwardY.value is equal to 0.
|
||||
Pass context.listener.forwardZ.value is equal to -1.
|
||||
Pass context.listener.upX.value is equal to 0.
|
||||
Pass context.listener.upY.value is equal to 1.
|
||||
Pass context.listener.upZ.value is equal to 0.
|
||||
Pass < [default constructor] All assertions passed. (total 30 assertions)
|
||||
Pass > [test AudioNodeOptions]
|
||||
Pass node1 = new PannerNode(c, {"channelCount":1}) did not throw an exception.
|
||||
Pass node1.channelCount is equal to 1.
|
||||
Pass node2 = new PannerNode(c, {"channelCount":2}) did not throw an exception.
|
||||
Pass node2.channelCount is equal to 2.
|
||||
Pass new PannerNode(c, {"channelCount":0}) threw NotSupportedError: "Invalid channel count".
|
||||
Pass node.channelCount = 0 threw NotSupportedError: "Invalid channel count".
|
||||
Pass node.channelCount after setting to 0 is equal to 2.
|
||||
Pass new PannerNode(c, {"channelCount":3}) threw NotSupportedError: "PannerNode does not support channel count greater than 2".
|
||||
Pass node.channelCount = 3 threw NotSupportedError: "PannerNode does not support channel count greater than 2".
|
||||
Pass node.channelCount after setting to 3 is equal to 2.
|
||||
Pass new PannerNode(c, {"channelCount":99}) threw NotSupportedError: "PannerNode does not support channel count greater than 2".
|
||||
Pass node.channelCount = 99 threw NotSupportedError: "PannerNode does not support channel count greater than 2".
|
||||
Pass node.channelCount after setting to 99 is equal to 2.
|
||||
Pass node3 = new PannerNode(c, {"channelCountMode":"clamped-max"}) did not throw an exception.
|
||||
Pass node3.channelCountMode is equal to clamped-max.
|
||||
Pass node4 = new PannerNode(c, {"channelCountMode":"explicit"}) did not throw an exception.
|
||||
Pass node4.channelCountMode is equal to explicit.
|
||||
Pass new PannerNode(c, {"channelCountMode":"max"}) threw NotSupportedError: "PannerNode does not support 'max' as channelCountMode.".
|
||||
Pass node.channelCountMode = max threw NotSupportedError: "PannerNode does not support 'max' as channelCountMode.".
|
||||
Pass node.channelCountMode after setting to max is equal to clamped-max.
|
||||
Pass new PannerNode(c, " + JSON.stringify(options) + ") threw TypeError: "Invalid value 'foobar' for enumeration type 'ChannelCountMode'".
|
||||
Pass node.channelCountMode = foobar did not throw an exception.
|
||||
Pass node.channelCountMode after setting to foobar is equal to clamped-max.
|
||||
Pass node5 = new PannerNode(c, {"channelInterpretation":"speakers"}) did not throw an exception.
|
||||
Pass node5.channelInterpretation is equal to speakers.
|
||||
Pass node6 = new PannerNode(c, {"channelInterpretation":"discrete"}) did not throw an exception.
|
||||
Pass node6.channelInterpretation is equal to discrete.
|
||||
Pass new PannerNode(c, {"channelInterpretation":"foobar"}) threw TypeError: "Invalid value 'foobar' for enumeration type 'ChannelInterpretation'".
|
||||
Pass new PannerNode(c, {"maxDistance":-1}) threw RangeError: "maxDistance cannot be negative".
|
||||
Pass node.maxDistance = -1 threw RangeError: "maxDistance cannot be negative".
|
||||
Pass node.maxDistance after setting to -1 is equal to 10000.
|
||||
Pass node7 = new PannerNode(c, {"maxDistance":100}) did not throw an exception.
|
||||
Pass node7.maxDistance is equal to 100.
|
||||
Pass new PannerNode(c, {"rolloffFactor":-1}) threw RangeError: "rolloffFactor cannot be negative".
|
||||
Pass node.rolloffFactor = -1 threw RangeError: "rolloffFactor cannot be negative".
|
||||
Pass node.rolloffFactor after setting to -1 is equal to 1.
|
||||
Pass node8 = new PannerNode(c, {"rolloffFactor":0}) did not throw an exception.
|
||||
Pass node8.rolloffFactor is equal to 0.
|
||||
Pass node8 = new PannerNode(c, {"rolloffFactor":0.5}) did not throw an exception.
|
||||
Pass node8.rolloffFactor is equal to 0.5.
|
||||
Pass node8 = new PannerNode(c, {"rolloffFactor":100}) did not throw an exception.
|
||||
Pass node8.rolloffFactor is equal to 100.
|
||||
Pass new PannerNode(c, {"coneOuterGain":-1}) threw InvalidStateError: "coneOuterGain must be in the range of [0, 1]".
|
||||
Pass node.coneOuterGain = -1 threw InvalidStateError: "coneOuterGain must be in the range of [0, 1]".
|
||||
Pass node.coneOuterGain after setting to -1 is equal to 0.
|
||||
Pass new PannerNode(c, {"coneOuterGain":1.1}) threw InvalidStateError: "coneOuterGain must be in the range of [0, 1]".
|
||||
Pass node.coneOuterGain = 1.1 threw InvalidStateError: "coneOuterGain must be in the range of [0, 1]".
|
||||
Pass node.coneOuterGain after setting to 1.1 is equal to 0.
|
||||
Pass node9 = new PannerNode(c, {"coneOuterGain":0}) did not throw an exception.
|
||||
Pass node9.coneOuterGain is equal to 0.
|
||||
Pass node9 = new PannerNode(c, {"coneOuterGain":0.5}) did not throw an exception.
|
||||
Pass node9.coneOuterGain is equal to 0.5.
|
||||
Pass node9 = new PannerNode(c, {"coneOuterGain":1}) did not throw an exception.
|
||||
Pass node9.coneOuterGain is equal to 1.
|
||||
Pass < [test AudioNodeOptions] All assertions passed. (total 54 assertions)
|
||||
Pass > [constructor with options]
|
||||
Pass node = new PannerNode(c, {"panningModel":"HRTF","positionX":1.4142135623730951,"positionY":2.8284271247461903,"positionZ":4.242640687119286,"orientationX":-1.4142135623730951,"orientationY":-2.8284271247461903,"orientationZ":-4.242640687119286,"distanceModel":"linear","refDistance":3.141592653589793,"maxDistance":6.283185307179586,"rolloffFactor":9.42477796076938,"coneInnerAngle":12.566370614359172,"coneOuterAngle":15.707963267948966,"coneOuterGain":0.3141592653589793}) did not throw an exception.
|
||||
Pass node instanceof PannerNode is equal to true.
|
||||
Fail X node.panningModel is not equal to HRTF. Got equalpower.
|
||||
Pass node.positionX.value is equal to 1.4142135381698608.
|
||||
Pass node.positionY.value is equal to 2.8284270763397217.
|
||||
Pass node.positionZ.value is equal to 4.242640495300293.
|
||||
Pass node.orientationX.value is equal to -1.4142135381698608.
|
||||
Pass node.orientationY.value is equal to -2.8284270763397217.
|
||||
Pass node.orientationZ.value is equal to -4.242640495300293.
|
||||
Fail X node.distanceModel is not equal to linear. Got inverse.
|
||||
Pass node.refDistance is equal to 3.141592653589793.
|
||||
Pass node.maxDistance is equal to 6.283185307179586.
|
||||
Pass node.rolloffFactor is equal to 9.42477796076938.
|
||||
Pass node.coneInnerAngle is equal to 12.566370614359172.
|
||||
Pass node.coneOuterAngle is equal to 15.707963267948966.
|
||||
Pass node.coneOuterGain is equal to 0.3141592653589793.
|
||||
Pass node.channelCount is equal to 2.
|
||||
Pass node.channelCountMode is equal to clamped-max.
|
||||
Pass node.channelInterpretation is equal to speakers.
|
||||
Fail < [constructor with options] 2 out of 19 assertions were failed.
|
||||
Fail # AUDIT TASK RUNNER FINISHED: 1 out of 5 tasks were failed.
|
|
@ -0,0 +1,292 @@
|
|||
// Test that constructor for the node with name |nodeName| handles the
|
||||
// various possible values for channelCount, channelCountMode, and
|
||||
// channelInterpretation.
|
||||
|
||||
// The |should| parameter is the test function from new |Audit|.
|
||||
function testAudioNodeOptions(should, context, nodeName, expectedNodeOptions) {
|
||||
if (expectedNodeOptions === undefined)
|
||||
expectedNodeOptions = {};
|
||||
let node;
|
||||
|
||||
// Test that we can set channelCount and that errors are thrown for
|
||||
// invalid values
|
||||
let testChannelCount = 17;
|
||||
if (expectedNodeOptions.channelCount) {
|
||||
testChannelCount = expectedNodeOptions.channelCount.value;
|
||||
}
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context, Object.assign({}, expectedNodeOptions.additionalOptions, {
|
||||
channelCount: testChannelCount
|
||||
}));
|
||||
},
|
||||
'new ' + nodeName + '(c, {channelCount: ' + testChannelCount + '})')
|
||||
.notThrow();
|
||||
should(node.channelCount, 'node.channelCount').beEqualTo(testChannelCount);
|
||||
|
||||
if (expectedNodeOptions.channelCount &&
|
||||
expectedNodeOptions.channelCount.isFixed) {
|
||||
// The channel count is fixed. Verify that we throw an error if
|
||||
// we try to change it. Arbitrarily set the count to be one more
|
||||
// than the expected value.
|
||||
testChannelCount = expectedNodeOptions.channelCount.value + 1;
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelCount: testChannelCount}));
|
||||
},
|
||||
'new ' + nodeName + '(c, {channelCount: ' + testChannelCount + '})')
|
||||
.throw(DOMException,
|
||||
expectedNodeOptions.channelCount.exceptionType);
|
||||
// And test that setting it to the fixed value does not throw.
|
||||
testChannelCount = expectedNodeOptions.channelCount.value;
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelCount: testChannelCount}));
|
||||
node.channelCount = testChannelCount;
|
||||
},
|
||||
'(new ' + nodeName + '(c, {channelCount: ' + testChannelCount + '})).channelCount = ' + testChannelCount)
|
||||
.notThrow();
|
||||
} else {
|
||||
// The channel count is not fixed. Try to set the count to invalid
|
||||
// values and make sure an error is thrown.
|
||||
[0, 99].forEach(testValue => {
|
||||
should(() => {
|
||||
node = new window[nodeName](
|
||||
context, Object.assign({}, expectedNodeOptions.additionalOptions, {
|
||||
channelCount: testValue
|
||||
}));
|
||||
}, `new ${nodeName}(c, {channelCount: ${testValue}})`)
|
||||
.throw(DOMException, 'NotSupportedError');
|
||||
});
|
||||
}
|
||||
|
||||
// Test channelCountMode
|
||||
let testChannelCountMode = 'max';
|
||||
if (expectedNodeOptions.channelCountMode) {
|
||||
testChannelCountMode = expectedNodeOptions.channelCountMode.value;
|
||||
}
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context, Object.assign({}, expectedNodeOptions.additionalOptions, {
|
||||
channelCountMode: testChannelCountMode
|
||||
}));
|
||||
},
|
||||
'new ' + nodeName + '(c, {channelCountMode: "' + testChannelCountMode +
|
||||
'"}')
|
||||
.notThrow();
|
||||
should(node.channelCountMode, 'node.channelCountMode')
|
||||
.beEqualTo(testChannelCountMode);
|
||||
|
||||
if (expectedNodeOptions.channelCountMode &&
|
||||
expectedNodeOptions.channelCountMode.isFixed) {
|
||||
// Channel count mode is fixed. Test setting to something else throws.
|
||||
['max', 'clamped-max', 'explicit'].forEach(testValue => {
|
||||
if (testValue !== expectedNodeOptions.channelCountMode.value) {
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelCountMode: testValue}));
|
||||
},
|
||||
`new ${nodeName}(c, {channelCountMode: "${testValue}"})`)
|
||||
.throw(DOMException,
|
||||
expectedNodeOptions.channelCountMode.exceptionType);
|
||||
} else {
|
||||
// Test that explicitly setting the the fixed value is allowed.
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelCountMode: testValue}));
|
||||
node.channelCountMode = testValue;
|
||||
},
|
||||
`(new ${nodeName}(c, {channelCountMode: "${testValue}"})).channelCountMode = "${testValue}"`)
|
||||
.notThrow();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Mode is not fixed. Verify that we can set the mode to all valid
|
||||
// values, and that we throw for invalid values.
|
||||
|
||||
let testValues = ['max', 'clamped-max', 'explicit'];
|
||||
|
||||
testValues.forEach(testValue => {
|
||||
should(() => {
|
||||
node = new window[nodeName](
|
||||
context, Object.assign({}, expectedNodeOptions.additionalOptions, {
|
||||
channelCountMode: testValue
|
||||
}));
|
||||
}, `new ${nodeName}(c, {channelCountMode: "${testValue}"})`).notThrow();
|
||||
should(
|
||||
node.channelCountMode, 'node.channelCountMode after valid setter')
|
||||
.beEqualTo(testValue);
|
||||
|
||||
});
|
||||
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelCountMode: 'foobar'}));
|
||||
},
|
||||
'new ' + nodeName + '(c, {channelCountMode: "foobar"}')
|
||||
.throw(TypeError);
|
||||
should(node.channelCountMode, 'node.channelCountMode after invalid setter')
|
||||
.beEqualTo(testValues[testValues.length - 1]);
|
||||
}
|
||||
|
||||
// Test channelInterpretation
|
||||
if (expectedNodeOptions.channelInterpretation &&
|
||||
expectedNodeOptions.channelInterpretation.isFixed) {
|
||||
// The channel interpretation is fixed. Verify that we throw an
|
||||
// error if we try to change it.
|
||||
['speakers', 'discrete'].forEach(testValue => {
|
||||
if (testValue !== expectedNodeOptions.channelInterpretation.value) {
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionOptions,
|
||||
{channelInterpretation: testValue}));
|
||||
},
|
||||
`new ${nodeName}(c, {channelInterpretation: "${testValue}"})`)
|
||||
.throw(DOMException,
|
||||
expectedNodeOptions.channelCountMode.exceptionType);
|
||||
} else {
|
||||
// Check that assigning the fixed value is OK.
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionOptions,
|
||||
{channelInterpretation: testValue}));
|
||||
node.channelInterpretation = testValue;
|
||||
},
|
||||
`(new ${nodeName}(c, {channelInterpretation: "${testValue}"})).channelInterpretation = "${testValue}"`)
|
||||
.notThrow();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Channel interpretation is not fixed. Verify that we can set it
|
||||
// to all possible values.
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelInterpretation: 'speakers'}));
|
||||
},
|
||||
'new ' + nodeName + '(c, {channelInterpretation: "speakers"})')
|
||||
.notThrow();
|
||||
should(node.channelInterpretation, 'node.channelInterpretation')
|
||||
.beEqualTo('speakers');
|
||||
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelInterpretation: 'discrete'}));
|
||||
},
|
||||
'new ' + nodeName + '(c, {channelInterpretation: "discrete"})')
|
||||
.notThrow();
|
||||
should(node.channelInterpretation, 'node.channelInterpretation')
|
||||
.beEqualTo('discrete');
|
||||
|
||||
should(
|
||||
() => {
|
||||
node = new window[nodeName](
|
||||
context,
|
||||
Object.assign(
|
||||
{}, expectedNodeOptions.additionalOptions,
|
||||
{channelInterpretation: 'foobar'}));
|
||||
},
|
||||
'new ' + nodeName + '(c, {channelInterpretation: "foobar"})')
|
||||
.throw(TypeError);
|
||||
should(
|
||||
node.channelInterpretation,
|
||||
'node.channelInterpretation after invalid setter')
|
||||
.beEqualTo('discrete');
|
||||
}
|
||||
}
|
||||
|
||||
function initializeContext(should) {
|
||||
let c;
|
||||
should(() => {
|
||||
c = new OfflineAudioContext(1, 1, 48000);
|
||||
}, 'context = new OfflineAudioContext(...)').notThrow();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
function testInvalidConstructor(should, name, context) {
|
||||
should(() => {
|
||||
new window[name]();
|
||||
}, 'new ' + name + '()').throw(TypeError);
|
||||
should(() => {
|
||||
new window[name](1);
|
||||
}, 'new ' + name + '(1)').throw(TypeError);
|
||||
should(() => {
|
||||
new window[name](context, 42);
|
||||
}, 'new ' + name + '(context, 42)').throw(TypeError);
|
||||
}
|
||||
|
||||
function testDefaultConstructor(should, name, context, options) {
|
||||
let node;
|
||||
|
||||
let message = options.prefix + ' = new ' + name + '(context';
|
||||
if (options.constructorOptions)
|
||||
message += ', ' + JSON.stringify(options.constructorOptions);
|
||||
message += ')'
|
||||
|
||||
should(() => {
|
||||
node = new window[name](context, options.constructorOptions);
|
||||
}, message).notThrow();
|
||||
|
||||
should(node instanceof window[name], options.prefix + ' instanceof ' + name)
|
||||
.beEqualTo(true);
|
||||
should(node.numberOfInputs, options.prefix + '.numberOfInputs')
|
||||
.beEqualTo(options.numberOfInputs);
|
||||
should(node.numberOfOutputs, options.prefix + '.numberOfOutputs')
|
||||
.beEqualTo(options.numberOfOutputs);
|
||||
should(node.channelCount, options.prefix + '.channelCount')
|
||||
.beEqualTo(options.channelCount);
|
||||
should(node.channelCountMode, options.prefix + '.channelCountMode')
|
||||
.beEqualTo(options.channelCountMode);
|
||||
should(node.channelInterpretation, options.prefix + '.channelInterpretation')
|
||||
.beEqualTo(options.channelInterpretation);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function testDefaultAttributes(should, node, prefix, items) {
|
||||
items.forEach((item) => {
|
||||
let attr = node[item.name];
|
||||
if (attr instanceof AudioParam) {
|
||||
should(attr.value, prefix + '.' + item.name + '.value')
|
||||
.beEqualTo(item.value);
|
||||
} else {
|
||||
should(attr, prefix + '.' + item.name).beEqualTo(item.value);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
// Copyright 2016 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
|
||||
/**
|
||||
* @fileOverview This file includes legacy utility functions for the layout
|
||||
* test.
|
||||
*/
|
||||
|
||||
// How many frames in a WebAudio render quantum.
|
||||
let RENDER_QUANTUM_FRAMES = 128;
|
||||
|
||||
// Compare two arrays (commonly extracted from buffer.getChannelData()) with
|
||||
// constraints:
|
||||
// options.thresholdSNR: Minimum allowed SNR between the actual and expected
|
||||
// signal. The default value is 10000.
|
||||
// options.thresholdDiffULP: Maximum allowed difference between the actual
|
||||
// and expected signal in ULP(Unit in the last place). The default is 0.
|
||||
// options.thresholdDiffCount: Maximum allowed number of sample differences
|
||||
// which exceeds the threshold. The default is 0.
|
||||
// options.bitDepth: The expected result is assumed to come from an audio
|
||||
// file with this number of bits of precision. The default is 16.
|
||||
function compareBuffersWithConstraints(should, actual, expected, options) {
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
// Only print out the message if the lengths are different; the
|
||||
// expectation is that they are the same, so don't clutter up the
|
||||
// output.
|
||||
if (actual.length !== expected.length) {
|
||||
should(
|
||||
actual.length === expected.length,
|
||||
'Length of actual and expected buffers should match')
|
||||
.beTrue();
|
||||
}
|
||||
|
||||
let maxError = -1;
|
||||
let diffCount = 0;
|
||||
let errorPosition = -1;
|
||||
let thresholdSNR = (options.thresholdSNR || 10000);
|
||||
|
||||
let thresholdDiffULP = (options.thresholdDiffULP || 0);
|
||||
let thresholdDiffCount = (options.thresholdDiffCount || 0);
|
||||
|
||||
// By default, the bit depth is 16.
|
||||
let bitDepth = (options.bitDepth || 16);
|
||||
let scaleFactor = Math.pow(2, bitDepth - 1);
|
||||
|
||||
let noisePower = 0, signalPower = 0;
|
||||
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
let diff = actual[i] - expected[i];
|
||||
noisePower += diff * diff;
|
||||
signalPower += expected[i] * expected[i];
|
||||
|
||||
if (Math.abs(diff) > maxError) {
|
||||
maxError = Math.abs(diff);
|
||||
errorPosition = i;
|
||||
}
|
||||
|
||||
// The reference file is a 16-bit WAV file, so we will almost never get
|
||||
// an exact match between it and the actual floating-point result.
|
||||
if (Math.abs(diff) > scaleFactor)
|
||||
diffCount++;
|
||||
}
|
||||
|
||||
let snr = 10 * Math.log10(signalPower / noisePower);
|
||||
let maxErrorULP = maxError * scaleFactor;
|
||||
|
||||
should(snr, 'SNR').beGreaterThanOrEqualTo(thresholdSNR);
|
||||
|
||||
should(
|
||||
maxErrorULP,
|
||||
options.prefix + ': Maximum difference (in ulp units (' + bitDepth +
|
||||
'-bits))')
|
||||
.beLessThanOrEqualTo(thresholdDiffULP);
|
||||
|
||||
should(diffCount, options.prefix + ': Number of differences between results')
|
||||
.beLessThanOrEqualTo(thresholdDiffCount);
|
||||
}
|
||||
|
||||
// Create an impulse in a buffer of length sampleFrameLength
|
||||
function createImpulseBuffer(context, sampleFrameLength) {
|
||||
let audioBuffer =
|
||||
context.createBuffer(1, sampleFrameLength, context.sampleRate);
|
||||
let n = audioBuffer.length;
|
||||
let dataL = audioBuffer.getChannelData(0);
|
||||
|
||||
for (let k = 0; k < n; ++k) {
|
||||
dataL[k] = 0;
|
||||
}
|
||||
dataL[0] = 1;
|
||||
|
||||
return audioBuffer;
|
||||
}
|
||||
|
||||
// Create a buffer of the given length with a linear ramp having values 0 <= x <
|
||||
// 1.
|
||||
function createLinearRampBuffer(context, sampleFrameLength) {
|
||||
let audioBuffer =
|
||||
context.createBuffer(1, sampleFrameLength, context.sampleRate);
|
||||
let n = audioBuffer.length;
|
||||
let dataL = audioBuffer.getChannelData(0);
|
||||
|
||||
for (let i = 0; i < n; ++i)
|
||||
dataL[i] = i / n;
|
||||
|
||||
return audioBuffer;
|
||||
}
|
||||
|
||||
// Create an AudioBuffer of length |sampleFrameLength| having a constant value
|
||||
// |constantValue|. If |constantValue| is a number, the buffer has one channel
|
||||
// filled with that value. If |constantValue| is an array, the buffer is created
|
||||
// wit a number of channels equal to the length of the array, and channel k is
|
||||
// filled with the k'th element of the |constantValue| array.
|
||||
function createConstantBuffer(context, sampleFrameLength, constantValue) {
|
||||
let channels;
|
||||
let values;
|
||||
|
||||
if (typeof constantValue === 'number') {
|
||||
channels = 1;
|
||||
values = [constantValue];
|
||||
} else {
|
||||
channels = constantValue.length;
|
||||
values = constantValue;
|
||||
}
|
||||
|
||||
let audioBuffer =
|
||||
context.createBuffer(channels, sampleFrameLength, context.sampleRate);
|
||||
let n = audioBuffer.length;
|
||||
|
||||
for (let c = 0; c < channels; ++c) {
|
||||
let data = audioBuffer.getChannelData(c);
|
||||
for (let i = 0; i < n; ++i)
|
||||
data[i] = values[c];
|
||||
}
|
||||
|
||||
return audioBuffer;
|
||||
}
|
||||
|
||||
// Create a stereo impulse in a buffer of length sampleFrameLength
|
||||
function createStereoImpulseBuffer(context, sampleFrameLength) {
|
||||
let audioBuffer =
|
||||
context.createBuffer(2, sampleFrameLength, context.sampleRate);
|
||||
let n = audioBuffer.length;
|
||||
let dataL = audioBuffer.getChannelData(0);
|
||||
let dataR = audioBuffer.getChannelData(1);
|
||||
|
||||
for (let k = 0; k < n; ++k) {
|
||||
dataL[k] = 0;
|
||||
dataR[k] = 0;
|
||||
}
|
||||
dataL[0] = 1;
|
||||
dataR[0] = 1;
|
||||
|
||||
return audioBuffer;
|
||||
}
|
||||
|
||||
// Convert time (in seconds) to sample frames.
|
||||
function timeToSampleFrame(time, sampleRate) {
|
||||
return Math.floor(0.5 + time * sampleRate);
|
||||
}
|
||||
|
||||
// Compute the number of sample frames consumed by noteGrainOn with
|
||||
// the specified |grainOffset|, |duration|, and |sampleRate|.
|
||||
function grainLengthInSampleFrames(grainOffset, duration, sampleRate) {
|
||||
let startFrame = timeToSampleFrame(grainOffset, sampleRate);
|
||||
let endFrame = timeToSampleFrame(grainOffset + duration, sampleRate);
|
||||
|
||||
return endFrame - startFrame;
|
||||
}
|
||||
|
||||
// True if the number is not an infinity or NaN
|
||||
function isValidNumber(x) {
|
||||
return !isNaN(x) && (x != Infinity) && (x != -Infinity);
|
||||
}
|
||||
|
||||
// Compute the (linear) signal-to-noise ratio between |actual| and
|
||||
// |expected|. The result is NOT in dB! If the |actual| and
|
||||
// |expected| have different lengths, the shorter length is used.
|
||||
function computeSNR(actual, expected) {
|
||||
let signalPower = 0;
|
||||
let noisePower = 0;
|
||||
|
||||
let length = Math.min(actual.length, expected.length);
|
||||
|
||||
for (let k = 0; k < length; ++k) {
|
||||
let diff = actual[k] - expected[k];
|
||||
signalPower += expected[k] * expected[k];
|
||||
noisePower += diff * diff;
|
||||
}
|
||||
|
||||
return signalPower / noisePower;
|
||||
}
|
1445
Tests/LibWeb/Text/input/wpt-import/webaudio/resources/audit.js
Normal file
1445
Tests/LibWeb/Text/input/wpt-import/webaudio/resources/audit.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,468 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test Constructor: Panner
|
||||
</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, 'PannerNode', context);
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.define('default constructor', (task, should) => {
|
||||
let prefix = 'node0';
|
||||
let node = testDefaultConstructor(should, 'PannerNode', context, {
|
||||
prefix: prefix,
|
||||
numberOfInputs: 1,
|
||||
numberOfOutputs: 1,
|
||||
channelCount: 2,
|
||||
channelCountMode: 'clamped-max',
|
||||
channelInterpretation: 'speakers'
|
||||
});
|
||||
|
||||
testDefaultAttributes(should, node, prefix, [
|
||||
{name: 'panningModel', value: 'equalpower'},
|
||||
{name: 'positionX', value: 0}, {name: 'positionY', value: 0},
|
||||
{name: 'positionZ', value: 0}, {name: 'orientationX', value: 1},
|
||||
{name: 'orientationY', value: 0}, {name: 'orientationZ', value: 0},
|
||||
{name: 'distanceModel', value: 'inverse'},
|
||||
{name: 'refDistance', value: 1}, {name: 'maxDistance', value: 10000},
|
||||
{name: 'rolloffFactor', value: 1},
|
||||
{name: 'coneInnerAngle', value: 360},
|
||||
{name: 'coneOuterAngle', value: 360},
|
||||
{name: 'coneOuterGain', value: 0}
|
||||
]);
|
||||
|
||||
// Test the listener too, while we're at it.
|
||||
let listenerAttributes = [
|
||||
{name: 'positionX', value: 0},
|
||||
{name: 'positionY', value: 0},
|
||||
{name: 'positionZ', value: 0},
|
||||
{name: 'forwardX', value: 0},
|
||||
{name: 'forwardY', value: 0},
|
||||
{name: 'forwardZ', value: -1},
|
||||
{name: 'upX', value: 0},
|
||||
{name: 'upY', value: 1},
|
||||
{name: 'upZ', value: 0},
|
||||
];
|
||||
|
||||
listenerAttributes.forEach((item) => {
|
||||
should(
|
||||
context.listener[item.name].value,
|
||||
'context.listener.' + item.name + '.value')
|
||||
.beEqualTo(item.value);
|
||||
});
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.define('test AudioNodeOptions', (task, should) => {
|
||||
// Can't use testAudioNodeOptions because the constraints for this node
|
||||
// are not supported there.
|
||||
let node;
|
||||
let success = true;
|
||||
|
||||
// Test that we can set the channel count to 1 or 2.
|
||||
let options = {channelCount: 1};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node1 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.channelCount, 'node1.channelCount')
|
||||
.beEqualTo(options.channelCount);
|
||||
|
||||
options = {channelCount: 2};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node2 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.channelCount, 'node2.channelCount')
|
||||
.beEqualTo(options.channelCount);
|
||||
|
||||
// Test that other channel counts throw an error
|
||||
options = {channelCount: 0};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(DOMException, 'NotSupportedError');
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.channelCount = options.channelCount;
|
||||
},
|
||||
`node.channelCount = ${options.channelCount}`)
|
||||
.throw(DOMException, "NotSupportedError");
|
||||
should(node.channelCount,
|
||||
`node.channelCount after setting to ${options.channelCount}`)
|
||||
.beEqualTo(2);
|
||||
|
||||
options = {channelCount: 3};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(DOMException, 'NotSupportedError');
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.channelCount = options.channelCount;
|
||||
},
|
||||
`node.channelCount = ${options.channelCount}`)
|
||||
.throw(DOMException, "NotSupportedError");
|
||||
should(node.channelCount,
|
||||
`node.channelCount after setting to ${options.channelCount}`)
|
||||
.beEqualTo(2);
|
||||
|
||||
options = {channelCount: 99};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(DOMException, 'NotSupportedError');
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.channelCount = options.channelCount;
|
||||
},
|
||||
`node.channelCount = ${options.channelCount}`)
|
||||
.throw(DOMException, "NotSupportedError");
|
||||
should(node.channelCount,
|
||||
`node.channelCount after setting to ${options.channelCount}`)
|
||||
.beEqualTo(2);
|
||||
|
||||
// Test channelCountMode. A mode of "max" is illegal, but others are
|
||||
// ok.
|
||||
options = {channelCountMode: 'clamped-max'};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node3 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.channelCountMode, 'node3.channelCountMode')
|
||||
.beEqualTo(options.channelCountMode);
|
||||
|
||||
options = {channelCountMode: 'explicit'};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node4 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.channelCountMode, 'node4.channelCountMode')
|
||||
.beEqualTo(options.channelCountMode);
|
||||
|
||||
options = {channelCountMode: 'max'};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(DOMException, 'NotSupportedError');
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.channelCountMode = options.channelCountMode;
|
||||
},
|
||||
`node.channelCountMode = ${options.channelCountMode}`)
|
||||
.throw(DOMException, "NotSupportedError");
|
||||
should(node.channelCountMode,
|
||||
`node.channelCountMode after setting to ${options.channelCountMode}`)
|
||||
.beEqualTo("clamped-max");
|
||||
|
||||
options = {channelCountMode: 'foobar'};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, " + JSON.stringify(options) + ")')
|
||||
.throw(TypeError);
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.channelCountMode = options.channelCountMode;
|
||||
},
|
||||
`node.channelCountMode = ${options.channelCountMode}`)
|
||||
.notThrow(); // Invalid assignment to enum-valued attrs does not throw.
|
||||
should(node.channelCountMode,
|
||||
`node.channelCountMode after setting to ${options.channelCountMode}`)
|
||||
.beEqualTo("clamped-max");
|
||||
|
||||
// Test channelInterpretation.
|
||||
options = {channelInterpretation: 'speakers'};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node5 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.channelInterpretation, 'node5.channelInterpretation')
|
||||
.beEqualTo(options.channelInterpretation);
|
||||
|
||||
options = {channelInterpretation: 'discrete'};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node6 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.channelInterpretation, 'node6.channelInterpretation')
|
||||
.beEqualTo(options.channelInterpretation);
|
||||
|
||||
options = {channelInterpretation: 'foobar'};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(TypeError);
|
||||
|
||||
// Test maxDistance
|
||||
options = {maxDistance: -1};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(RangeError);
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.maxDistance = options.maxDistance;
|
||||
},
|
||||
`node.maxDistance = ${options.maxDistance}`)
|
||||
.throw(RangeError);
|
||||
should(node.maxDistance,
|
||||
`node.maxDistance after setting to ${options.maxDistance}`)
|
||||
.beEqualTo(10000);
|
||||
|
||||
options = {maxDistance: 100};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node7 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.maxDistance, 'node7.maxDistance')
|
||||
.beEqualTo(options.maxDistance);
|
||||
|
||||
// Test rolloffFactor
|
||||
options = {rolloffFactor: -1};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(RangeError);
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.rolloffFactor = options.rolloffFactor;
|
||||
},
|
||||
`node.rolloffFactor = ${options.rolloffFactor}`)
|
||||
.throw(RangeError);
|
||||
should(node.rolloffFactor,
|
||||
`node.rolloffFactor after setting to ${options.rolloffFactor}`)
|
||||
.beEqualTo(1);
|
||||
|
||||
options = {rolloffFactor: 0};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node8 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.rolloffFactor, 'node8.rolloffFactor')
|
||||
.beEqualTo(options.rolloffFactor);
|
||||
|
||||
options = {rolloffFactor: 0.5};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node8 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.rolloffFactor, 'node8.rolloffFactor')
|
||||
.beEqualTo(options.rolloffFactor);
|
||||
|
||||
options = {rolloffFactor: 100};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node8 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.rolloffFactor, 'node8.rolloffFactor')
|
||||
.beEqualTo(options.rolloffFactor);
|
||||
|
||||
// Test coneOuterGain
|
||||
options = {coneOuterGain: -1};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(DOMException, 'InvalidStateError');
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.coneOuterGain = options.coneOuterGain;
|
||||
},
|
||||
`node.coneOuterGain = ${options.coneOuterGain}`)
|
||||
.throw(DOMException, 'InvalidStateError');
|
||||
should(node.coneOuterGain,
|
||||
`node.coneOuterGain after setting to ${options.coneOuterGain}`)
|
||||
.beEqualTo(0);
|
||||
|
||||
options = {coneOuterGain: 1.1};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.throw(DOMException, 'InvalidStateError');
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context);
|
||||
node.coneOuterGain = options.coneOuterGain;
|
||||
},
|
||||
`node.coneOuterGain = ${options.coneOuterGain}`)
|
||||
.throw(DOMException, 'InvalidStateError');
|
||||
should(node.coneOuterGain,
|
||||
`node.coneOuterGain after setting to ${options.coneOuterGain}`)
|
||||
.beEqualTo(0);
|
||||
|
||||
options = {coneOuterGain: 0.0};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node9 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.coneOuterGain, 'node9.coneOuterGain')
|
||||
.beEqualTo(options.coneOuterGain);
|
||||
options = {coneOuterGain: 0.5};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node9 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.coneOuterGain, 'node9.coneOuterGain')
|
||||
.beEqualTo(options.coneOuterGain);
|
||||
|
||||
options = {coneOuterGain: 1.0};
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node9 = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node.coneOuterGain, 'node9.coneOuterGain')
|
||||
.beEqualTo(options.coneOuterGain);
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.define('constructor with options', (task, should) => {
|
||||
let node;
|
||||
let success = true;
|
||||
let options = {
|
||||
panningModel: 'HRTF',
|
||||
// We use full double float values here to verify also that the actual
|
||||
// AudioParam value is properly rounded to a float. The actual value
|
||||
// is immaterial as long as x != Math.fround(x).
|
||||
positionX: Math.SQRT2,
|
||||
positionY: 2 * Math.SQRT2,
|
||||
positionZ: 3 * Math.SQRT2,
|
||||
orientationX: -Math.SQRT2,
|
||||
orientationY: -2 * Math.SQRT2,
|
||||
orientationZ: -3 * Math.SQRT2,
|
||||
distanceModel: 'linear',
|
||||
// We use full double float values here to verify also that the actual
|
||||
// attribute is a double float. The actual value is immaterial as
|
||||
// long as x != Math.fround(x).
|
||||
refDistance: Math.PI,
|
||||
maxDistance: 2 * Math.PI,
|
||||
rolloffFactor: 3 * Math.PI,
|
||||
coneInnerAngle: 4 * Math.PI,
|
||||
coneOuterAngle: 5 * Math.PI,
|
||||
coneOuterGain: 0.1 * Math.PI
|
||||
};
|
||||
|
||||
should(
|
||||
() => {
|
||||
node = new PannerNode(context, options);
|
||||
},
|
||||
'node = new PannerNode(c, ' + JSON.stringify(options) + ')')
|
||||
.notThrow();
|
||||
should(node instanceof PannerNode, 'node instanceof PannerNode')
|
||||
.beEqualTo(true);
|
||||
|
||||
should(node.panningModel, 'node.panningModel')
|
||||
.beEqualTo(options.panningModel);
|
||||
should(node.positionX.value, 'node.positionX.value')
|
||||
.beEqualTo(Math.fround(options.positionX));
|
||||
should(node.positionY.value, 'node.positionY.value')
|
||||
.beEqualTo(Math.fround(options.positionY));
|
||||
should(node.positionZ.value, 'node.positionZ.value')
|
||||
.beEqualTo(Math.fround(options.positionZ));
|
||||
should(node.orientationX.value, 'node.orientationX.value')
|
||||
.beEqualTo(Math.fround(options.orientationX));
|
||||
should(node.orientationY.value, 'node.orientationY.value')
|
||||
.beEqualTo(Math.fround(options.orientationY));
|
||||
should(node.orientationZ.value, 'node.orientationZ.value')
|
||||
.beEqualTo(Math.fround(options.orientationZ));
|
||||
should(node.distanceModel, 'node.distanceModel')
|
||||
.beEqualTo(options.distanceModel);
|
||||
should(node.refDistance, 'node.refDistance')
|
||||
.beEqualTo(options.refDistance);
|
||||
should(node.maxDistance, 'node.maxDistance')
|
||||
.beEqualTo(options.maxDistance);
|
||||
should(node.rolloffFactor, 'node.rolloffFactor')
|
||||
.beEqualTo(options.rolloffFactor);
|
||||
should(node.coneInnerAngle, 'node.coneInnerAngle')
|
||||
.beEqualTo(options.coneInnerAngle);
|
||||
should(node.coneOuterAngle, 'node.coneOuterAngle')
|
||||
.beEqualTo(options.coneOuterAngle);
|
||||
should(node.coneOuterGain, 'node.coneOuterGain')
|
||||
.beEqualTo(options.coneOuterGain);
|
||||
|
||||
should(node.channelCount, 'node.channelCount').beEqualTo(2);
|
||||
should(node.channelCountMode, 'node.channelCountMode')
|
||||
.beEqualTo('clamped-max');
|
||||
should(node.channelInterpretation, 'node.channelInterpretation')
|
||||
.beEqualTo('speakers');
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue