Title: [266270] trunk
Revision
266270
Author
[email protected]
Date
2020-08-27 19:56:46 -0700 (Thu, 27 Aug 2020)

Log Message

AudioParam's minValue / maxValue are ignored
https://bugs.webkit.org/show_bug.cgi?id=215905

Reviewed by Darin Adler.

Source/WebCore:

Clamp the AudioParam's values so that they are always in the
[minValue, maxValue] range.

Test: webaudio/audioparam-nominal-range.html

* Modules/webaudio/AudioParam.cpp:
(WebCore::AudioParam::value):
(WebCore::AudioParam::setValue):
(WebCore::AudioParam::smooth):
(WebCore::AudioParam::calculateFinalValues):
(WebCore::AudioParam::calculateTimelineValues):
* Modules/webaudio/AudioParamTimeline.cpp:
(WebCore::AudioParamTimeline::valueForContextTime):
(WebCore::AudioParamTimeline::valuesForTimeRange):
* Modules/webaudio/AudioParamTimeline.h:
* Modules/webaudio/BiquadProcessor.cpp:
(WebCore::BiquadProcessor::BiquadProcessor):

LayoutTests:

Import layout test coverage from Blink.

* webaudio/audioparam-nominal-range-expected.txt: Added.
* webaudio/audioparam-nominal-range.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (266269 => 266270)


--- trunk/LayoutTests/ChangeLog	2020-08-28 02:55:21 UTC (rev 266269)
+++ trunk/LayoutTests/ChangeLog	2020-08-28 02:56:46 UTC (rev 266270)
@@ -1,3 +1,15 @@
+2020-08-27  Chris Dumez  <[email protected]>
+
+        AudioParam's minValue / maxValue are ignored
+        https://bugs.webkit.org/show_bug.cgi?id=215905
+
+        Reviewed by Darin Adler.
+
+        Import layout test coverage from Blink.
+
+        * webaudio/audioparam-nominal-range-expected.txt: Added.
+        * webaudio/audioparam-nominal-range.html: Added.
+
 2020-08-27  Ryosuke Niwa  <[email protected]>
 
         Prevent infinite recursion when upgrading custom elements

Added: trunk/LayoutTests/webaudio/audioparam-nominal-range-expected.txt (0 => 266270)


--- trunk/LayoutTests/webaudio/audioparam-nominal-range-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webaudio/audioparam-nominal-range-expected.txt	2020-08-28 02:56:46 UTC (rev 266270)
@@ -0,0 +1,329 @@
+
+PASS # AUDIT TASK RUNNER STARTED. 
+PASS Executing "initialize" 
+PASS Executing "Offline createGain" 
+PASS Executing "Offline createDelay" 
+PASS Executing "Offline createBufferSource" 
+PASS 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" 
+PASS Executing "Offline createIIRFilter" 
+PASS Executing "Offline createWaveShaper" 
+PASS Executing "Offline createConvolver" 
+PASS Executing "Offline createAnalyser" 
+PASS Executing "Offline createScriptProcessor" 
+PASS Executing "Offline createPeriodicWave" 
+PASS Executing "Offline createChannelSplitter" 
+PASS Executing "Offline createChannelMerger" 
+PASS Executing "Online createMediaElementSource" 
+PASS 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   StereoPannerNode.pan.minValue is equal to -1. 
+PASS   StereoPannerNode.pan.maxValue is equal to 1. 
+PASS   StereoPannerNode.pan.minValue = 42 is not equal to 42. 
+PASS   StereoPannerNode.pan.minValue is read-only is equal to true. 
+PASS   StereoPannerNode.pan.maxValue = 42 is not equal to 42. 
+PASS   StereoPannerNode.pan.maxValue is read-only is equal to true. 
+PASS   Set StereoPannerNode.pan.value = -3 is equal to -1. 
+PASS   Set StereoPannerNode.pan.value = 3 is equal to 1. 
+PASS   StereoPannerNode.pan was clipped to lie within the nominal range is equal to true. 
+PASS   Nominal ranges for AudioParam(s) of StereoPannerNode are correct 
+PASS < [Offline createStereoPanner] All assertions passed. (total 10 assertions) 
+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   IIRFilterNode has no AudioParams as expected 
+PASS < [Offline createIIRFilter] All assertions passed. (total 1 assertions) 
+PASS > [Offline createWaveShaper]  
+PASS   WaveShaperNode has no AudioParams as expected 
+PASS < [Offline createWaveShaper] All assertions passed. (total 1 assertions) 
+PASS > [Offline createConvolver]  
+PASS   ConvolverNode has no AudioParams as expected 
+PASS < [Offline createConvolver] All assertions passed. (total 1 assertions) 
+PASS > [Offline createAnalyser]  
+PASS   AnalyserNode has no AudioParams as expected 
+PASS < [Offline createAnalyser] All assertions passed. (total 1 assertions) 
+PASS > [Offline createScriptProcessor]  
+PASS   ScriptProcessorNode has no AudioParams as expected 
+PASS < [Offline createScriptProcessor] All assertions passed. (total 1 assertions) 
+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   ChannelMergerNode has no AudioParams as expected 
+PASS < [Offline createChannelMerger] All assertions passed. (total 1 assertions) 
+PASS > [Online createMediaElementSource]  
+PASS   MediaElementAudioSourceNode has no AudioParams as expected 
+PASS < [Online createMediaElementSource] All assertions passed. (total 1 assertions) 
+PASS > [Online createMediaStreamDestination]  
+PASS   MediaStreamAudioDestinationNode has no AudioParams as expected 
+PASS < [Online createMediaStreamDestination] All assertions passed. (total 1 assertions) 
+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]  
+PASS   Test automations (check console logs) did not throw an exception. 
+PASS < [automation] All assertions passed. (total 1 assertions) 
+PASS # AUDIT TASK RUNNER FINISHED: 24 tasks ran successfully. 
+

