LibWeb: Initialize AudioBufferSourceNode with correct defaults

This commit is contained in:
Tim Ledbetter 2025-01-04 02:21:16 +00:00 committed by Tim Ledbetter
commit a6ab9cc983
Notes: github-actions[bot] 2025-01-08 14:46:56 +00:00
4 changed files with 178 additions and 2 deletions

View file

@ -129,6 +129,17 @@ WebIDL::ExceptionOr<GC::Ref<AudioBufferSourceNode>> AudioBufferSourceNode::const
// MUST initialize the AudioNode this, with context and options as arguments.
auto node = realm.create<AudioBufferSourceNode>(realm, context, options);
// Default options for channel count and interpretation
// https://webaudio.github.io/web-audio-api/#AudioBufferSourceNode
AudioNodeDefaultOptions default_options;
default_options.channel_count = 2;
default_options.channel_count_mode = Bindings::ChannelCountMode::Max;
default_options.channel_interpretation = Bindings::ChannelInterpretation::Speakers;
// FIXME: Set tail-time to no
TRY(node->initialize_audio_node_options(options, default_options));
return node;
}

View file

@ -14,7 +14,7 @@
namespace Web::WebAudio {
// https://webaudio.github.io/web-audio-api/#AudioBufferSourceOptions
struct AudioBufferSourceOptions {
struct AudioBufferSourceOptions : AudioNodeOptions {
GC::Ptr<AudioBuffer> buffer;
float detune { 0 };
bool loop { false };
@ -42,7 +42,7 @@ public:
WebIDL::ExceptionOr<void> set_loop_end(double);
double loop_end() const;
WebIDL::UnsignedLong number_of_inputs() override { return 0; }
WebIDL::UnsignedLong number_of_outputs() override { return 2; }
WebIDL::UnsignedLong number_of_outputs() override { return 1; }
WebIDL::ExceptionOr<void> start(Optional<double>, Optional<double>, Optional<double>);

View file

@ -0,0 +1,49 @@
Harness status: OK
Found 44 tests
44 Pass
Pass # AUDIT TASK RUNNER STARTED.
Pass Executing "initialize"
Pass Executing "invalid constructor"
Pass Executing "default constructor"
Pass Executing "nullable buffer"
Pass Executing "constructor 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 AudioBufferSourceNode() threw TypeError: "AudioBufferSourceNode() needs one argument".
Pass new AudioBufferSourceNode(1) threw TypeError: "Not an object of type BaseAudioContext".
Pass new AudioBufferSourceNode(context, 42) threw TypeError: "Not an object of type AudioBufferSourceOptions".
Pass < [invalid constructor] All assertions passed. (total 3 assertions)
Pass > [default constructor]
Pass node0 = new AudioBufferSourceNode(context) did not throw an exception.
Pass node0 instanceof AudioBufferSourceNode is equal to true.
Pass node0.numberOfInputs is equal to 0.
Pass node0.numberOfOutputs is equal to 1.
Pass node0.channelCount is equal to 2.
Pass node0.channelCountMode is equal to max.
Pass node0.channelInterpretation is equal to speakers.
Pass node0.buffer is equal to null.
Pass node0.detune.value is equal to 0.
Pass node0.loop is equal to false.
Pass node0.loopEnd is equal to 0.
Pass node0.loopStart is equal to 0.
Pass node0.playbackRate.value is equal to 1.
Pass < [default constructor] All assertions passed. (total 13 assertions)
Pass > [nullable buffer]
Pass node1 = new AudioBufferSourceNode(c, {"buffer":null} did not throw an exception.
Pass node1.buffer is equal to null.
Pass < [nullable buffer] All assertions passed. (total 2 assertions)
Pass > [constructor options]
Pass node = new AudioBufferSourceNode(c, {"buffer":{},"detune":0.5,"loop":true,"loopEnd":0.010416666666666666,"loopStart":0.00010416666666666667,"playbackRate":0.75}) did not throw an exception.
Pass node2.buffer === buffer is equal to true.
Pass node2.detune.value is equal to 0.5.
Pass node2.loop is equal to true.
Pass node2.loopEnd is equal to 0.010416666666666666.
Pass node2.loopStart is equal to 0.00010416666666666667.
Pass node2.playbackRate.value is equal to 0.75.
Pass < [constructor options] All assertions passed. (total 7 assertions)
Pass # AUDIT TASK RUNNER FINISHED: 5 tasks ran successfully.

View file

@ -0,0 +1,116 @@
<!DOCTYPE html>
<html>
<head>
<title>
Test Constructor: AudioBufferSource
</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, 'AudioBufferSourceNode', context);
task.done();
});
audit.define('default constructor', (task, should) => {
let prefix = 'node0';
let node =
testDefaultConstructor(should, 'AudioBufferSourceNode', context, {
prefix: prefix,
numberOfInputs: 0,
numberOfOutputs: 1,
channelCount: 2,
channelCountMode: 'max',
channelInterpretation: 'speakers'
});
testDefaultAttributes(should, node, prefix, [
{name: 'buffer', value: null},
{name: 'detune', value: 0},
{name: 'loop', value: false},
{name: 'loopEnd', value: 0.0},
{name: 'loopStart', value: 0.0},
{name: 'playbackRate', value: 1.0},
]);
task.done();
});
audit.define('nullable buffer', (task, should) => {
let node;
let options = {buffer: null};
should(
() => {
node = new AudioBufferSourceNode(context, options);
},
'node1 = new AudioBufferSourceNode(c, ' + JSON.stringify(options))
.notThrow();
should(node.buffer, 'node1.buffer').beEqualTo(null);
task.done();
});
audit.define('constructor options', (task, should) => {
let node;
let buffer = context.createBuffer(2, 1000, context.sampleRate);
let options = {
buffer: buffer,
detune: .5,
loop: true,
loopEnd: (buffer.length / 2) / context.sampleRate,
loopStart: 5 / context.sampleRate,
playbackRate: .75
};
let message = 'node = new AudioBufferSourceNode(c, ' +
JSON.stringify(options) + ')';
should(() => {
node = new AudioBufferSourceNode(context, options);
}, message).notThrow();
// Use the factory method to create an equivalent node and compare the
// results from the constructor against this node.
let factoryNode = context.createBufferSource();
factoryNode.buffer = options.buffer;
factoryNode.detune.value = options.detune;
factoryNode.loop = options.loop;
factoryNode.loopEnd = options.loopEnd;
factoryNode.loopStart = options.loopStart;
factoryNode.playbackRate.value = options.playbackRate;
should(node.buffer === buffer, 'node2.buffer === buffer')
.beEqualTo(true);
should(node.detune.value, 'node2.detune.value')
.beEqualTo(factoryNode.detune.value);
should(node.loop, 'node2.loop').beEqualTo(factoryNode.loop);
should(node.loopEnd, 'node2.loopEnd').beEqualTo(factoryNode.loopEnd);
should(node.loopStart, 'node2.loopStart')
.beEqualTo(factoryNode.loopStart);
should(node.playbackRate.value, 'node2.playbackRate.value')
.beEqualTo(factoryNode.playbackRate.value);
task.done();
});
audit.run();
</script>
</body>
</html>