Title: [267381] trunk
Revision
267381
Author
[email protected]
Date
2020-09-21 16:14:06 -0700 (Mon, 21 Sep 2020)

Log Message

Properly handle AudioParam.setTargetAtTime() followed by a ramp
https://bugs.webkit.org/show_bug.cgi?id=216804

Reviewed by Darin Adler.

Source/WebCore:

Properly handle AudioParam.setTargetAtTime() followed by a ramp:
- https://www.w3.org/TR/webaudio/#dom-audioparam-settargetattime
- https://www.w3.org/TR/webaudio/#dom-audioparam-linearramptovalueattime
- https://www.w3.org/TR/webaudio/#dom-audioparam-exponentialramptovalueattime

This is a merge of the following Blink change:
- https://codereview.chromium.org/1485003002

No new tests, rebaselined existing test.

* Modules/webaudio/AudioParamTimeline.cpp:
(WebCore::AudioParamTimeline::valuesForTimeRangeImpl):
(WebCore::AudioParamTimeline::processSetTargetFollowedByRamp):
* Modules/webaudio/AudioParamTimeline.h:

LayoutTests:

Rebaseline test that is now passing.

* webaudio/AudioParam/audioparam-setTargetAtTime-continuous-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (267380 => 267381)


--- trunk/LayoutTests/ChangeLog	2020-09-21 23:10:08 UTC (rev 267380)
+++ trunk/LayoutTests/ChangeLog	2020-09-21 23:14:06 UTC (rev 267381)
@@ -1,5 +1,16 @@
 2020-09-21  Chris Dumez  <[email protected]>
 
+        Properly handle AudioParam.setTargetAtTime() followed by a ramp
+        https://bugs.webkit.org/show_bug.cgi?id=216804
+
+        Reviewed by Darin Adler.
+
+        Rebaseline test that is now passing.
+
+        * webaudio/AudioParam/audioparam-setTargetAtTime-continuous-expected.txt:
+
+2020-09-21  Chris Dumez  <[email protected]>
+
         Throw when AudioConnect::connect() is called for an output that has no channels
         https://bugs.webkit.org/show_bug.cgi?id=216802
 

Modified: trunk/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous-expected.txt (267380 => 267381)


--- trunk/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous-expected.txt	2020-09-21 23:10:08 UTC (rev 267380)
+++ trunk/LayoutTests/webaudio/AudioParam/audioparam-setTargetAtTime-continuous-expected.txt	2020-09-21 23:14:06 UTC (rev 267381)
@@ -8,68 +8,26 @@
 PASS > [linear ramp replace]  
 PASS   Linear ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
 PASS   Linear ramp: SetTarget part was correctly replaced by the ramp 
-FAIL X Linear ramp does not equal [1,1.0004401408450705,1.0008802816901408,1.0013204225352113,1.0017605633802817,1.002200704225352,1.0026408450704225,1.003080985915493,1.0035211267605635,1.0039612676056338,1.0044014084507042,1.0048415492957747,1.005281690140845,1.0057218309859155,1.006161971830986,1.0066021126760563...] with an element-wise tolerance of {"absoluteThreshold":0.00000126765,"relativeThreshold":0}.
-	Index	Actual			Expected		AbsError		RelError		Test threshold
-	[0]	0.0000000000000000e+0	1.0000000000000000e+0	1.0000000000000000e+0	1.0000000000000000e+0	1.2676500000000001e-6
-	[1]	8.8028167374432087e-4	1.0004401408450705e+0	9.9955985917132617e-1	9.9912010560371878e-1	1.2676500000000001e-6
-	[2]	1.7605633474886417e-3	1.0008802816901408e+0	9.9911971834265212e-1	9.9824098508113712e-1	1.2676500000000001e-6
-	[3]	2.6408447884023190e-3	1.0013204225352113e+0	9.9867957774680893e-1	9.9736263764428568e-1	1.2676500000000001e-6
-	[4]	3.5211266949772835e-3	1.0017605633802817e+0	9.9823943668530446e-1	9.9648506157689443e-1	1.2676500000000001e-6
-	...and 2267 more errors.
-	Max AbsError of 1.0000000000000000e+0 at index of 0.
-	Max RelError of 1.0000000000000000e+0 at index of 0.
- assert_true: expected true got false
+PASS   Linear ramp equals [expected array] with an element-wise tolerance of {"absoluteThreshold":0.00000126765,"relativeThreshold":0}. 
 PASS   Linear ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
