| Index: third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
|
| diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
|
| index be242483b7738a578b20925345fa49205d00b2dd..a2c5f457501a6780e817c33802e721d133bb983d 100644
|
| --- a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
|
| +++ b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
|
| @@ -420,6 +420,46 @@ float AudioParamTimeline::valuesForFrameRangeImpl(
|
| continue;
|
| }
|
|
|
| + // If there's no next event, set nextEventType to LastType to indicate that.
|
| + ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Type>(nextEvent->getType()) : ParamEvent::LastType;
|
| +
|
| + // 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.getType() == ParamEvent::SetTarget
|
| + && (nextEventType == ParamEvent::LinearRampToValue
|
| + || nextEventType == ParamEvent::ExponentialRampToValue)) {
|
| + // 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() - 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()) / 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;
|
| + }
|
| + m_events[i] = ParamEvent::createSetValueEvent(value, currentFrame / sampleRate);
|
| + }
|
| +
|
| float value1 = event.value();
|
| double time1 = event.time();
|
|
|
| @@ -448,8 +488,6 @@ float AudioParamTimeline::valuesForFrameRangeImpl(
|
| size_t fillToFrame = fillToEndFrame - startFrame;
|
| fillToFrame = std::min(fillToFrame, static_cast<size_t>(numberOfValues));
|
|
|
| - ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Type>(nextEvent->getType()) : ParamEvent::LastType /* unknown */;
|
| -
|
| // First handle linear and exponential ramps which require looking ahead to the next event.
|
| if (nextEventType == ParamEvent::LinearRampToValue) {
|
| const float valueDelta = value2 - value1;
|
| @@ -536,6 +574,11 @@ float AudioParamTimeline::valuesForFrameRangeImpl(
|
| // computed value.
|
| if (writeIndex >= 1)
|
| value /= multiplier;
|
| +
|
| + // Due to roundoff it's possible that value exceeds value2. Clip value to value2 if
|
| + // we are within 1/2 frame of time2.
|
| + if (currentFrame > time2 * sampleRate - 0.5)
|
| + value = value2;
|
| }
|
| } else {
|
| // Handle event types not requiring looking ahead to the next event.
|
|
|