mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-04 15:19:42 +00:00
LibWeb: Use correct ranges for BiquadFilterNode
parameters
This commit is contained in:
parent
423d106fd8
commit
e469c884d4
Notes:
github-actions[bot]
2025-01-08 19:06:47 +00:00
Author: https://github.com/tcl3
Commit: e469c884d4
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3127
4 changed files with 818 additions and 3 deletions
|
@ -4,11 +4,13 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Math.h>
|
||||
#include <LibWeb/Bindings/AudioParamPrototype.h>
|
||||
#include <LibWeb/Bindings/BiquadFilterNodePrototype.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/WebAudio/AudioNode.h>
|
||||
#include <LibWeb/WebAudio/AudioParam.h>
|
||||
#include <LibWeb/WebAudio/BaseAudioContext.h>
|
||||
#include <LibWeb/WebAudio/BiquadFilterNode.h>
|
||||
|
||||
namespace Web::WebAudio {
|
||||
|
@ -18,10 +20,10 @@ GC_DEFINE_ALLOCATOR(BiquadFilterNode);
|
|||
BiquadFilterNode::BiquadFilterNode(JS::Realm& realm, GC::Ref<BaseAudioContext> context, BiquadFilterOptions const& options)
|
||||
: AudioNode(realm, context)
|
||||
, m_type(options.type)
|
||||
, m_frequency(AudioParam::create(realm, options.frequency, NumericLimits<float>::lowest(), NumericLimits<float>::max(), Bindings::AutomationRate::ARate))
|
||||
, m_detune(AudioParam::create(realm, options.detune, NumericLimits<float>::lowest(), NumericLimits<float>::max(), Bindings::AutomationRate::ARate))
|
||||
, m_frequency(AudioParam::create(realm, options.frequency, 0, context->nyquist_frequency(), Bindings::AutomationRate::ARate))
|
||||
, m_detune(AudioParam::create(realm, options.detune, -1200 * AK::log2(NumericLimits<float>::max()), 1200 * AK::log2(NumericLimits<float>::max()), Bindings::AutomationRate::ARate))
|
||||
, m_q(AudioParam::create(realm, options.q, NumericLimits<float>::lowest(), NumericLimits<float>::max(), Bindings::AutomationRate::ARate))
|
||||
, m_gain(AudioParam::create(realm, options.gain, NumericLimits<float>::lowest(), NumericLimits<float>::max(), Bindings::AutomationRate::ARate))
|
||||
, m_gain(AudioParam::create(realm, options.gain, NumericLimits<float>::lowest(), 40 * AK::log10(NumericLimits<float>::max()), Bindings::AutomationRate::ARate))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -51,9 +51,17 @@ protected:
|
|||
|
||||
private:
|
||||
Bindings::BiquadFilterType m_type { Bindings::BiquadFilterType::Lowpass };
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-frequency
|
||||
GC::Ref<AudioParam> m_frequency;
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-detune
|
||||
GC::Ref<AudioParam> m_detune;
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-q
|
||||
GC::Ref<AudioParam> m_q;
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-gain
|
||||
GC::Ref<AudioParam> m_gain;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 302 tests
|
||||
|
||||
291 Pass
|
||||
11 Fail
|
||||
Pass # AUDIT TASK RUNNER STARTED.
|
||||
Pass Executing "initialize"
|
||||
Pass Executing "Offline createGain"
|
||||
Pass Executing "Offline createDelay"
|
||||
Pass Executing "Offline createBufferSource"
|
||||
Fail Executing "Offline createStereoPanner"
|
||||
Pass Executing "Offline createDynamicsCompressor"
|
||||
Pass Executing "Offline createBiquadFilter"
|
||||
Pass Executing "Offline createOscillator"
|
||||
Pass Executing "Offline createPanner"
|
||||
Pass Executing "Offline createConstantSource"
|
||||
Pass Executing "Offline createBuffer"
|
||||
Fail Executing "Offline createIIRFilter"
|
||||
Fail Executing "Offline createWaveShaper"
|
||||
Fail Executing "Offline createConvolver"
|
||||
Fail Executing "Offline createAnalyser"
|
||||
Fail Executing "Offline createScriptProcessor"
|
||||
Pass Executing "Offline createPeriodicWave"
|
||||
Pass Executing "Offline createChannelSplitter"
|
||||
Pass Executing "Offline createChannelMerger"
|
||||
Fail Executing "Online createMediaElementSource"
|
||||
Fail Executing "Online createMediaStreamDestination"
|
||||
Pass Executing "AudioListener"
|
||||
Pass Executing "verifyTests"
|
||||
Pass Executing "automation"
|
||||
Pass Audit report
|
||||
Pass > [initialize]
|
||||
Pass Create offline context for tests did not throw an exception.
|
||||
Pass Create online context for tests did not throw an exception.
|
||||
Pass < [initialize] All assertions passed. (total 2 assertions)
|
||||
Pass > [Offline createGain]
|
||||
Pass GainNode.gain.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass GainNode.gain.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass GainNode.gain.minValue = 42 is not equal to 42.
|
||||
Pass GainNode.gain.minValue is read-only is equal to true.
|
||||
Pass GainNode.gain.maxValue = 42 is not equal to 42.
|
||||
Pass GainNode.gain.maxValue is read-only is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of GainNode are correct
|
||||
Pass < [Offline createGain] All assertions passed. (total 7 assertions)
|
||||
Pass > [Offline createDelay]
|
||||
Pass DelayNode.delayTime.minValue is equal to 0.
|
||||
Pass DelayNode.delayTime.maxValue is equal to 1.5.
|
||||
Pass DelayNode.delayTime.minValue = 42 is not equal to 42.
|
||||
Pass DelayNode.delayTime.minValue is read-only is equal to true.
|
||||
Pass DelayNode.delayTime.maxValue = 42 is not equal to 42.
|
||||
Pass DelayNode.delayTime.maxValue is read-only is equal to true.
|
||||
Pass Set DelayNode.delayTime.value = -1 is equal to 0.
|
||||
Pass Set DelayNode.delayTime.value = 4 is equal to 1.5.
|
||||
Pass DelayNode.delayTime was clipped to lie within the nominal range is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of DelayNode are correct
|
||||
Pass < [Offline createDelay] All assertions passed. (total 10 assertions)
|
||||
Pass > [Offline createBufferSource]
|
||||
Pass AudioBufferSourceNode.playbackRate.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioBufferSourceNode.playbackRate.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioBufferSourceNode.playbackRate.minValue = 42 is not equal to 42.
|
||||
Pass AudioBufferSourceNode.playbackRate.minValue is read-only is equal to true.
|
||||
Pass AudioBufferSourceNode.playbackRate.maxValue = 42 is not equal to 42.
|
||||
Pass AudioBufferSourceNode.playbackRate.maxValue is read-only is equal to true.
|
||||
Pass AudioBufferSourceNode.detune.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioBufferSourceNode.detune.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioBufferSourceNode.detune.minValue = 42 is not equal to 42.
|
||||
Pass AudioBufferSourceNode.detune.minValue is read-only is equal to true.
|
||||
Pass AudioBufferSourceNode.detune.maxValue = 42 is not equal to 42.
|
||||
Pass AudioBufferSourceNode.detune.maxValue is read-only is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of AudioBufferSourceNode are correct
|
||||
Pass < [Offline createBufferSource] All assertions passed. (total 13 assertions)
|
||||
Pass > [Offline createStereoPanner]
|
||||
Pass > [Offline createDynamicsCompressor]
|
||||
Pass DynamicsCompressorNode.threshold.minValue is equal to -100.
|
||||
Pass DynamicsCompressorNode.threshold.maxValue is equal to 0.
|
||||
Pass DynamicsCompressorNode.threshold.minValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.threshold.minValue is read-only is equal to true.
|
||||
Pass DynamicsCompressorNode.threshold.maxValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.threshold.maxValue is read-only is equal to true.
|
||||
Pass Set DynamicsCompressorNode.threshold.value = -201 is equal to -100.
|
||||
Pass Set DynamicsCompressorNode.threshold.value = 1 is equal to 0.
|
||||
Pass DynamicsCompressorNode.threshold was clipped to lie within the nominal range is equal to true.
|
||||
Pass DynamicsCompressorNode.knee.minValue is equal to 0.
|
||||
Pass DynamicsCompressorNode.knee.maxValue is equal to 40.
|
||||
Pass DynamicsCompressorNode.knee.minValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.knee.minValue is read-only is equal to true.
|
||||
Pass DynamicsCompressorNode.knee.maxValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.knee.maxValue is read-only is equal to true.
|
||||
Pass Set DynamicsCompressorNode.knee.value = -1 is equal to 0.
|
||||
Pass Set DynamicsCompressorNode.knee.value = 81 is equal to 40.
|
||||
Pass DynamicsCompressorNode.knee was clipped to lie within the nominal range is equal to true.
|
||||
Pass DynamicsCompressorNode.ratio.minValue is equal to 1.
|
||||
Pass DynamicsCompressorNode.ratio.maxValue is equal to 20.
|
||||
Pass DynamicsCompressorNode.ratio.minValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.ratio.minValue is read-only is equal to true.
|
||||
Pass DynamicsCompressorNode.ratio.maxValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.ratio.maxValue is read-only is equal to true.
|
||||
Pass Set DynamicsCompressorNode.ratio.value = 1 is equal to 1.
|
||||
Pass Set DynamicsCompressorNode.ratio.value = 41 is equal to 20.
|
||||
Pass DynamicsCompressorNode.ratio was clipped to lie within the nominal range is equal to true.
|
||||
Pass DynamicsCompressorNode.attack.minValue is equal to 0.
|
||||
Pass DynamicsCompressorNode.attack.maxValue is equal to 1.
|
||||
Pass DynamicsCompressorNode.attack.minValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.attack.minValue is read-only is equal to true.
|
||||
Pass DynamicsCompressorNode.attack.maxValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.attack.maxValue is read-only is equal to true.
|
||||
Pass Set DynamicsCompressorNode.attack.value = -1 is equal to 0.
|
||||
Pass Set DynamicsCompressorNode.attack.value = 3 is equal to 1.
|
||||
Pass DynamicsCompressorNode.attack was clipped to lie within the nominal range is equal to true.
|
||||
Pass DynamicsCompressorNode.release.minValue is equal to 0.
|
||||
Pass DynamicsCompressorNode.release.maxValue is equal to 1.
|
||||
Pass DynamicsCompressorNode.release.minValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.release.minValue is read-only is equal to true.
|
||||
Pass DynamicsCompressorNode.release.maxValue = 42 is not equal to 42.
|
||||
Pass DynamicsCompressorNode.release.maxValue is read-only is equal to true.
|
||||
Pass Set DynamicsCompressorNode.release.value = -1 is equal to 0.
|
||||
Pass Set DynamicsCompressorNode.release.value = 3 is equal to 1.
|
||||
Pass DynamicsCompressorNode.release was clipped to lie within the nominal range is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of DynamicsCompressorNode are correct
|
||||
Pass < [Offline createDynamicsCompressor] All assertions passed. (total 46 assertions)
|
||||
Pass > [Offline createBiquadFilter]
|
||||
Pass BiquadFilterNode.frequency.minValue is equal to 0.
|
||||
Pass BiquadFilterNode.frequency.maxValue is equal to 24000.
|
||||
Pass BiquadFilterNode.frequency.minValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.frequency.minValue is read-only is equal to true.
|
||||
Pass BiquadFilterNode.frequency.maxValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.frequency.maxValue is read-only is equal to true.
|
||||
Pass Set BiquadFilterNode.frequency.value = -1 is equal to 0.
|
||||
Pass Set BiquadFilterNode.frequency.value = 48001 is equal to 24000.
|
||||
Pass BiquadFilterNode.frequency was clipped to lie within the nominal range is equal to true.
|
||||
Pass BiquadFilterNode.detune.minValue is equal to -153600.
|
||||
Pass BiquadFilterNode.detune.maxValue is equal to 153600.
|
||||
Pass BiquadFilterNode.detune.minValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.detune.minValue is read-only is equal to true.
|
||||
Pass BiquadFilterNode.detune.maxValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.detune.maxValue is read-only is equal to true.
|
||||
Pass Set BiquadFilterNode.detune.value = -307201 is equal to -153600.
|
||||
Pass Set BiquadFilterNode.detune.value = 307201 is equal to 153600.
|
||||
Pass BiquadFilterNode.detune was clipped to lie within the nominal range is equal to true.
|
||||
Pass BiquadFilterNode.Q.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass BiquadFilterNode.Q.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass BiquadFilterNode.Q.minValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.Q.minValue is read-only is equal to true.
|
||||
Pass BiquadFilterNode.Q.maxValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.Q.maxValue is read-only is equal to true.
|
||||
Pass BiquadFilterNode.gain.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass BiquadFilterNode.gain.maxValue is equal to 1541.273681640625.
|
||||
Pass BiquadFilterNode.gain.minValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.gain.minValue is read-only is equal to true.
|
||||
Pass BiquadFilterNode.gain.maxValue = 42 is not equal to 42.
|
||||
Pass BiquadFilterNode.gain.maxValue is read-only is equal to true.
|
||||
Pass Set BiquadFilterNode.gain.value = 3083.54736328125 is equal to 1541.273681640625.
|
||||
Pass BiquadFilterNode.gain was clipped to lie within the nominal range is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of BiquadFilterNode are correct
|
||||
Pass < [Offline createBiquadFilter] All assertions passed. (total 33 assertions)
|
||||
Pass > [Offline createOscillator]
|
||||
Pass OscillatorNode.frequency.minValue is equal to -24000.
|
||||
Pass OscillatorNode.frequency.maxValue is equal to 24000.
|
||||
Pass OscillatorNode.frequency.minValue = 42 is not equal to 42.
|
||||
Pass OscillatorNode.frequency.minValue is read-only is equal to true.
|
||||
Pass OscillatorNode.frequency.maxValue = 42 is not equal to 42.
|
||||
Pass OscillatorNode.frequency.maxValue is read-only is equal to true.
|
||||
Pass Set OscillatorNode.frequency.value = -48001 is equal to -24000.
|
||||
Pass Set OscillatorNode.frequency.value = 48001 is equal to 24000.
|
||||
Pass OscillatorNode.frequency was clipped to lie within the nominal range is equal to true.
|
||||
Pass OscillatorNode.detune.minValue is equal to -153600.
|
||||
Pass OscillatorNode.detune.maxValue is equal to 153600.
|
||||
Pass OscillatorNode.detune.minValue = 42 is not equal to 42.
|
||||
Pass OscillatorNode.detune.minValue is read-only is equal to true.
|
||||
Pass OscillatorNode.detune.maxValue = 42 is not equal to 42.
|
||||
Pass OscillatorNode.detune.maxValue is read-only is equal to true.
|
||||
Pass Set OscillatorNode.detune.value = -307201 is equal to -153600.
|
||||
Pass Set OscillatorNode.detune.value = 307201 is equal to 153600.
|
||||
Pass OscillatorNode.detune was clipped to lie within the nominal range is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of OscillatorNode are correct
|
||||
Pass < [Offline createOscillator] All assertions passed. (total 19 assertions)
|
||||
Pass > [Offline createPanner]
|
||||
Pass PannerNode.positionX.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass PannerNode.positionX.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass PannerNode.positionX.minValue = 42 is not equal to 42.
|
||||
Pass PannerNode.positionX.minValue is read-only is equal to true.
|
||||
Pass PannerNode.positionX.maxValue = 42 is not equal to 42.
|
||||
Pass PannerNode.positionX.maxValue is read-only is equal to true.
|
||||
Pass PannerNode.positionY.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass PannerNode.positionY.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass PannerNode.positionY.minValue = 42 is not equal to 42.
|
||||
Pass PannerNode.positionY.minValue is read-only is equal to true.
|
||||
Pass PannerNode.positionY.maxValue = 42 is not equal to 42.
|
||||
Pass PannerNode.positionY.maxValue is read-only is equal to true.
|
||||
Pass PannerNode.positionZ.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass PannerNode.positionZ.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass PannerNode.positionZ.minValue = 42 is not equal to 42.
|
||||
Pass PannerNode.positionZ.minValue is read-only is equal to true.
|
||||
Pass PannerNode.positionZ.maxValue = 42 is not equal to 42.
|
||||
Pass PannerNode.positionZ.maxValue is read-only is equal to true.
|
||||
Pass PannerNode.orientationX.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass PannerNode.orientationX.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass PannerNode.orientationX.minValue = 42 is not equal to 42.
|
||||
Pass PannerNode.orientationX.minValue is read-only is equal to true.
|
||||
Pass PannerNode.orientationX.maxValue = 42 is not equal to 42.
|
||||
Pass PannerNode.orientationX.maxValue is read-only is equal to true.
|
||||
Pass PannerNode.orientationY.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass PannerNode.orientationY.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass PannerNode.orientationY.minValue = 42 is not equal to 42.
|
||||
Pass PannerNode.orientationY.minValue is read-only is equal to true.
|
||||
Pass PannerNode.orientationY.maxValue = 42 is not equal to 42.
|
||||
Pass PannerNode.orientationY.maxValue is read-only is equal to true.
|
||||
Pass PannerNode.orientationZ.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass PannerNode.orientationZ.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass PannerNode.orientationZ.minValue = 42 is not equal to 42.
|
||||
Pass PannerNode.orientationZ.minValue is read-only is equal to true.
|
||||
Pass PannerNode.orientationZ.maxValue = 42 is not equal to 42.
|
||||
Pass PannerNode.orientationZ.maxValue is read-only is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of PannerNode are correct
|
||||
Pass < [Offline createPanner] All assertions passed. (total 37 assertions)
|
||||
Pass > [Offline createConstantSource]
|
||||
Pass ConstantSourceNode.offset.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass ConstantSourceNode.offset.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass ConstantSourceNode.offset.minValue = 42 is not equal to 42.
|
||||
Pass ConstantSourceNode.offset.minValue is read-only is equal to true.
|
||||
Pass ConstantSourceNode.offset.maxValue = 42 is not equal to 42.
|
||||
Pass ConstantSourceNode.offset.maxValue is read-only is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of ConstantSourceNode are correct
|
||||
Pass < [Offline createConstantSource] All assertions passed. (total 7 assertions)
|
||||
Pass > [Offline createBuffer]
|
||||
Pass AudioBuffer has no AudioParams as expected
|
||||
Pass < [Offline createBuffer] All assertions passed. (total 1 assertions)
|
||||
Pass > [Offline createIIRFilter]
|
||||
Pass > [Offline createWaveShaper]
|
||||
Pass > [Offline createConvolver]
|
||||
Pass > [Offline createAnalyser]
|
||||
Pass > [Offline createScriptProcessor]
|
||||
Pass > [Offline createPeriodicWave]
|
||||
Pass PeriodicWave has no AudioParams as expected
|
||||
Pass < [Offline createPeriodicWave] All assertions passed. (total 1 assertions)
|
||||
Pass > [Offline createChannelSplitter]
|
||||
Pass ChannelSplitterNode has no AudioParams as expected
|
||||
Pass < [Offline createChannelSplitter] All assertions passed. (total 1 assertions)
|
||||
Pass > [Offline createChannelMerger]
|
||||
Pass AudioNode has no AudioParams as expected
|
||||
Pass < [Offline createChannelMerger] All assertions passed. (total 1 assertions)
|
||||
Pass > [Online createMediaElementSource]
|
||||
Pass > [Online createMediaStreamDestination]
|
||||
Pass > [AudioListener]
|
||||
Pass AudioListener.positionX.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.positionX.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.positionX.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.positionX.minValue is read-only is equal to true.
|
||||
Pass AudioListener.positionX.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.positionX.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.positionY.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.positionY.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.positionY.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.positionY.minValue is read-only is equal to true.
|
||||
Pass AudioListener.positionY.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.positionY.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.positionZ.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.positionZ.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.positionZ.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.positionZ.minValue is read-only is equal to true.
|
||||
Pass AudioListener.positionZ.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.positionZ.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.forwardX.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.forwardX.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.forwardX.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.forwardX.minValue is read-only is equal to true.
|
||||
Pass AudioListener.forwardX.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.forwardX.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.forwardY.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.forwardY.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.forwardY.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.forwardY.minValue is read-only is equal to true.
|
||||
Pass AudioListener.forwardY.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.forwardY.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.forwardZ.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.forwardZ.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.forwardZ.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.forwardZ.minValue is read-only is equal to true.
|
||||
Pass AudioListener.forwardZ.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.forwardZ.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.upX.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.upX.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.upX.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.upX.minValue is read-only is equal to true.
|
||||
Pass AudioListener.upX.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.upX.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.upY.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.upY.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.upY.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.upY.minValue is read-only is equal to true.
|
||||
Pass AudioListener.upY.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.upY.maxValue is read-only is equal to true.
|
||||
Pass AudioListener.upZ.minValue is equal to -3.4028234663852886e+38.
|
||||
Pass AudioListener.upZ.maxValue is equal to 3.4028234663852886e+38.
|
||||
Pass AudioListener.upZ.minValue = 42 is not equal to 42.
|
||||
Pass AudioListener.upZ.minValue is read-only is equal to true.
|
||||
Pass AudioListener.upZ.maxValue = 42 is not equal to 42.
|
||||
Pass AudioListener.upZ.maxValue is read-only is equal to true.
|
||||
Pass Nominal ranges for AudioParam(s) of AudioListener are correct
|
||||
Pass < [AudioListener] All assertions passed. (total 55 assertions)
|
||||
Pass > [verifyTests]
|
||||
Pass Number of nodes not tested : 0
|
||||
Pass < [verifyTests] All assertions passed. (total 1 assertions)
|
||||
Pass > [automation]
|
||||
Fail X Test automations (check console logs) incorrectly threw NotSupportedError: "FIXME: Implement AudioParam::linear_ramp_to_value_at_time".
|
||||
Fail < [automation] 1 out of 1 assertions were failed.
|
||||
Fail # AUDIT TASK RUNNER FINISHED: 1 out of 24 tasks were failed.
|
|
@ -0,0 +1,497 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Test AudioParam Nominal Range Values
|
||||
</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>
|
||||
</head>
|
||||
<body>
|
||||
<script id="layout-test-code">
|
||||
// Some arbitrary sample rate for the offline context.
|
||||
let sampleRate = 48000;
|
||||
|
||||
// The actual contexts to use. Generally use the offline context for
|
||||
// testing except for the media nodes which require an AudioContext.
|
||||
let offlineContext;
|
||||
let audioContext;
|
||||
|
||||
// The set of all methods that we've tested for verifying that we tested
|
||||
// all of the necessary objects.
|
||||
let testedMethods = new Set();
|
||||
|
||||
// The most positive single float value (the value just before infinity).
|
||||
// Be careful when changing this value! Javascript only uses double
|
||||
// floats, so the value here should be the max single-float value,
|
||||
// converted directly to a double-float value. This also depends on
|
||||
// Javascript reading this value and producing the desired double-float
|
||||
// value correctly.
|
||||
let mostPositiveFloat = 3.4028234663852886e38;
|
||||
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
// Array describing the tests that should be run. |testOfflineConfigs| is
|
||||
// for tests that can use an offline context. |testOnlineConfigs| is for
|
||||
// tests that need to use an online context. Offline contexts are
|
||||
// preferred when possible.
|
||||
let testOfflineConfigs = [
|
||||
{
|
||||
// The name of the method to create the particular node to be tested.
|
||||
creator: 'createGain',
|
||||
|
||||
// Any args to pass to the creator function.
|
||||
args: [],
|
||||
|
||||
// The min/max limits for each AudioParam of the node. This is a
|
||||
// dictionary whose keys are
|
||||
// the names of each AudioParam in the node. Don't define this if the
|
||||
// node doesn't have any
|
||||
// AudioParam attributes.
|
||||
limits: {
|
||||
gain: {
|
||||
// The expected min and max values for this AudioParam.
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
creator: 'createDelay',
|
||||
// Just specify a non-default value for the maximum delay so we can
|
||||
// make sure the limits are
|
||||
// set correctly.
|
||||
args: [1.5],
|
||||
limits: {delayTime: {minValue: 0, maxValue: 1.5}}
|
||||
},
|
||||
{
|
||||
creator: 'createBufferSource',
|
||||
args: [],
|
||||
limits: {
|
||||
playbackRate:
|
||||
{minValue: -mostPositiveFloat, maxValue: mostPositiveFloat},
|
||||
detune: {minValue: -mostPositiveFloat, maxValue: mostPositiveFloat}
|
||||
}
|
||||
},
|
||||
{
|
||||
creator: 'createStereoPanner',
|
||||
args: [],
|
||||
limits: {pan: {minValue: -1, maxValue: 1}}
|
||||
},
|
||||
{
|
||||
creator: 'createDynamicsCompressor',
|
||||
args: [],
|
||||
// Do not set limits for reduction; it's currently an AudioParam but
|
||||
// should be a float.
|
||||
// So let the test fail for reduction. When reduction is changed,
|
||||
// this test will then
|
||||
// correctly pass.
|
||||
limits: {
|
||||
threshold: {minValue: -100, maxValue: 0},
|
||||
knee: {minValue: 0, maxValue: 40},
|
||||
ratio: {minValue: 1, maxValue: 20},
|
||||
attack: {minValue: 0, maxValue: 1},
|
||||
release: {minValue: 0, maxValue: 1}
|
||||
}
|
||||
},
|
||||
{
|
||||
creator: 'createBiquadFilter',
|
||||
args: [],
|
||||
limits: {
|
||||
gain: {
|
||||
minValue: -mostPositiveFloat,
|
||||
// This complicated expression is used to get all the arithmetic
|
||||
// to round to the correct single-precision float value for the
|
||||
// desired max. This also assumes that the implication computes
|
||||
// the limit as 40 * log10f(std::numeric_limits<float>::max()).
|
||||
maxValue:
|
||||
Math.fround(40 * Math.fround(Math.log10(mostPositiveFloat)))
|
||||
},
|
||||
Q: {minValue: -mostPositiveFloat, maxValue: mostPositiveFloat},
|
||||
frequency: {minValue: 0, maxValue: sampleRate / 2},
|
||||
detune: {
|
||||
minValue: -Math.fround(1200 * Math.log2(mostPositiveFloat)),
|
||||
maxValue: Math.fround(1200 * Math.log2(mostPositiveFloat))
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
creator: 'createOscillator',
|
||||
args: [],
|
||||
limits: {
|
||||
frequency: {minValue: -sampleRate / 2, maxValue: sampleRate / 2},
|
||||
detune: {
|
||||
minValue: -Math.fround(1200 * Math.log2(mostPositiveFloat)),
|
||||
maxValue: Math.fround(1200 * Math.log2(mostPositiveFloat))
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
creator: 'createPanner',
|
||||
args: [],
|
||||
limits: {
|
||||
positionX: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
positionY: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
positionZ: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
orientationX: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
orientationY: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
orientationZ: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
creator: 'createConstantSource',
|
||||
args: [],
|
||||
limits: {
|
||||
offset: {minValue: -mostPositiveFloat, maxValue: mostPositiveFloat}
|
||||
}
|
||||
},
|
||||
// These nodes don't have AudioParams, but we want to test them anyway.
|
||||
// Any arguments for the
|
||||
// constructor are pretty much arbitrary; they just need to be valid.
|
||||
{
|
||||
creator: 'createBuffer',
|
||||
args: [1, 1, sampleRate],
|
||||
},
|
||||
{creator: 'createIIRFilter', args: [[1, 2], [1, .9]]},
|
||||
{
|
||||
creator: 'createWaveShaper',
|
||||
args: [],
|
||||
},
|
||||
{
|
||||
creator: 'createConvolver',
|
||||
args: [],
|
||||
},
|
||||
{
|
||||
creator: 'createAnalyser',
|
||||
args: [],
|
||||
},
|
||||
{
|
||||
creator: 'createScriptProcessor',
|
||||
args: [0],
|
||||
},
|
||||
{
|
||||
creator: 'createPeriodicWave',
|
||||
args: [Float32Array.from([0, 0]), Float32Array.from([1, 0])],
|
||||
},
|
||||
{
|
||||
creator: 'createChannelSplitter',
|
||||
args: [],
|
||||
},
|
||||
{
|
||||
creator: 'createChannelMerger',
|
||||
args: [],
|
||||
},
|
||||
];
|
||||
|
||||
let testOnlineConfigs = [
|
||||
{creator: 'createMediaElementSource', args: [new Audio()]},
|
||||
{creator: 'createMediaStreamDestination', args: []}
|
||||
// Can't currently test MediaStreamSource because we're using an offline
|
||||
// context.
|
||||
];
|
||||
|
||||
// Create the contexts so we can use it in the following test.
|
||||
audit.define('initialize', (task, should) => {
|
||||
// Just any context so that we can create the nodes.
|
||||
should(() => {
|
||||
offlineContext = new OfflineAudioContext(1, 1, sampleRate);
|
||||
}, 'Create offline context for tests').notThrow();
|
||||
should(() => {
|
||||
onlineContext = new AudioContext();
|
||||
}, 'Create online context for tests').notThrow();
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Create a task for each entry in testOfflineConfigs
|
||||
for (let test in testOfflineConfigs) {
|
||||
let config = testOfflineConfigs[test]
|
||||
audit.define('Offline ' + config.creator, (function(c) {
|
||||
return (task, should) => {
|
||||
let node = offlineContext[c.creator](...c.args);
|
||||
testLimits(should, c.creator, node, c.limits);
|
||||
task.done();
|
||||
};
|
||||
})(config));
|
||||
}
|
||||
|
||||
for (let test in testOnlineConfigs) {
|
||||
let config = testOnlineConfigs[test]
|
||||
audit.define('Online ' + config.creator, (function(c) {
|
||||
return (task, should) => {
|
||||
let node = onlineContext[c.creator](...c.args);
|
||||
testLimits(should, c.creator, node, c.limits);
|
||||
task.done();
|
||||
};
|
||||
})(config));
|
||||
}
|
||||
|
||||
// Test the AudioListener params that were added for the automated Panner
|
||||
audit.define('AudioListener', (task, should) => {
|
||||
testLimits(should, '', offlineContext.listener, {
|
||||
positionX: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
positionY: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
positionZ: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
forwardX: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
forwardY: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
forwardZ: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
upX: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
upY: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
},
|
||||
upZ: {
|
||||
minValue: -mostPositiveFloat,
|
||||
maxValue: mostPositiveFloat,
|
||||
}
|
||||
});
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Verify that we have tested all the create methods available on the
|
||||
// context.
|
||||
audit.define('verifyTests', (task, should) => {
|
||||
let allNodes = new Set();
|
||||
// Create the set of all "create" methods from the context.
|
||||
for (let method in offlineContext) {
|
||||
if (typeof offlineContext[method] === 'function' &&
|
||||
method.substring(0, 6) === 'create') {
|
||||
allNodes.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the difference between the set of all create methods on the
|
||||
// context and the set of tests that we've run.
|
||||
let diff = new Set([...allNodes].filter(x => !testedMethods.has(x)));
|
||||
|
||||
// Can't currently test a MediaStreamSourceNode, so remove it from the
|
||||
// diff set.
|
||||
diff.delete('createMediaStreamSource');
|
||||
|
||||
// It's a test failure if we didn't test all of the create methods in
|
||||
// the context (except createMediaStreamSource, of course).
|
||||
let output = [];
|
||||
if (diff.size) {
|
||||
for (let item of diff)
|
||||
output.push(' ' + item.substring(6));
|
||||
}
|
||||
|
||||
should(output.length === 0, 'Number of nodes not tested')
|
||||
.message(': 0', ': ' + output);
|
||||
|
||||
task.done();
|
||||
});
|
||||
|
||||
// Simple test of a few automation methods to verify we get warnings.
|
||||
audit.define('automation', (task, should) => {
|
||||
// Just use a DelayNode for testing because the audio param has finite
|
||||
// limits.
|
||||
should(() => {
|
||||
let d = offlineContext.createDelay();
|
||||
|
||||
// The console output should have the warnings that we're interested
|
||||
// in.
|
||||
d.delayTime.setValueAtTime(-1, 0);
|
||||
d.delayTime.linearRampToValueAtTime(2, 1);
|
||||
d.delayTime.exponentialRampToValueAtTime(3, 2);
|
||||
d.delayTime.setTargetAtTime(-1, 3, .1);
|
||||
d.delayTime.setValueCurveAtTime(
|
||||
Float32Array.from([.1, .2, 1.5, -1]), 4, .1);
|
||||
}, 'Test automations (check console logs)').notThrow();
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.run();
|
||||
|
||||
// Is |object| an AudioParam? We determine this by checking the
|
||||
// constructor name.
|
||||
function isAudioParam(object) {
|
||||
return object && object.constructor.name === 'AudioParam';
|
||||
}
|
||||
|
||||
// Does |limitOptions| exist and does it have valid values for the
|
||||
// expected min and max values?
|
||||
function hasValidLimits(limitOptions) {
|
||||
return limitOptions && (typeof limitOptions.minValue === 'number') &&
|
||||
(typeof limitOptions.maxValue === 'number');
|
||||
}
|
||||
|
||||
// Check the min and max values for the AudioParam attribute named
|
||||
// |paramName| for the |node|. The expected limits is given by the
|
||||
// dictionary |limits|. If some test fails, add the name of the failed
|
||||
function validateAudioParamLimits(should, node, paramName, limits) {
|
||||
let nodeName = node.constructor.name;
|
||||
let parameter = node[paramName];
|
||||
let prefix = nodeName + '.' + paramName;
|
||||
|
||||
let success = true;
|
||||
if (hasValidLimits(limits[paramName])) {
|
||||
// Verify that the min and max values for the parameter are correct.
|
||||
let isCorrect = should(parameter.minValue, prefix + '.minValue')
|
||||
.beEqualTo(limits[paramName].minValue);
|
||||
isCorrect = should(parameter.maxValue, prefix + '.maxValue')
|
||||
.beEqualTo(limits[paramName].maxValue) &&
|
||||
isCorrect;
|
||||
|
||||
// Verify that the min and max attributes are read-only. |testValue|
|
||||
// MUST be a number that can be represented exactly the same way as
|
||||
// both a double and single float. A small integer works nicely.
|
||||
const testValue = 42;
|
||||
parameter.minValue = testValue;
|
||||
let isReadOnly;
|
||||
isReadOnly =
|
||||
should(parameter.minValue, `${prefix}.minValue = ${testValue}`)
|
||||
.notBeEqualTo(testValue);
|
||||
|
||||
should(isReadOnly, prefix + '.minValue is read-only').beEqualTo(true);
|
||||
|
||||
isCorrect = isReadOnly && isCorrect;
|
||||
|
||||
parameter.maxValue = testValue;
|
||||
isReadOnly =
|
||||
should(parameter.maxValue, `${prefix}.maxValue = ${testValue}`)
|
||||
.notBeEqualTo(testValue);
|
||||
should(isReadOnly, prefix + '.maxValue is read-only').beEqualTo(true);
|
||||
|
||||
isCorrect = isReadOnly && isCorrect;
|
||||
|
||||
// Now try to set the parameter outside the nominal range.
|
||||
let newValue = 2 * limits[paramName].minValue - 1;
|
||||
|
||||
let isClipped = true;
|
||||
let clippingTested = false;
|
||||
// If the new value is beyond float the largest single-precision
|
||||
// float, skip the test because Chrome throws an error.
|
||||
if (newValue >= -mostPositiveFloat) {
|
||||
parameter.value = newValue;
|
||||
clippingTested = true;
|
||||
isClipped =
|
||||
should(
|
||||
parameter.value, 'Set ' + prefix + '.value = ' + newValue)
|
||||
.beEqualTo(parameter.minValue) &&
|
||||
isClipped;
|
||||
}
|
||||
|
||||
newValue = 2 * limits[paramName].maxValue + 1;
|
||||
|
||||
if (newValue <= mostPositiveFloat) {
|
||||
parameter.value = newValue;
|
||||
clippingTested = true;
|
||||
isClipped =
|
||||
should(
|
||||
parameter.value, 'Set ' + prefix + '.value = ' + newValue)
|
||||
.beEqualTo(parameter.maxValue) &&
|
||||
isClipped;
|
||||
}
|
||||
|
||||
if (clippingTested) {
|
||||
should(
|
||||
isClipped,
|
||||
prefix + ' was clipped to lie within the nominal range')
|
||||
.beEqualTo(true);
|
||||
}
|
||||
|
||||
isCorrect = isCorrect && isClipped;
|
||||
|
||||
success = isCorrect && success;
|
||||
} else {
|
||||
// Test config didn't specify valid limits. Fail this test!
|
||||
should(
|
||||
clippingTested,
|
||||
'Limits for ' + nodeName + '.' + paramName +
|
||||
' were correctly defined')
|
||||
.beEqualTo(false);
|
||||
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Test all of the AudioParams for |node| using the expected values in
|
||||
// |limits|. |creatorName| is the name of the method to create the node,
|
||||
// and is used to keep trakc of which tests we've run.
|
||||
function testLimits(should, creatorName, node, limits) {
|
||||
let nodeName = node.constructor.name;
|
||||
testedMethods.add(creatorName);
|
||||
|
||||
let success = true;
|
||||
|
||||
// List of all of the AudioParams that were tested.
|
||||
let audioParams = [];
|
||||
|
||||
// List of AudioParams that failed the test.
|
||||
let incorrectParams = [];
|
||||
|
||||
// Look through all of the keys for the node and extract just the
|
||||
// AudioParams
|
||||
Object.keys(node.__proto__).forEach(function(paramName) {
|
||||
if (isAudioParam(node[paramName])) {
|
||||
audioParams.push(paramName);
|
||||
let isValid = validateAudioParamLimits(
|
||||
should, node, paramName, limits, incorrectParams);
|
||||
if (!isValid)
|
||||
incorrectParams.push(paramName);
|
||||
|
||||
success = isValid && success;
|
||||
}
|
||||
});
|
||||
|
||||
// Print an appropriate message depending on whether there were
|
||||
// AudioParams defined or not.
|
||||
if (audioParams.length) {
|
||||
let message =
|
||||
'Nominal ranges for AudioParam(s) of ' + node.constructor.name;
|
||||
should(success, message)
|
||||
.message('are correct', 'are incorrect for: ' + +incorrectParams);
|
||||
return success;
|
||||
} else {
|
||||
should(!limits, nodeName)
|
||||
.message(
|
||||
'has no AudioParams as expected',
|
||||
'has no AudioParams but test expected ' + limits);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue