diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/WebAudio/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/WebAudio/BUILD.gn index d5fbc36d492..f0ee11e4c15 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/WebAudio/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/WebAudio/BUILD.gn @@ -18,6 +18,8 @@ source_set("WebAudio") { "AudioScheduledSourceNode.h", "BaseAudioContext.cpp", "BaseAudioContext.h", + "BiquadFilterNode.cpp", + "BiquadFilterNode.h", "DynamicsCompressorNode.cpp", "DynamicsCompressorNode.h", "GainNode.cpp", diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni index 9e6e5dfc31a..0530fe4ba15 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni @@ -325,6 +325,7 @@ standard_idl_files = [ "//Userland/Libraries/LibWeb/WebAudio/AudioParam.idl", "//Userland/Libraries/LibWeb/WebAudio/AudioScheduledSourceNode.idl", "//Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.idl", + "//Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.idl", "//Userland/Libraries/LibWeb/WebAudio/DynamicsCompressorNode.idl", "//Userland/Libraries/LibWeb/WebAudio/GainNode.idl", "//Userland/Libraries/LibWeb/WebAudio/OfflineAudioContext.idl", diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 0878d5d36ca..27764aa1bb8 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -688,6 +688,7 @@ set(SOURCES WebAudio/AudioParam.cpp WebAudio/AudioScheduledSourceNode.cpp WebAudio/BaseAudioContext.cpp + WebAudio/BiquadFilterNode.cpp WebAudio/DynamicsCompressorNode.cpp WebAudio/GainNode.cpp WebAudio/OfflineAudioContext.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 720cbb2fcdf..c4a3abb6fe7 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -717,6 +717,7 @@ class AudioNode; class AudioParam; class AudioScheduledSourceNode; class BaseAudioContext; +class BiquadFilterNode; class DynamicsCompressorNode; class GainNode; class OfflineAudioContext; diff --git a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp index c6eef658501..b5d5693783f 100644 --- a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp +++ b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,13 @@ WebIDL::CallbackType* BaseAudioContext::onstatechange() return event_handler_attribute(HTML::EventNames::statechange); } +// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbiquadfilter +WebIDL::ExceptionOr> BaseAudioContext::create_biquad_filter() +{ + // Factory method for a BiquadFilterNode representing a second order filter which can be configured as one of several common filter types. + return BiquadFilterNode::create(realm(), *this); +} + // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer WebIDL::ExceptionOr> BaseAudioContext::create_buffer(WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate) { diff --git a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h index 2bd927991d5..a11f13ce1bb 100644 --- a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h +++ b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.h @@ -9,6 +9,7 @@ #include #include +#include #include namespace Web::WebAudio { @@ -47,6 +48,7 @@ public: static WebIDL::ExceptionOr verify_audio_options_inside_nominal_range(JS::Realm&, WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate); + WebIDL::ExceptionOr> create_biquad_filter(); WebIDL::ExceptionOr> create_buffer(WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate); WebIDL::ExceptionOr> create_buffer_source(); WebIDL::ExceptionOr> create_oscillator(); diff --git a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.idl b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.idl index 6a358c54eb4..c28c3915760 100644 --- a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.idl +++ b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.idl @@ -26,7 +26,7 @@ interface BaseAudioContext : EventTarget { attribute EventHandler onstatechange; [FIXME] AnalyserNode createAnalyser (); - [FIXME] BiquadFilterNode createBiquadFilter (); + BiquadFilterNode createBiquadFilter (); AudioBuffer createBuffer(unsigned long numberOfChannels, unsigned long length, float sampleRate); AudioBufferSourceNode createBufferSource (); [FIXME] ChannelMergerNode createChannelMerger (optional unsigned long numberOfInputs = 6); diff --git a/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.cpp b/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.cpp new file mode 100644 index 00000000000..8c49b7fd086 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, Bar Yemini + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Web::WebAudio { + +JS_DEFINE_ALLOCATOR(BiquadFilterNode); + +BiquadFilterNode::BiquadFilterNode(JS::Realm& realm, JS::NonnullGCPtr context, BiquadFilterOptions const&) + : AudioNode(realm, context) +{ +} + +BiquadFilterNode::~BiquadFilterNode() = default; + +WebIDL::ExceptionOr> BiquadFilterNode::create(JS::Realm& realm, JS::NonnullGCPtr context, BiquadFilterOptions const& options) +{ + return construct_impl(realm, context, options); +} + +// https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-biquadfilternode +WebIDL::ExceptionOr> BiquadFilterNode::construct_impl(JS::Realm& realm, JS::NonnullGCPtr context, BiquadFilterOptions const& options) +{ + // When the constructor is called with a BaseAudioContext c and an option object option, the user agent + // MUST initialize the AudioNode this, with context and options as arguments. + + auto node = realm.vm().heap().allocate(realm, realm, context, options); + return node; +} + +void BiquadFilterNode::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + WEB_SET_PROTOTYPE_FOR_INTERFACE(BiquadFilterNode); +} + +void BiquadFilterNode::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); +} + +} diff --git a/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.h b/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.h new file mode 100644 index 00000000000..abcafa07289 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024, Bar Yemini + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::WebAudio { + +// https://webaudio.github.io/web-audio-api/#BiquadFilterOptions +struct BiquadFilterOptions : AudioNodeOptions { + Bindings::BiquadFilterType type { Bindings::BiquadFilterType::Lowpass }; + float q { 1 }; + float detune { 0 }; + float frequency { 350 }; + float gain { 0 }; +}; + +// https://webaudio.github.io/web-audio-api/#BiquadFilterNode +class BiquadFilterNode : public AudioNode { + WEB_PLATFORM_OBJECT(BiquadFilterNode, AudioNode); + JS_DECLARE_ALLOCATOR(BiquadFilterNode); + +public: + virtual ~BiquadFilterNode() override; + + static WebIDL::ExceptionOr> create(JS::Realm&, JS::NonnullGCPtr, BiquadFilterOptions const& = {}); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, JS::NonnullGCPtr, BiquadFilterOptions const& = {}); + +protected: + BiquadFilterNode(JS::Realm&, JS::NonnullGCPtr, BiquadFilterOptions const& = {}); + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Cell::Visitor&) override; +}; + +} diff --git a/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.idl b/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.idl new file mode 100644 index 00000000000..e7810dc844c --- /dev/null +++ b/Userland/Libraries/LibWeb/WebAudio/BiquadFilterNode.idl @@ -0,0 +1,33 @@ +#import +#import +#import + +enum BiquadFilterType { + "lowpass", + "highpass", + "bandpass", + "lowshelf", + "highshelf", + "peaking", + "notch", + "allpass" +}; + +dictionary BiquadFilterOptions : AudioNodeOptions { + BiquadFilterType type = "lowpass"; + float Q = 1; + float detune = 0; + float frequency = 350; + float gain = 0; +}; + +[Exposed=Window] +interface BiquadFilterNode : AudioNode { + constructor (BaseAudioContext context, optional BiquadFilterOptions options = {}); + [FIXME] attribute BiquadFilterType type; + [FIXME] readonly attribute AudioParam frequency; + [FIXME] readonly attribute AudioParam detune; + [FIXME] readonly attribute AudioParam Q; + [FIXME] readonly attribute AudioParam gain; + [FIXME] undefined getFrequencyResponse (Float32Array frequencyHz, Float32Array magResponse, Float32Array phaseResponse); +}; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 0fcfbece629..e1a691146c6 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -316,6 +316,7 @@ libweb_js_bindings(WebAudio/AudioNode) libweb_js_bindings(WebAudio/AudioParam) libweb_js_bindings(WebAudio/AudioScheduledSourceNode) libweb_js_bindings(WebAudio/BaseAudioContext) +libweb_js_bindings(WebAudio/BiquadFilterNode) libweb_js_bindings(WebAudio/DynamicsCompressorNode) libweb_js_bindings(WebAudio/GainNode) libweb_js_bindings(WebAudio/OfflineAudioContext)