-FAIL < [linear ramp replace] 1 out of 4 assertions were failed. assert_true: expected true got false
+PASS < [linear ramp replace] All assertions passed. (total 4 assertions) 
 PASS > [delayed linear ramp]  
 PASS   Delayed linear ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
 PASS   Delayed linear ramp: SetTarget part equals [expected array] with an element-wise tolerance of {"absoluteThreshold":3.43632e-7,"relativeThreshold":0}. 
-FAIL X Delayed linear ramp does not equal [0.44932896411722156,0.45015029411504087,0.4509716241128601,0.4517929541106794,0.45261428410849863,0.45343561410631794,0.4542569441041372,0.45507827410195645,0.45589960409977576,0.45672093409759495,0.4575422640954142,0.4583635940932335,0.45918492409105277,0.460006254088872,0.46082758408669133,0.4616489140845106...] with an element-wise tolerance of {"absoluteThreshold":0.00000107972,"relativeThreshold":0}.
-	Index	Actual			Expected		AbsError		RelError		Test threshold
-	[0]	3.3802819252014160e-1	4.4932896411722156e-1	1.1130077159707996e-1	2.4770442256209341e-1	1.0797199999999999e-6
-	[1]	3.3890849351882935e-1	4.5015029411504087e-1	1.1124180059621153e-1	2.4712146598705201e-1	1.0797199999999999e-6
-	[2]	3.3978873491287231e-1	4.5097162411286013e-1	1.1118288919998781e-1	2.4654076499536740e-1	1.0797199999999999e-6
-	[3]	3.4066903591156006e-1	4.5179295411067938e-1	1.1112391819911932e-1	2.4596204342730055e-1	1.0797199999999999e-6
-	[4]	3.4154930710792542e-1	4.5261428410849863e-1	1.1106497700057322e-1	2.4538548804162183e-1	1.0797199999999999e-6
-	...and 1883 more errors.
-	Max AbsError of 1.1130077159707996e-1 at index of 0.
-	Max RelError of 2.4770442256209341e-1 at index of 0.
- assert_true: expected true got false
+PASS   Delayed linear ramp equals [expected array] with an element-wise tolerance of {"absoluteThreshold":0.00000107972,"relativeThreshold":0}. 
 PASS   Delayed linear ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
-FAIL < [delayed linear ramp] 1 out of 4 assertions were failed. assert_true: expected true got false
+PASS < [delayed linear ramp] All assertions passed. (total 4 assertions) 
 PASS > [expo ramp replace]  
 PASS   Exponential ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
 PASS   Exponential ramp: SetTarget part was correctly replaced by the ramp 
-FAIL X Exponential ramp does not equal [1,1.00030517578125,1.0006103515625,1.0009156465530396,1.0012210607528687,1.0015265941619873,1.001832127571106,1.0021378993988037,1.0024436712265015,1.0027495622634888,1.003055453300476,1.0033615827560425,1.0036677122116089,1.0039739608764648,1.0042803287506104,1.0045866966247559...] with an element-wise tolerance of {"absoluteThreshold":0.0000114441,"relativeThreshold":0}.
-	Index	Actual			Expected		AbsError		RelError		Test threshold
-	[0]	0.0000000000000000e+0	1.0000000000000000e+0	1.0000000000000000e+0	1.0000000000000000e+0	1.1444099999999999e-5
-	[1]	0.0000000000000000e+0	1.0003051757812500e+0	1.0003051757812500e+0	1.0000000000000000e+0	1.1444099999999999e-5
-	[2]	0.0000000000000000e+0	1.0006103515625000e+0	1.0006103515625000e+0	1.0000000000000000e+0	1.1444099999999999e-5
-	[3]	0.0000000000000000e+0	1.0009156465530396e+0	1.0009156465530396e+0	1.0000000000000000e+0	1.1444099999999999e-5
-	[4]	0.0000000000000000e+0	1.0012210607528687e+0	1.0012210607528687e+0	1.0000000000000000e+0	1.1444099999999999e-5
-	...and 2267 more errors.
-	Max AbsError of 1.9993898868560791e+0 at index of 2271.
-	[2271]	0.0000000000000000e+0	1.9993898868560791e+0	1.9993898868560791e+0	1.0000000000000000e+0	1.1444099999999999e-5
-	Max RelError of 1.0000000000000000e+0 at index of 0.
- assert_true: expected true got false
+PASS   Exponential ramp equals [expected array] with an element-wise tolerance of {"absoluteThreshold":0.0000114441,"relativeThreshold":0}. 
 PASS   Exponential ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