Added: trunk/LayoutTests/webaudio/audioparam-nominal-range.html (0 => 266270)


--- trunk/LayoutTests/webaudio/audioparam-nominal-range.html	                        (rev 0)
+++ trunk/LayoutTests/webaudio/audioparam-nominal-range.html	2020-08-28 02:56:46 UTC (rev 266270)
@@ -0,0 +1,497 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>
+      Test AudioParam Nominal Range Values
+    </title>
+    <script src=""
+    <script src=""
+    <script src=""
+    <script src=""
+  </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>

Modified: trunk/Source/WebCore/ChangeLog (266269 => 266270)


--- trunk/Source/WebCore/ChangeLog	2020-08-28 02:55:21 UTC (rev 266269)
+++ trunk/Source/WebCore/ChangeLog	2020-08-28 02:56:46 UTC (rev 266270)
@@ -1,3 +1,28 @@
+2020-08-27  Chris Dumez  <[email protected]>
+
+        AudioParam's minValue / maxValue are ignored
+        https://bugs.webkit.org/show_bug.cgi?id=215905
+
+        Reviewed by Darin Adler.
+
+        Clamp the AudioParam's values so that they are always in the
+        [minValue, maxValue] range.
+
+        Test: webaudio/audioparam-nominal-range.html
+
+        * Modules/webaudio/AudioParam.cpp:
+        (WebCore::AudioParam::value):
+        (WebCore::AudioParam::setValue):
+        (WebCore::AudioParam::smooth):
+        (WebCore::AudioParam::calculateFinalValues):
+        (WebCore::AudioParam::calculateTimelineValues):
+        * Modules/webaudio/AudioParamTimeline.cpp:
+        (WebCore::AudioParamTimeline::valueForContextTime):
+        (WebCore::AudioParamTimeline::valuesForTimeRange):
+        * Modules/webaudio/AudioParamTimeline.h:
+        * Modules/webaudio/BiquadProcessor.cpp:
+        (WebCore::BiquadProcessor::BiquadProcessor):
+
 2020-08-27  Ryosuke Niwa  <[email protected]>
 
         Prevent infinite recursion when upgrading custom elements

Modified: trunk/Source/WebCore/Modules/webaudio/AudioParam.cpp (266269 => 266270)


--- trunk/Source/WebCore/Modules/webaudio/AudioParam.cpp	2020-08-28 02:55:21 UTC (rev 266269)
+++ trunk/Source/WebCore/Modules/webaudio/AudioParam.cpp	2020-08-28 02:56:46 UTC (rev 266270)
@@ -34,6 +34,7 @@
 #include "AudioUtilities.h"
 #include "FloatConversion.h"
 #include "Logging.h"
