This commit is contained in:
Tim Ledbetter 2025-01-02 11:45:49 +00:00 committed by GitHub
commit eb8b38a876
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 197 additions and 1 deletions

View file

@ -793,6 +793,7 @@ set(SOURCES
WebAudio/BaseAudioContext.cpp
WebAudio/BiquadFilterNode.cpp
WebAudio/ChannelMergerNode.cpp
WebAudio/ConstantSourceNode.cpp
WebAudio/ChannelSplitterNode.cpp
WebAudio/DynamicsCompressorNode.cpp
WebAudio/GainNode.cpp

View file

@ -91,6 +91,12 @@ WebIDL::ExceptionOr<GC::Ref<ChannelMergerNode>> BaseAudioContext::create_channel
return ChannelMergerNode::create(realm(), *this, options);
}
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createconstantsource
WebIDL::ExceptionOr<GC::Ref<ConstantSourceNode>> BaseAudioContext::create_constant_source()
{
return ConstantSourceNode::create(realm(), *this);
}
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createchannelsplitter
WebIDL::ExceptionOr<GC::Ref<ChannelSplitterNode>> BaseAudioContext::create_channel_splitter(WebIDL::UnsignedLong number_of_outputs)
{

View file

@ -13,6 +13,7 @@
#include <LibWeb/WebAudio/AudioListener.h>
#include <LibWeb/WebAudio/BiquadFilterNode.h>
#include <LibWeb/WebAudio/ChannelMergerNode.h>
#include <LibWeb/WebAudio/ConstantSourceNode.h>
#include <LibWeb/WebAudio/ChannelSplitterNode.h>
#include <LibWeb/WebIDL/Types.h>
@ -60,6 +61,7 @@ public:
WebIDL::ExceptionOr<GC::Ref<AudioBuffer>> create_buffer(WebIDL::UnsignedLong number_of_channels, WebIDL::UnsignedLong length, float sample_rate);
WebIDL::ExceptionOr<GC::Ref<AudioBufferSourceNode>> create_buffer_source();
WebIDL::ExceptionOr<GC::Ref<ChannelMergerNode>> create_channel_merger(WebIDL::UnsignedLong number_of_inputs);
WebIDL::ExceptionOr<GC::Ref<ConstantSourceNode>> create_constant_source();
WebIDL::ExceptionOr<GC::Ref<ChannelSplitterNode>> create_channel_splitter(WebIDL::UnsignedLong number_of_outputs);
WebIDL::ExceptionOr<GC::Ref<OscillatorNode>> create_oscillator();
WebIDL::ExceptionOr<GC::Ref<DynamicsCompressorNode>> create_dynamics_compressor();

View file

@ -36,7 +36,7 @@ interface BaseAudioContext : EventTarget {
AudioBufferSourceNode createBufferSource ();
ChannelMergerNode createChannelMerger (optional unsigned long numberOfInputs = 6);
ChannelSplitterNode createChannelSplitter (optional unsigned long numberOfOutputs = 6);
[FIXME] ConstantSourceNode createConstantSource ();
ConstantSourceNode createConstantSource ();
[FIXME] ConvolverNode createConvolver ();
[FIXME] DelayNode createDelay (optional double maxDelayTime = 1.0);
DynamicsCompressorNode createDynamicsCompressor();

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/NumericLimits.h>
#include <LibWeb/Bindings/ConstantSourceNodePrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/WebAudio/BaseAudioContext.h>
#include <LibWeb/WebAudio/ConstantSourceNode.h>
namespace Web::WebAudio {
GC_DEFINE_ALLOCATOR(ConstantSourceNode);
ConstantSourceNode::ConstantSourceNode(JS::Realm& realm, GC::Ref<BaseAudioContext> context, ConstantSourceOptions const& options)
: AudioScheduledSourceNode(realm, context)
, m_offset(AudioParam::create(realm, options.offset, NumericLimits<float>::lowest(), NumericLimits<float>::max(), Bindings::AutomationRate::ARate))
{
}
ConstantSourceNode::~ConstantSourceNode() = default;
WebIDL::ExceptionOr<GC::Ref<ConstantSourceNode>> ConstantSourceNode::create(JS::Realm& realm, GC::Ref<BaseAudioContext> context, ConstantSourceOptions const& options)
{
return construct_impl(realm, context, options);
}
WebIDL::ExceptionOr<GC::Ref<ConstantSourceNode>> ConstantSourceNode::construct_impl(JS::Realm& realm, GC::Ref<BaseAudioContext> context, ConstantSourceOptions const& options)
{
return realm.create<ConstantSourceNode>(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);
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/WebAudio/AudioScheduledSourceNode.h>
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<GC::Ref<ConstantSourceNode>> create(JS::Realm&, GC::Ref<BaseAudioContext>, ConstantSourceOptions const& = {});
static WebIDL::ExceptionOr<GC::Ref<ConstantSourceNode>> construct_impl(JS::Realm&, GC::Ref<BaseAudioContext>, ConstantSourceOptions const& = {});
virtual WebIDL::UnsignedLong number_of_inputs() override { return 0; }
virtual WebIDL::UnsignedLong number_of_outputs() override { return 1; }
GC::Ref<AudioParam const> offset() const { return m_offset; }
private:
ConstantSourceNode(JS::Realm&, GC::Ref<BaseAudioContext>, 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<AudioParam> m_offset;
};
}

View file

@ -0,0 +1,15 @@
#import <WebAudio/AudioNode.idl>
#import <WebAudio/AudioParam.idl>
#import <WebAudio/BaseAudioContext.idl>
// 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;
};

View file

@ -370,6 +370,7 @@ libweb_js_bindings(WebAudio/BiquadFilterNode)
libweb_js_bindings(WebAudio/DynamicsCompressorNode)
libweb_js_bindings(WebAudio/GainNode)
libweb_js_bindings(WebAudio/ChannelMergerNode)
libweb_js_bindings(WebAudio/ConstantSourceNode)
libweb_js_bindings(WebAudio/ChannelSplitterNode)
libweb_js_bindings(WebAudio/OfflineAudioContext)
libweb_js_bindings(WebAudio/OscillatorNode)

View file

@ -67,6 +67,7 @@ CloseWatcher
Comment
CompositionEvent
CompressionStream
ConstantSourceNode
CountQueuingStrategy
Crypto
CryptoKey

View file

@ -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.

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<title>
Test Constructor: ConstantSource
</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, 'ConstantSourceNode', context);
task.done();
});
audit.define('default constructor', (task, should) => {
let prefix = 'node0';
let node =
testDefaultConstructor(should, 'ConstantSourceNode', context, {
prefix: prefix,
numberOfInputs: 0,
numberOfOutputs: 1,
channelCount: 2,
channelCountMode: 'max',
channelInterpretation: 'speakers'
});
testDefaultAttributes(
should, node, prefix, [{name: 'offset', value: 1}]);
task.done();
});
audit.run();
</script>
</body>
</html>