| 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 4746187d04c7ff57a88d2c5254bb6408fa236261..35731182aa8088b21deb7f47a87c1c8cdf21436e 100644
|
| --- a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
|
| +++ b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
|
| @@ -37,17 +37,19 @@
|
|
|
| namespace blink {
|
|
|
| -// For a SetTarget event, if the relative difference between the current value and the target value
|
| -// is less than this, consider them the same and just output the target value. This value MUST be
|
| -// larger than the single precision epsilon of 5.960465e-8. Due to round-off, this value is not
|
| -// achievable in general. This value can vary across the platforms (CPU) and thus it is determined
|
| -// experimentally.
|
| +// For a SetTarget event, if the relative difference between the current value
|
| +// and the target value is less than this, consider them the same and just
|
| +// output the target value. This value MUST be larger than the single precision
|
| +// epsilon of 5.960465e-8. Due to round-off, this value is not achievable in
|
| +// general. This value can vary across the platforms (CPU) and thus it is
|
| +// determined experimentally.
|
| const float kSetTargetThreshold = 1.5e-6;
|
|
|
| -// For a SetTarget event, if the target value is 0, and the current value is less than this
|
| -// threshold, consider the curve to have converged to 0. We need a separate case from
|
| -// kSetTargetThreshold because that uses relative error, which is never met if the target value is
|
| -// 0, a common case. This value MUST be larger than least positive normalized single precision
|
| +// For a SetTarget event, if the target value is 0, and the current value is
|
| +// less than this threshold, consider the curve to have converged to 0. We need
|
| +// a separate case from kSetTargetThreshold because that uses relative error,
|
| +// which is never met if the target value is 0, a common case. This value MUST
|
| +// be larger than least positive normalized single precision
|
| // value (1.1754944e-38) because we normally operate with flush-to-zero enabled.
|
| const float kSetTargetZeroThreshold = 1e-20;
|
|
|
| @@ -76,7 +78,8 @@ static bool isPositiveAudioParamTime(double time,
|
| }
|
|
|
| String AudioParamTimeline::eventToString(const ParamEvent& event) {
|
| - // The default arguments for most automation methods is the value and the time.
|
| + // The default arguments for most automation methods is the value and the
|
| + // time.
|
| String args =
|
| String::number(event.value()) + ", " + String::number(event.time(), 16);
|
|
|
| @@ -273,8 +276,8 @@ void AudioParamTimeline::insertEvent(const ParamEvent& event,
|
| ExceptionState& exceptionState) {
|
| DCHECK(isMainThread());
|
|
|
| - // Sanity check the event. Be super careful we're not getting infected with NaN or Inf. These
|
| - // should have been handled by the caller.
|
| + // Sanity check the event. Be super careful we're not getting infected with
|
| + // NaN or Inf. These should have been handled by the caller.
|
| bool isValid = event.getType() < ParamEvent::LastType &&
|
| std::isfinite(event.value()) && std::isfinite(event.time()) &&
|
| std::isfinite(event.timeConstant()) &&
|
| @@ -292,17 +295,17 @@ void AudioParamTimeline::insertEvent(const ParamEvent& event,
|
| if (!m_events.size() &&
|
| (event.getType() == ParamEvent::LinearRampToValue ||
|
| event.getType() == ParamEvent::ExponentialRampToValue)) {
|
| - // There are no events preceding these ramps. Insert a new setValueAtTime event to set the
|
| - // starting point for these events.
|
| + // There are no events preceding these ramps. Insert a new setValueAtTime
|
| + // event to set the starting point for these events.
|
| m_events.insert(0, AudioParamTimeline::ParamEvent::createSetValueEvent(
|
| event.initialValue(), event.callTime()));
|
| }
|
|
|
| for (i = 0; i < m_events.size(); ++i) {
|
| if (event.getType() == ParamEvent::SetValueCurve) {
|
| - // If this event is a SetValueCurve, make sure it doesn't overlap any existing
|
| - // event. It's ok if the SetValueCurve starts at the same time as the end of some other
|
| - // duration.
|
| + // If this event is a SetValueCurve, make sure it doesn't overlap any
|
| + // existing event. It's ok if the SetValueCurve starts at the same time as
|
| + // the end of some other duration.
|
| double endTime = event.time() + event.duration();
|
| if (m_events[i].time() > event.time() && m_events[i].time() < endTime) {
|
| exceptionState.throwDOMException(
|
| @@ -311,7 +314,8 @@ void AudioParamTimeline::insertEvent(const ParamEvent& event,
|
| return;
|
| }
|
| } else {
|
| - // Otherwise, make sure this event doesn't overlap any existing SetValueCurve event.
|
| + // Otherwise, make sure this event doesn't overlap any existing
|
| + // SetValueCurve event.
|
| if (m_events[i].getType() == ParamEvent::SetValueCurve) {
|
| double endTime = m_events[i].time() + m_events[i].duration();
|
| if (event.time() >= m_events[i].time() && event.time() < endTime) {
|
| @@ -343,17 +347,19 @@ bool AudioParamTimeline::hasValues() const {
|
| if (tryLocker.locked())
|
| return m_events.size();
|
|
|
| - // Can't get the lock so that means the main thread is trying to insert an event. Just
|
| - // return true then. If the main thread releases the lock before valueForContextTime or
|
| - // valuesForFrameRange runs, then the there will be an event on the timeline, so everything
|
| - // is fine. If the lock is held so that neither valueForContextTime nor valuesForFrameRange
|
| - // can run, this is ok too, because they have tryLocks to produce a default value. The
|
| - // event will then get processed in the next rendering quantum.
|
| + // Can't get the lock so that means the main thread is trying to insert an
|
| + // event. Just return true then. If the main thread releases the lock before
|
| + // valueForContextTime or valuesForFrameRange runs, then the there will be an
|
| + // event on the timeline, so everything is fine. If the lock is held so that
|
| + // neither valueForContextTime nor valuesForFrameRange can run, this is ok
|
| + // too, because they have tryLocks to produce a default value. The event will
|
| + // then get processed in the next rendering quantum.
|
| //
|
| - // Don't want to return false here because that would confuse the processing of the timeline
|
| - // if previously we returned true and now suddenly return false, only to return true on the
|
| - // next rendering quantum. Currently, once a timeline has been introduced it is always true
|
| - // forever because m_events never shrinks.
|
| + // Don't want to return false here because that would confuse the processing
|
| + // of the timeline if previously we returned true and now suddenly return
|
| + // false, only to return true on the next rendering quantum. Currently, once
|
| + // a timeline has been introduced it is always true forever because m_events
|
| + // never shrinks.
|
| return true;
|
| }
|
|
|
| @@ -391,10 +397,8 @@ float AudioParamTimeline::valueForContextTime(
|
| float value;
|
| double sampleRate = audioDestination.sampleRate();
|
| size_t startFrame = audioDestination.currentSampleFrame();
|
| - double controlRate =
|
| - sampleRate /
|
| - AudioHandler::
|
| - ProcessingSizeInFrames; // one parameter change per render quantum
|
| + // One parameter change per render quantum.
|
| + double controlRate = sampleRate / AudioHandler::ProcessingSizeInFrames;
|
| value = valuesForFrameRange(startFrame, startFrame + 1, defaultValue, &value,
|
| 1, sampleRate, controlRate, minValue, maxValue);
|
|
|
| @@ -444,7 +448,8 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| if (!values || !(numberOfValues >= 1))
|
| return defaultValue;
|
|
|
| - // Return default value if there are no events matching the desired time range.
|
| + // Return default value if there are no events matching the desired time
|
| + // range.
|
| if (!m_events.size() || (endFrame / sampleRate <= m_events[0].time())) {
|
| for (unsigned i = 0; i < numberOfValues; ++i)
|
| values[i] = defaultValue;
|
| @@ -480,12 +485,12 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| size_t currentFrame = startFrame;
|
| unsigned writeIndex = 0;
|
|
|
| - // If first event is after startFrame then fill initial part of values buffer with defaultValue
|
| - // until we reach the first event time.
|
| + // If first event is after startFrame then fill initial part of values buffer
|
| + // with defaultValue until we reach the first event time.
|
| double firstEventTime = m_events[0].time();
|
| if (firstEventTime > startFrame / sampleRate) {
|
| - // |fillToFrame| is an exclusive upper bound, so use ceil() to compute the bound from the
|
| - // firstEventTime.
|
| + // |fillToFrame| is an exclusive upper bound, so use ceil() to compute the
|
| + // bound from the firstEventTime.
|
| size_t fillToFrame = endFrame;
|
| double firstEventFrame = ceil(firstEventTime * sampleRate);
|
| if (endFrame > firstEventFrame)
|
| @@ -525,15 +530,17 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| // processed again before advancing to setValueAtTime. The number of
|
| // frames to be processed should be zero in this case.
|
| if (nextEvent && nextEvent->time() < currentFrame / sampleRate) {
|
| - // But if the current event is a SetValue event and the event time is between
|
| - // currentFrame - 1 and curentFrame (in time). we don't want to skip it. If we do skip
|
| - // it, the SetValue event is completely skipped and not applied, which is wrong. Other
|
| - // events don't have this problem. (Because currentFrame is unsigned, we do the time
|
| - // check in this funny, but equivalent way.)
|
| + // But if the current event is a SetValue event and the event time is
|
| + // between currentFrame - 1 and curentFrame (in time). we don't want to
|
| + // skip it. If we do skip it, the SetValue event is completely skipped
|
| + // and not applied, which is wrong. Other events don't have this problem.
|
| + // (Because currentFrame is unsigned, we do the time check in this funny,
|
| + // but equivalent way.)
|
| double eventFrame = event.time() * sampleRate;
|
|
|
| - // Condition is currentFrame - 1 < eventFrame <= currentFrame, but currentFrame is
|
| - // unsigned and could be 0, so use currentFrame < eventFrame + 1 instead.
|
| + // Condition is currentFrame - 1 < eventFrame <= currentFrame, but
|
| + // currentFrame is unsigned and could be 0, so use
|
| + // currentFrame < eventFrame + 1 instead.
|
| if (!((event.getType() == ParamEvent::SetValue &&
|
| (eventFrame <= currentFrame) &&
|
| (currentFrame < eventFrame + 1)))) {
|
| @@ -551,22 +558,25 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| 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 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.
|
| + // 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.
|
| + // 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,
|
| + // 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
|
| @@ -576,14 +586,15 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| // 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.
|
| + // 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.
|
| + // 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));
|
| @@ -602,16 +613,17 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| double deltaTime = time2 - time1;
|
| float k = deltaTime > 0 ? 1 / deltaTime : 0;
|
|
|
| - // |fillToEndFrame| is the exclusive upper bound of the last frame to be computed for this
|
| - // event. It's either the last desired frame (|endFrame|) or derived from the end time of
|
| - // the next event (time2). We compute ceil(time2*sampleRate) because fillToEndFrame is the
|
| - // exclusive upper bound. Consider the case where |startFrame| = 128 and time2 = 128.1
|
| - // (assuming sampleRate = 1). Since time2 is greater than 128, we want to output a value
|
| - // for frame 128. This requires that fillToEndFrame be at least 129. This is achieved by
|
| - // ceil(time2).
|
| + // |fillToEndFrame| is the exclusive upper bound of the last frame to be
|
| + // computed for this event. It's either the last desired frame (|endFrame|)
|
| + // or derived from the end time of the next event (time2). We compute
|
| + // ceil(time2*sampleRate) because fillToEndFrame is the exclusive upper
|
| + // bound. Consider the case where |startFrame| = 128 and time2 = 128.1
|
| + // (assuming sampleRate = 1). Since time2 is greater than 128, we want to
|
| + // output a value for frame 128. This requires that fillToEndFrame be at
|
| + // least 129. This is achieved by ceil(time2).
|
| //
|
| - // However, time2 can be very large, so compute this carefully in the case where time2
|
| - // exceeds the size of a size_t.
|
| + // However, time2 can be very large, so compute this carefully in the case
|
| + // where time2 exceeds the size of a size_t.
|
|
|
| size_t fillToEndFrame = endFrame;
|
| if (endFrame > time2 * sampleRate)
|
| @@ -621,15 +633,21 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| size_t fillToFrame = fillToEndFrame - startFrame;
|
| fillToFrame = std::min(fillToFrame, static_cast<size_t>(numberOfValues));
|
|
|
| - // First handle linear and exponential ramps which require looking ahead to the next event.
|
| + // First handle linear and exponential ramps which require looking ahead to
|
| + // the next event.
|
| if (nextEventType == ParamEvent::LinearRampToValue) {
|
| const float valueDelta = value2 - value1;
|
| #if CPU(X86) || CPU(X86_64)
|
| - // Minimize in-loop operations. Calculate starting value and increment. Next step: value += inc.
|
| - // value = value1 + (currentFrame/sampleRate - time1) * k * (value2 - value1);
|
| + // Minimize in-loop operations. Calculate starting value and increment.
|
| + // Next step: value += inc.
|
| + // value = value1 +
|
| + // (currentFrame/sampleRate - time1) * k * (value2 - value1);
|
| // inc = 4 / sampleRate * k * (value2 - value1);
|
| - // Resolve recursion by expanding constants to achieve a 4-step loop unrolling.
|
| - // value = value1 + ((currentFrame/sampleRate - time1) + i * sampleFrameTimeIncr) * k * (value2 -value1), i in 0..3
|
| + // Resolve recursion by expanding constants to achieve a 4-step loop
|
| + // unrolling.
|
| + // value = value1 +
|
| + // ((currentFrame/sampleRate - time1) + i * sampleFrameTimeIncr) * k
|
| + // * (value2 -value1), i in 0..3
|
| __m128 vValue =
|
| _mm_mul_ps(_mm_set_ps1(1 / sampleRate), _mm_set_ps(3, 2, 1, 0));
|
| vValue =
|
| @@ -649,9 +667,9 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| _mm_storeu_ps(values + writeIndex, vValue);
|
| vValue = _mm_add_ps(vValue, vInc);
|
| }
|
| - // Update |value| with the last value computed so that the .value attribute of the
|
| - // AudioParam gets the correct linear ramp value, in case the following loop doesn't
|
| - // execute.
|
| + // Update |value| with the last value computed so that the .value
|
| + // attribute of the AudioParam gets the correct linear ramp value, in case
|
| + // the following loop doesn't execute.
|
| if (writeIndex >= 1)
|
| value = values[writeIndex - 1];
|
| #endif
|
| @@ -665,21 +683,22 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| }
|
| } else if (nextEventType == ParamEvent::ExponentialRampToValue) {
|
| if (value1 * value2 <= 0) {
|
| - // It's an error if value1 and value2 have opposite signs or if one of them is zero.
|
| - // Handle this by propagating the previous value, and making it the default.
|
| + // It's an error if value1 and value2 have opposite signs or if one of
|
| + // them is zero. Handle this by propagating the previous value, and
|
| + // making it the default.
|
| value = value1;
|
|
|
| for (; writeIndex < fillToFrame; ++writeIndex)
|
| values[writeIndex] = value;
|
| } else {
|
| float numSampleFrames = deltaTime * sampleRate;
|
| - // The value goes exponentially from value1 to value2 in a duration of deltaTime
|
| - // seconds according to
|
| + // The value goes exponentially from value1 to value2 in a duration of
|
| + // deltaTime seconds according to
|
| //
|
| // v(t) = v1*(v2/v1)^((t-t1)/(t2-t1))
|
| //
|
| - // Let c be currentFrame and F be the sampleRate. Then we want to sample v(t)
|
| - // at times t = (c + k)/F for k = 0, 1, ...:
|
| + // Let c be currentFrame and F be the sampleRate. Then we want to
|
| + // sample v(t) at times t = (c + k)/F for k = 0, 1, ...:
|
| //
|
| // v((c+k)/F) = v1*(v2/v1)^(((c/F+k/F)-t1)/(t2-t1))
|
| // = v1*(v2/v1)^((c/F-t1)/(t2-t1))
|
| @@ -706,13 +725,13 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| value *= multiplier;
|
| ++currentFrame;
|
| }
|
| - // |value| got updated one extra time in the above loop. Restore it to the last
|
| - // computed value.
|
| + // |value| got updated one extra time in the above loop. Restore it to
|
| + // the last 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.
|
| + // 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;
|
| }
|
| @@ -735,15 +754,16 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| case ParamEvent::ExponentialRampToValue: {
|
| currentFrame = fillToEndFrame;
|
|
|
| - // If we're here, we've reached the end of the ramp. If we can (because the
|
| - // start and end values have the same sign, and neither is 0), use the actual
|
| - // end value. If not, we have to propagate whatever we have.
|
| + // If we're here, we've reached the end of the ramp. If we can
|
| + // (because the start and end values have the same sign, and neither
|
| + // is 0), use the actual end value. If not, we have to propagate
|
| + // whatever we have.
|
| if (i >= 1 && ((m_events[i - 1].value() * event.value()) > 0))
|
| value = event.value();
|
|
|
| - // Simply stay at a constant value from the last time. We don't want to use the
|
| - // value of the event in case value1 * value2 < 0. In this case we should
|
| - // propagate the previous value, which is in |value|.
|
| + // Simply stay at a constant value from the last time. We don't want
|
| + // to use the value of the event in case value1 * value2 < 0. In this
|
| + // case we should propagate the previous value, which is in |value|.
|
| for (; writeIndex < fillToFrame; ++writeIndex)
|
| values[writeIndex] = value;
|
|
|
| @@ -762,16 +782,16 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| AudioUtilities::discreteTimeConstantForSampleRate(timeConstant,
|
| controlRate));
|
|
|
| - // Set the starting value correctly. This is only needed when the current time
|
| - // is "equal" to the start time of this event. This is to get the sampling
|
| - // correct if the start time of this automation isn't on a frame boundary.
|
| - // Otherwise, we can just continue from where we left off from the previous
|
| - // rendering quantum.
|
| + // Set the starting value correctly. This is only needed when the
|
| + // current time is "equal" to the start time of this event. This is
|
| + // to get the sampling correct if the start time of this automation
|
| + // isn't on a frame boundary. Otherwise, we can just continue from
|
| + // where we left off from the previous rendering quantum.
|
| {
|
| double rampStartFrame = time1 * sampleRate;
|
| // Condition is c - 1 < r <= c where c = currentFrame and r =
|
| - // rampStartFrame. Compute it this way because currentFrame is unsigned and
|
| - // could be 0.
|
| + // rampStartFrame. Compute it this way because currentFrame is
|
| + // unsigned and could be 0.
|
| if (rampStartFrame <= currentFrame &&
|
| currentFrame < rampStartFrame + 1) {
|
| value =
|
| @@ -779,22 +799,23 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| (value - target) *
|
| exp(-(currentFrame / sampleRate - time1) / timeConstant);
|
| } else {
|
| - // Otherwise, need to compute a new value bacause |value| is the last
|
| - // computed value of SetTarget. Time has progressed by one frame, so we
|
| - // need to update the value for the new frame.
|
| + // Otherwise, need to compute a new value bacause |value| is the
|
| + // last computed value of SetTarget. Time has progressed by one
|
| + // frame, so we need to update the value for the new frame.
|
| value += (target - value) * discreteTimeConstant;
|
| }
|
| }
|
|
|
| - // If the value is close enough to the target, just fill in the data with the
|
| - // target value.
|
| + // If the value is close enough to the target, just fill in the data
|
| + // with the target value.
|
| if (fabs(value - target) < kSetTargetThreshold * fabs(target) ||
|
| (!target && fabs(value) < kSetTargetZeroThreshold)) {
|
| for (; writeIndex < fillToFrame; ++writeIndex)
|
| values[writeIndex] = target;
|
| } else {
|
| #if CPU(X86) || CPU(X86_64)
|
| - // Resolve recursion by expanding constants to achieve a 4-step loop unrolling.
|
| + // Resolve recursion by expanding constants to achieve a 4-step loop
|
| + // unrolling.
|
| // v1 = v0 + (t - v0) * c
|
| // v2 = v1 + (t - v1) * c
|
| // v2 = v0 + (t - v0) * c + (t - (v0 + (t - v0) * c)) * c
|
| @@ -830,8 +851,8 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| values[writeIndex] = value;
|
| value += (target - value) * discreteTimeConstant;
|
| }
|
| - // The previous loops may have updated |value| one extra time. Reset it to
|
| - // the last computed value.
|
| + // The previous loops may have updated |value| one extra time.
|
| + // Reset it to the last computed value.
|
| if (writeIndex >= 1)
|
| value = values[writeIndex - 1];
|
| currentFrame = fillToEndFrame;
|
| @@ -846,8 +867,8 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
|
|
| // Curve events have duration, so don't just use next event time.
|
| double duration = event.duration();
|
| - // How much to step the curve index for each frame. This is basically the term
|
| - // (N - 1)/Td in the specification.
|
| + // How much to step the curve index for each frame. This is basically
|
| + // the term (N - 1)/Td in the specification.
|
| double curvePointsPerFrame =
|
| (numberOfCurvePoints - 1) / duration / sampleRate;
|
|
|
| @@ -859,14 +880,15 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| break;
|
| }
|
|
|
| - // Save old values and recalculate information based on the curve's duration
|
| - // instead of the next event time.
|
| + // Save old values and recalculate information based on the curve's
|
| + // duration instead of the next event time.
|
| size_t nextEventFillToFrame = fillToFrame;
|
|
|
| - // fillToEndFrame = min(endFrame, ceil(sampleRate * (time1 + duration))), but
|
| - // compute this carefully in case sampleRate*(time1 + duration) is huge.
|
| - // fillToEndFrame is an exclusive upper bound of the last frame to be computed,
|
| - // so ceil is used.
|
| + // fillToEndFrame = min(endFrame,
|
| + // ceil(sampleRate * (time1 + duration))),
|
| + // but compute this carefully in case sampleRate*(time1 + duration) is
|
| + // huge. fillToEndFrame is an exclusive upper bound of the last frame
|
| + // to be computed, so ceil is used.
|
| {
|
| double curveEndFrame = ceil(sampleRate * (time1 + duration));
|
| if (endFrame > curveEndFrame)
|
| @@ -876,21 +898,23 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| }
|
|
|
| // |fillToFrame| can be less than |startFrame| when the end of the
|
| - // setValueCurve automation has been reached, but the next automation has not
|
| - // yet started. In this case, |fillToFrame| is clipped to |time1|+|duration|
|
| - // above, but |startFrame| will keep increasing (because the current time is
|
| - // increasing).
|
| + // setValueCurve automation has been reached, but the next automation
|
| + // has not yet started. In this case, |fillToFrame| is clipped to
|
| + // |time1|+|duration| above, but |startFrame| will keep increasing
|
| + // (because the current time is increasing).
|
| fillToFrame =
|
| (fillToEndFrame < startFrame) ? 0 : fillToEndFrame - startFrame;
|
| fillToFrame =
|
| std::min(fillToFrame, static_cast<size_t>(numberOfValues));
|
|
|
| // Index into the curve data using a floating-point value.
|
| - // We're scaling the number of curve points by the duration (see curvePointsPerFrame).
|
| + // We're scaling the number of curve points by the duration (see
|
| + // curvePointsPerFrame).
|
| double curveVirtualIndex = 0;
|
| if (time1 < currentFrame / sampleRate) {
|
| // Index somewhere in the middle of the curve data.
|
| - // Don't use timeToSampleFrame() since we want the exact floating-point frame.
|
| + // Don't use timeToSampleFrame() since we want the exact
|
| + // floating-point frame.
|
| double frameOffset = currentFrame - time1 * sampleRate;
|
| curveVirtualIndex = curvePointsPerFrame * frameOffset;
|
| }
|
| @@ -898,8 +922,9 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| // Set the default value in case fillToFrame is 0.
|
| value = curveData[numberOfCurvePoints - 1];
|
|
|
| - // Render the stretched curve data using linear interpolation. Oversampled
|
| - // curve data can be provided if sharp discontinuities are desired.
|
| + // Render the stretched curve data using linear interpolation.
|
| + // Oversampled curve data can be provided if sharp discontinuities are
|
| + // desired.
|
| unsigned k = 0;
|
| #if CPU(X86) || CPU(X86_64)
|
| const __m128 vCurveVirtualIndex = _mm_set_ps1(curveVirtualIndex);
|
| @@ -917,8 +942,8 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| unsigned truncatedSteps = ((fillToFrame - writeIndex) / 4) * 4;
|
| unsigned fillToFrameTrunc = writeIndex + truncatedSteps;
|
| for (; writeIndex < fillToFrameTrunc; writeIndex += 4) {
|
| - // Compute current index this way to minimize round-off that would have
|
| - // occurred by incrementing the index by curvePointsPerFrame.
|
| + // Compute current index this way to minimize round-off that would
|
| + // have occurred by incrementing the index by curvePointsPerFrame.
|
| __m128 vCurrentVirtualIndex = _mm_add_ps(
|
| vCurveVirtualIndex, _mm_mul_ps(vK, vCurvePointsPerFrame));
|
| vK = _mm_add_ps(vK, vN4);
|
| @@ -929,10 +954,11 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| __m128i vCurveIndex1 = _mm_cvttps_epi32(_mm_min_ps(
|
| _mm_add_ps(vCurrentVirtualIndex, vN1), vNumberOfCurvePointsM1));
|
|
|
| - // Linearly interpolate between the two nearest curve points. |delta| is
|
| - // clamped to 1 because currentVirtualIndex can exceed curveIndex0 by more
|
| - // than one. This can happen when we reached the end of the curve but still
|
| - // need values to fill out the current rendering quantum.
|
| + // Linearly interpolate between the two nearest curve points.
|
| + // |delta| is clamped to 1 because currentVirtualIndex can exceed
|
| + // curveIndex0 by more than one. This can happen when we reached
|
| + // the end of the curve but still need values to fill out the
|
| + // current rendering quantum.
|
| _mm_storeu_si128((__m128i*)aCurveIndex0, vCurveIndex0);
|
| _mm_storeu_si128((__m128i*)aCurveIndex1, vCurveIndex1);
|
| __m128 vC0 = _mm_set_ps(
|
| @@ -958,8 +984,8 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| }
|
| #endif
|
| for (; writeIndex < fillToFrame; ++writeIndex, ++k) {
|
| - // Compute current index this way to minimize round-off that would have
|
| - // occurred by incrementing the index by curvePointsPerFrame.
|
| + // Compute current index this way to minimize round-off that would
|
| + // have occurred by incrementing the index by curvePointsPerFrame.
|
| double currentVirtualIndex =
|
| curveVirtualIndex + k * curvePointsPerFrame;
|
| unsigned curveIndex0;
|
| @@ -974,10 +1000,11 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| unsigned curveIndex1 =
|
| std::min(curveIndex0 + 1, numberOfCurvePoints - 1);
|
|
|
| - // Linearly interpolate between the two nearest curve points. |delta| is
|
| - // clamped to 1 because currentVirtualIndex can exceed curveIndex0 by more
|
| - // than one. This can happen when we reached the end of the curve but still
|
| - // need values to fill out the current rendering quantum.
|
| + // Linearly interpolate between the two nearest curve points.
|
| + // |delta| is clamped to 1 because currentVirtualIndex can exceed
|
| + // curveIndex0 by more than one. This can happen when we reached
|
| + // the end of the curve but still need values to fill out the
|
| + // current rendering quantum.
|
| DCHECK_LT(curveIndex0, numberOfCurvePoints);
|
| DCHECK_LT(curveIndex1, numberOfCurvePoints);
|
| float c0 = curveData[curveIndex0];
|
| @@ -989,8 +1016,9 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| values[writeIndex] = value;
|
| }
|
|
|
| - // If there's any time left after the duration of this event and the start
|
| - // of the next, then just propagate the last value of the curveData.
|
| + // If there's any time left after the duration of this event and the
|
| + // start of the next, then just propagate the last value of the
|
| + // curveData.
|
| if (writeIndex < nextEventFillToFrame)
|
| value = curveData[numberOfCurvePoints - 1];
|
| for (; writeIndex < nextEventFillToFrame; ++writeIndex)
|
| @@ -1015,13 +1043,13 @@ float AudioParamTimeline::valuesForFrameRangeImpl(size_t startFrame,
|
| if (lastSkippedEventIndex > 0)
|
| m_events.remove(0, lastSkippedEventIndex - 1);
|
|
|
| - // If there's any time left after processing the last event then just propagate the last value
|
| - // to the end of the values buffer.
|
| + // If there's any time left after processing the last event then just
|
| + // propagate the last value to the end of the values buffer.
|
| for (; writeIndex < numberOfValues; ++writeIndex)
|
| values[writeIndex] = value;
|
|
|
| - // This value is used to set the .value attribute of the AudioParam. it should be the last
|
| - // computed value.
|
| + // This value is used to set the .value attribute of the AudioParam. it
|
| + // should be the last computed value.
|
| return values[numberOfValues - 1];
|
| }
|
|
|
|
|