+#include "VectorMath.h"
 #include <wtf/MathExtras.h>
 
 namespace WebCore {
@@ -64,11 +65,9 @@
 {
     // Update value for timeline.
     if (context().isAudioThread()) {
-        bool hasValue;
-        float timelineValue = m_timeline.valueForContextTime(context(), m_value, hasValue);
-
-        if (hasValue)
-            m_value = timelineValue;
+        auto timelineValue = m_timeline.valueForContextTime(context(), m_value, minValue(), maxValue());
+        if (timelineValue)
+            m_value = *timelineValue;
     }
 
     return m_value;
@@ -78,10 +77,7 @@
 {
     DEBUG_LOG(LOGIDENTIFIER, value);
 
-    // Check against _javascript_ giving us bogus floating-point values.
-    // Don't ASSERT, since this can happen if somebody writes bad JS.
-    if (!std::isnan(value) && !std::isinf(value))
-        m_value = value;
+    m_value = std::clamp(value, minValue(), maxValue());
 }
 
 ExceptionOr<void> AudioParam::setAutomationRate(AutomationRate automationRate)
@@ -102,8 +98,9 @@
 {
     // If values have been explicitly scheduled on the timeline, then use the exact value.
     // Smoothing effectively is performed by the timeline.
-    bool useTimelineValue = false;
-    m_value = m_timeline.valueForContextTime(context(), m_value, useTimelineValue);
+    auto timelineValue = m_timeline.valueForContextTime(context(), m_value, minValue(), maxValue());
+    if (timelineValue)
+        m_value = *timelineValue;
 
     if (m_smoothedValue == m_value) {
         // Smoothed value has already approached and snapped to value.
@@ -110,7 +107,7 @@
         return true;
     }
     
-    if (useTimelineValue)
+    if (timelineValue)
         m_smoothedValue = m_value;
     else {
         // Dezipper - exponential approach.
@@ -227,11 +224,10 @@
         calculateTimelineValues(values, numberOfValues);
     } else {
         // Calculate control-rate (k-rate) intrinsic value.
-        bool hasValue;
-        float timelineValue = m_timeline.valueForContextTime(context(), m_value, hasValue);
+        auto timelineValue = m_timeline.valueForContextTime(context(), m_value, minValue(), maxValue());
 
-        if (hasValue)
-            m_value = timelineValue;
+        if (timelineValue)
+            m_value = *timelineValue;
 
         values[0] = m_value;
     }
@@ -250,6 +246,11 @@
         // Sum, with unity-gain.
         summingBus->sumFrom(*connectionBus);
     }
+
+    // Clamp values based on range allowed by AudioParam's min and max values.
+    float minValue = this->minValue();
+    float maxValue = this->maxValue();
+    VectorMath::vclip(values, 1, &minValue, &maxValue, values, 1, numberOfValues);
 }
 
 void AudioParam::calculateTimelineValues(float* values, unsigned numberOfValues)
@@ -262,7 +263,7 @@
 
     // Note we're running control rate at the sample-rate.
     // Pass in the current value as default value.
-    m_value = m_timeline.valuesForTimeRange(startTime, endTime, m_value, values, numberOfValues, sampleRate, sampleRate);
+    m_value = m_timeline.valuesForTimeRange(startTime, endTime, m_value, minValue(), maxValue(), values, numberOfValues, sampleRate, sampleRate);
 }
 
 void AudioParam::connect(AudioNodeOutput* output)

Modified: trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.cpp (266269 => 266270)


--- trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.cpp	2020-08-28 02:55:21 UTC (rev 266269)
+++ trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.cpp	2020-08-28 02:56:46 UTC (rev 266270)
@@ -31,6 +31,7 @@
 
 #include "AudioUtilities.h"
 #include "FloatConversion.h"
+#include "VectorMath.h"
 #include <algorithm>
 #include <wtf/MathExtras.h>
 
@@ -133,14 +134,12 @@
     }
 }
 
