diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 8da4cbb79e8..04fbefa92af 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -794,6 +794,7 @@ set(SOURCES WebAudio/BiquadFilterNode.cpp WebAudio/ChannelMergerNode.cpp WebAudio/ChannelSplitterNode.cpp + WebAudio/ConstantSourceNode.cpp WebAudio/DynamicsCompressorNode.cpp WebAudio/GainNode.cpp WebAudio/OfflineAudioContext.cpp diff --git a/Libraries/LibWeb/WebAudio/ConstantSourceNode.cpp b/Libraries/LibWeb/WebAudio/ConstantSourceNode.cpp new file mode 100644 index 00000000000..bcf5f72c796 --- /dev/null +++ b/Libraries/LibWeb/WebAudio/ConstantSourceNode.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, Tim Ledbetter + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace Web::WebAudio { + +GC_DEFINE_ALLOCATOR(ConstantSourceNode); + +ConstantSourceNode::ConstantSourceNode(JS::Realm& realm, GC::Ref context, ConstantSourceOptions const& options) + : AudioScheduledSourceNode(realm, context) + , m_offset(AudioParam::create(realm, options.offset, NumericLimits::lowest(), NumericLimits::max(), Bindings::AutomationRate::ARate)) +{ +} + +ConstantSourceNode::~ConstantSourceNode() = default; + +WebIDL::ExceptionOr> ConstantSourceNode::create(JS::Realm& realm, GC::Ref context, ConstantSourceOptions const& options) +{ + return construct_impl(realm, context, options); +} + +WebIDL::ExceptionOr> ConstantSourceNode::construct_impl(JS::Realm& realm, GC::Ref context, ConstantSourceOptions const& options) +{ + return realm.create(realm, context, options); +} + +void ConstantSourceNode::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + WEB_SET_PROTOTYPE_FOR_INTERFACE(ConstantSourceNode); +} + +void ConstantSourceNode::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_offset); +} + +} diff --git a/Libraries/LibWeb/WebAudio/ConstantSourceNode.h b/Libraries/LibWeb/WebAudio/ConstantSourceNode.h new file mode 100644 index 00000000000..0404a858d7a --- /dev/null +++ b/Libraries/LibWeb/WebAudio/ConstantSourceNode.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025, Tim Ledbetter + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::WebAudio { + +// https://webaudio.github.io/web-audio-api/#ChannelMergerOptions +struct ConstantSourceOptions : AudioNodeOptions { + float offset { 1.0f }; +}; + +// https://webaudio.github.io/web-audio-api/#ChannelMergerNode +class ConstantSourceNode final : public AudioScheduledSourceNode { + WEB_PLATFORM_OBJECT(ConstantSourceNode, AudioScheduledSourceNode); + GC_DECLARE_ALLOCATOR(ConstantSourceNode); + +public: + virtual ~ConstantSourceNode() override; + + static WebIDL::ExceptionOr> create(JS::Realm&, GC::Ref, ConstantSourceOptions const& = {}); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, GC::Ref, ConstantSourceOptions const& = {}); + + virtual WebIDL::UnsignedLong number_of_inputs() override { return 0; } + virtual WebIDL::UnsignedLong number_of_outputs() override { return 1; } + + GC::Ref offset() const { return m_offset; } + +private: + ConstantSourceNode(JS::Realm&, GC::Ref, ConstantSourceOptions const&); + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Cell::Visitor&) override; + + // https://webaudio.github.io/web-audio-api/#dom-constantsourcenode-offset + GC::Ref m_offset; +}; + +} diff --git a/Libraries/LibWeb/WebAudio/ConstantSourceNode.idl b/Libraries/LibWeb/WebAudio/ConstantSourceNode.idl new file mode 100644 index 00000000000..4846aae6298 --- /dev/null +++ b/Libraries/LibWeb/WebAudio/ConstantSourceNode.idl @@ -0,0 +1,15 @@ +#import +#import +#import + +// https://webaudio.github.io/web-audio-api/#ConstantSourceOptions +dictionary ConstantSourceOptions { + float offset = 1; +}; + +// https://webaudio.github.io/web-audio-api/#ConstantSourceNode +[Exposed=Window] +interface ConstantSourceNode : AudioScheduledSourceNode { + constructor (BaseAudioContext context, optional ConstantSourceOptions options = {}); + readonly attribute AudioParam offset; +}; diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 8c06aa588ff..1ae9fe7b0b1 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -371,6 +371,7 @@ libweb_js_bindings(WebAudio/DynamicsCompressorNode) libweb_js_bindings(WebAudio/GainNode) libweb_js_bindings(WebAudio/ChannelMergerNode) libweb_js_bindings(WebAudio/ChannelSplitterNode) +libweb_js_bindings(WebAudio/ConstantSourceNode) libweb_js_bindings(WebAudio/OfflineAudioContext) libweb_js_bindings(WebAudio/OscillatorNode) libweb_js_bindings(WebAudio/PannerNode) diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 224db943aba..43078762a67 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -67,6 +67,7 @@ CloseWatcher Comment CompositionEvent CompressionStream +ConstantSourceNode CountQueuingStrategy Crypto CryptoKey diff --git a/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.txt b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.txt new file mode 100644 index 00000000000..19e8388df02 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.txt @@ -0,0 +1,29 @@ +Harness status: OK + +Found 24 tests + +24 Pass +Pass # AUDIT TASK RUNNER STARTED. +Pass Executing "initialize" +Pass Executing "invalid constructor" +Pass Executing "default constructor" +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 ConstantSourceNode() threw TypeError: "ConstantSourceNode() needs one argument". +Pass new ConstantSourceNode(1) threw TypeError: "Not an object of type BaseAudioContext". +Pass new ConstantSourceNode(context, 42) threw TypeError: "Not an object of type ConstantSourceOptions". +Pass < [invalid constructor] All assertions passed. (total 3 assertions) +Pass > [default constructor] +Pass node0 = new ConstantSourceNode(context) did not throw an exception. +Pass node0 instanceof ConstantSourceNode 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.offset.value is equal to 1. +Pass < [default constructor] All assertions passed. (total 8 assertions) +Pass # AUDIT TASK RUNNER FINISHED: 3 tasks ran successfully. \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.html b/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.html new file mode 100644 index 00000000000..771dbdbd5a1 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/webaudio/the-audio-api/the-constantsourcenode-interface/ctor-constantsource.html @@ -0,0 +1,50 @@ + + + + + Test Constructor: ConstantSource + + + + + + + + + + +