-FAIL < [expo ramp replace] 1 out of 4 assertions were failed. assert_true: expected true got false
+PASS < [expo ramp replace] All assertions passed. (total 4 assertions) 
 PASS > [delayed expo ramp]  
 PASS   Delayed exponential ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
 PASS   Delayed exponential ramp: SetTarget part equals [expected array] with an element-wise tolerance of {"absoluteThreshold":3.43632e-7,"relativeThreshold":0}. 
-FAIL X Delayed exponential ramp does not equal [0.4493289589881897,0.4496844708919525,0.45004022121429443,0.4503962993621826,0.4507526457309723,0.45110926032066345,0.4514661729335785,0.451823353767395,0.4521808326244354,0.4525385797023773,0.4528966248035431,0.45325493812561035,0.4536135494709015,0.4539724290370941,0.4543316066265106,0.4546910524368286...] with an element-wise tolerance of {"absoluteThreshold":0.00000429154,"relativeThreshold":0}.
-	Index	Actual			Expected		AbsError		RelError		Test threshold
-	[0]	0.0000000000000000e+0	4.4932895898818970e-1	4.4932895898818970e-1	1.0000000000000000e+0	4.2915399999999997e-6
-	[1]	0.0000000000000000e+0	4.4968447089195251e-1	4.4968447089195251e-1	1.0000000000000000e+0	4.2915399999999997e-6
-	[2]	0.0000000000000000e+0	4.5004022121429443e-1	4.5004022121429443e-1	1.0000000000000000e+0	4.2915399999999997e-6
-	[3]	0.0000000000000000e+0	4.5039629936218262e-1	4.5039629936218262e-1	1.0000000000000000e+0	4.2915399999999997e-6
-	[4]	0.0000000000000000e+0	4.5075264573097229e-1	4.5075264573097229e-1	1.0000000000000000e+0	4.2915399999999997e-6
-	...and 1883 more errors.
-	Max AbsError of 1.9984188079833984e+0 at index of 1887.
-	[1887]	0.0000000000000000e+0	1.9984188079833984e+0	1.9984188079833984e+0	1.0000000000000000e+0	4.2915399999999997e-6
-	Max RelError of 1.0000000000000000e+0 at index of 0.
- assert_true: expected true got false
+PASS   Delayed exponential ramp equals [expected array] with an element-wise tolerance of {"absoluteThreshold":0.00000429154,"relativeThreshold":0}. 
 PASS   Delayed exponential ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2...] with an element-wise tolerance of {"absoluteThreshold":0,"relativeThreshold":0}. 
-FAIL < [delayed expo ramp] 1 out of 4 assertions were failed. assert_true: expected true got false
-FAIL # AUDIT TASK RUNNER FINISHED: 4 out of 4 tasks were failed. assert_true: expected true got false
+PASS < [delayed expo ramp] All assertions passed. (total 4 assertions) 
+PASS # AUDIT TASK RUNNER FINISHED: 4 tasks ran successfully. 
 

Modified: trunk/Source/WebCore/ChangeLog (267380 => 267381)


--- trunk/Source/WebCore/ChangeLog	2020-09-21 23:10:08 UTC (rev 267380)
+++ trunk/Source/WebCore/ChangeLog	2020-09-21 23:14:06 UTC (rev 267381)
@@ -1,3 +1,25 @@
+2020-09-21  Chris Dumez  <[email protected]>
+
+        Properly handle AudioParam.setTargetAtTime() followed by a ramp
+        https://bugs.webkit.org/show_bug.cgi?id=216804
+
+        Reviewed by Darin Adler.
+
+        Properly handle AudioParam.setTargetAtTime() followed by a ramp:
+        - https://www.w3.org/TR/webaudio/#dom-audioparam-settargetattime
+        - https://www.w3.org/TR/webaudio/#dom-audioparam-linearramptovalueattime
+        - https://www.w3.org/TR/webaudio/#dom-audioparam-exponentialramptovalueattime
+
+        This is a merge of the following Blink change:
+        - https://codereview.chromium.org/1485003002
+
+        No new tests, rebaselined existing test.
+
+        * Modules/webaudio/AudioParamTimeline.cpp:
+        (WebCore::AudioParamTimeline::valuesForTimeRangeImpl):
+        (WebCore::AudioParamTimeline::processSetTargetFollowedByRamp):
+        * Modules/webaudio/AudioParamTimeline.h:
+
 2020-09-21  Antoine Quint  <[email protected]>
 
         Remove unused NodeFlag::HasCSSAnimation