-float AudioParamTimeline::valueForContextTime(BaseAudioContext& context, float defaultValue, bool& hasValue)
+Optional<float> AudioParamTimeline::valueForContextTime(BaseAudioContext& context, float defaultValue, float minValue, float maxValue)
 {
     {
         std::unique_lock<Lock> lock(m_eventsMutex, std::try_to_lock);
-        if (!lock.owns_lock() || !m_events.size() || Seconds { context.currentTime() } < m_events[0].time()) {
-            hasValue = false;
-            return defaultValue;
-        }
+        if (!lock.owns_lock() || !m_events.size() || Seconds { context.currentTime() } < m_events[0].time())
+            return WTF::nullopt;
     }
 
     // Ask for just a single value.
@@ -149,13 +148,11 @@
     Seconds startTime = Seconds { context.currentTime() };
     Seconds endTime = startTime + Seconds { 1.1 / sampleRate }; // time just beyond one sample-frame
     double controlRate = sampleRate / AudioNode::ProcessingSizeInFrames; // one parameter change per render quantum
-    value = valuesForTimeRange(startTime, endTime, defaultValue, &value, 1, sampleRate, controlRate);
-
-    hasValue = true;
+    value = valuesForTimeRange(startTime, endTime, defaultValue, minValue, maxValue, &value, 1, sampleRate, controlRate);
     return value;
 }
 
-float AudioParamTimeline::valuesForTimeRange(Seconds startTime, Seconds endTime, float defaultValue, float* values, unsigned numberOfValues, double sampleRate, double controlRate)
+float AudioParamTimeline::valuesForTimeRange(Seconds startTime, Seconds endTime, float defaultValue, float minValue, float maxValue, float* values, unsigned numberOfValues, double sampleRate, double controlRate)
 {
     // We can't contend the lock in the realtime audio thread.
     std::unique_lock<Lock> lock(m_eventsMutex, std::try_to_lock);
@@ -169,6 +166,9 @@
 
     float value = valuesForTimeRangeImpl(startTime, endTime, defaultValue, values, numberOfValues, sampleRate, controlRate);
 
+    // Clamp values based on range allowed by AudioParam's min and max values.
+    VectorMath::vclip(values, 1, &minValue, &maxValue, values, 1, numberOfValues);
+
     return value;
 }
 

Modified: trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.h (266269 => 266270)


--- trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.h	2020-08-28 02:55:21 UTC (rev 266269)
+++ trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.h	2020-08-28 02:56:46 UTC (rev 266270)
@@ -52,7 +52,7 @@
 
     // hasValue is set to true if a valid timeline value is returned.
     // otherwise defaultValue is returned.
-    float valueForContextTime(BaseAudioContext&, float defaultValue, bool& hasValue);
+    Optional<float> valueForContextTime(BaseAudioContext&, float defaultValue, float minValue, float maxValue);
 
     // Given the time range, calculates parameter values into the values buffer
     // and returns the last parameter value calculated for "values" or the defaultValue if none were calculated.
@@ -59,7 +59,7 @@
     // controlRate is the rate (number per second) at which parameter values will be calculated.
     // It should equal sampleRate for sample-accurate parameter changes, and otherwise will usually match
     // the render quantum size such that the parameter value changes once per render quantum.
-    float valuesForTimeRange(Seconds startTime, Seconds endTime, float defaultValue, float* values, unsigned numberOfValues, double sampleRate, double controlRate);
+    float valuesForTimeRange(Seconds startTime, Seconds endTime, float defaultValue, float minValue, float maxValue, float* values, unsigned numberOfValues, double sampleRate, double controlRate);
 
     bool hasValues() { return m_events.size(); }
 

Modified: trunk/Source/WebCore/Modules/webaudio/BiquadProcessor.cpp (266269 => 266270)


--- trunk/Source/WebCore/Modules/webaudio/BiquadProcessor.cpp	2020-08-28 02:55:21 UTC (rev 266269)
+++ trunk/Source/WebCore/Modules/webaudio/BiquadProcessor.cpp	2020-08-28 02:56:46 UTC (rev 266270)
@@ -37,7 +37,7 @@
     , m_type(BiquadFilterType::Lowpass)
     , m_parameter1(AudioParam::create(context, "frequency", 350.0, 0.0, 0.5 * sampleRate, AutomationRate::ARate))
     , m_parameter2(AudioParam::create(context, "Q", 1, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
-    , m_parameter3(AudioParam::create(context, "gain", 0.0, -FLT_MAX, 1541, AutomationRate::ARate))
+    , m_parameter3(AudioParam::create(context, "gain", 0.0, -FLT_MAX, 40 * std::log10(std::numeric_limits<float>::max()), AutomationRate::ARate))
     , m_parameter4(AudioParam::create(context, "detune", 0.0, -153600, 153600, AutomationRate::ARate))
     , m_filterCoefficientsDirty(true)
     , m_hasSampleAccurateValues(false)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to