Modified: trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.cpp (267380 => 267381)


--- trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.cpp	2020-09-21 23:10:08 UTC (rev 267380)
+++ trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.cpp	2020-09-21 23:14:06 UTC (rev 267381)
@@ -388,23 +388,25 @@
     // and keeping track of a "current" event index.
     int n = m_events.size();
     for (int i = 0; i < n && writeIndex < numberOfValues; ++i) {
-        auto& event = m_events[i].get();
+        auto* event = &m_events[i].get();
         auto* nextEvent = i < n - 1 ? &m_events[i + 1].get() : nullptr;
 
         // Wait until we get a more recent event.
-        if (!isEventCurrent(event, nextEvent, currentFrame, sampleRate))
+        if (!isEventCurrent(*event, nextEvent, currentFrame, sampleRate))
             continue;
 
         auto nextEventType = nextEvent ? static_cast<ParamEvent::Type>(nextEvent->type()) : ParamEvent::LastType /* unknown */;
 
-        float value1 = event.value();
-        auto time1 = event.time();
+        processSetTargetFollowedByRamp(i, event, nextEventType, currentFrame, sampleRate, controlRate, value);
+
+        float value1 = event->value();
+        auto time1 = event->time();
         float value2 = nextEvent ? nextEvent->value() : value1;
         auto time2 = nextEvent ? nextEvent->time() : Seconds { endFrame * samplingPeriod + 1 };
 
         ASSERT(time2 >= time1);
 
-        handleCancelValues(event, nextEvent, value2, time2, nextEventType);
+        handleCancelValues(*event, nextEvent, value2, time2, nextEventType);
 
         auto deltaTime = time2 - time1;
 
@@ -443,7 +445,7 @@
             }
         } else {
             // Handle event types not requiring looking ahead to the next event.
-            switch (event.type()) {
+            switch (event->type()) {
             case ParamEvent::SetValue:
             case ParamEvent::LinearRampToValue:
             case ParamEvent::ExponentialRampToValue:
@@ -450,7 +452,7 @@
                 currentFrame = fillToEndFrame;
 
                 // Simply stay at a constant value.
-                value = event.value();
+                value = event->value();
                 for (; writeIndex < fillToFrame; ++writeIndex)
                     values[writeIndex] = value;
 
@@ -460,8 +462,8 @@
                 // event, the current value is one sample behind. Update
                 // the sample value by one sample, but only at the start of
                 // this CancelValues event.
-                if (event.hasDefaultCancelledValue())
-                    value = event.value();
+                if (event->hasDefaultCancelledValue())
+                    value = event->value();
                 else {
                     double cancelFrame = time1.value() * sampleRate;
                     if (i >= 1 && cancelFrame <= currentFrame && currentFrame < cancelFrame + 1) {
@@ -483,8 +485,8 @@
                 break;
             case ParamEvent::SetTarget: {
                 // Exponential approach to target value with given time constant.
-                float target = event.value();
-                float timeConstant = event.timeConstant();
+                float target = event->value();
+                float timeConstant = event->timeConstant();
                 float discreteTimeConstant = static_cast<float>(AudioUtilities::discreteTimeConstantForSampleRate(timeConstant, controlRate));
 
                 // Set the starting value correctly. This is only needed when the
@@ -520,13 +522,13 @@
                 break;
             }
             case ParamEvent::SetValueCurve: {
-                float* curveData = event.curve().data();
-                unsigned numberOfCurvePoints = event.curve().size();
-                float curveEndValue = event.curveEndValue();
+                float* curveData = event->curve().data();
+                unsigned numberOfCurvePoints = event->curve().size();
+                float curveEndValue = event->curveEndValue();
 
                 // Curve events have duration, so don't just use next event time.
-                auto duration = event.duration();
-                double curvePointsPerFrame = event.curvePointsPerSecond() * samplingPeriod;
+                auto duration = event->duration();
+                double curvePointsPerFrame = event->curvePointsPerSecond() * samplingPeriod;
 
                 if (!curveData || !numberOfCurvePoints || duration <= 0_s || sampleRate <= 0) {
                     // Error condition - simply propagate previous value.
@@ -719,6 +721,52 @@
         value = values[writeIndex - 1];
 }
 
+void AudioParamTimeline::processSetTargetFollowedByRamp(int eventIndex, ParamEvent*& event, ParamEvent::Type nextEventType, size_t currentFrame, double sampleRate, double controlRate, float& value)
+{
+    // If the current event is SetTarget and the next event is a LinearRampToValue or ExponentialRampToValue,
+    // special handling is needed. In this case, the linear and exponential ramp should start at wherever
+    // the SetTarget processing has reached.
+    if (event->type() != ParamEvent::SetTarget)
+        return;
+
+    if (nextEventType != ParamEvent::LinearRampToValue && nextEventType != ParamEvent::ExponentialRampToValue)
+        return;
+
+    // Replace the SetTarget with a SetValue to set the starting time and value for the ramp using the
+    // current frame. We need to update |value| appropriately depending on whether the ramp has started
+    // or not.
+    //
+    // If SetTarget starts somewhere between currentFrame - 1 and currentFrame, we directly compute the
+    // value it would have at currentFrame. If not, we update the value from the value from currentFrame - 1.
+    //
+    // Can't use the condition currentFrame - 1 <= t0 * sampleRate <= currentFrame because currentFrame
+    // is unsigned and could be 0. Instead, compute the condition this way, where f = currentFrame and
+    // Fs = sampleRate:
+    //
+    //    f - 1 <= t0 * Fs <= f
+    //    2 * f - 2 <= 2 * Fs * t0 <= 2 * f
+    //    -2 <= 2 * Fs * t0 - 2 * f <= 0
+    //    -1 <= 2 * Fs * t0 - 2 * f + 1 <= 1
+    //     abs(2 * Fs * t0 - 2 * f + 1) <= 1
+
+    if (fabs(2 * sampleRate * event->time().value() - 2 * currentFrame + 1) <= 1) {
+        // SetTarget is starting somewhere between currentFrame - 1 and currentFrame. Compute the value
+        // the SetTarget would have at the currentFrame.
+        value = event->value() + (value - event->value()) * exp(-(currentFrame / sampleRate - event->time().value()) / event->timeConstant());
+    } else {
+        // SetTarget has already started. Update |value| one frame because it's the value from the previous frame.
+        float discreteTimeConstant = static_cast<float>(AudioUtilities::discreteTimeConstantForSampleRate(event->timeConstant(), controlRate));
+        value += (event->value() - value) * discreteTimeConstant;
+    }
+    // Insert a SetValueEvent to mark the starting value and time.
+    // Clear the clamp check because this doesn't need it.
+    m_events[eventIndex] = ParamEvent::createSetValueEvent(value, Seconds { currentFrame / sampleRate });
+
+    // Update our pointer to the current event because we just changed it.
+    event = &m_events[eventIndex].get();
+}
+
+
 float AudioParamTimeline::linearRampAtTime(Seconds t, float value1, Seconds time1, float value2, Seconds time2)
 {
     return value1 + (value2 - value1) * (t - time1).value() / (time2 - time1).value();

Modified: trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.h (267380 => 267381)


--- trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.h	2020-09-21 23:10:08 UTC (rev 267380)
+++ trunk/Source/WebCore/Modules/webaudio/AudioParamTimeline.h	2020-09-21 23:14:06 UTC (rev 267381)
@@ -164,6 +164,7 @@
     bool isEventCurrent(const ParamEvent&, const ParamEvent* nextEvent, size_t currentFrame, double sampleRate) const;
     void processLinearRamp(float* values, unsigned& writeIndex, unsigned fillToFrame, float& value, float value1, float value2, Seconds deltaTime, Seconds time1, double samplingPeriod, size_t& currentFrame);
     void processSetTarget(float* values, unsigned& writeIndex, unsigned fillToFrame, float& value, float target, float discreteTimeConstant);
+    void processSetTargetFollowedByRamp(int eventIndex, ParamEvent*&, ParamEvent::Type nextEventType, size_t currentFrame, double samplingPeriod, double controlRate, float& value);
 
     Vector<UniqueRef<ParamEvent>> m_events;
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to