зеркало из https://github.com/mozilla/gecko-dev.git
Bug 897092 - Fix setTargetAtTime glitch. r=ehsan
--HG-- extra : rebase_source : 8b1162e7721637df2b8a2faad849609d3177369b
This commit is contained in:
Родитель
54f5b5ae26
Коммит
f2e69e21d4
|
@ -160,7 +160,9 @@ class AudioEventTimeline
|
|||
{
|
||||
public:
|
||||
explicit AudioEventTimeline(float aDefaultValue)
|
||||
: mValue(aDefaultValue)
|
||||
: mValue(aDefaultValue),
|
||||
mComputedValue(aDefaultValue),
|
||||
mLastComputedValue(aDefaultValue)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -186,7 +188,7 @@ public:
|
|||
{
|
||||
// Silently don't change anything if there are any events
|
||||
if (mEvents.IsEmpty()) {
|
||||
mValue = aValue;
|
||||
mLastComputedValue = mComputedValue = mValue = aValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,9 +239,29 @@ public:
|
|||
mEvents.Clear();
|
||||
}
|
||||
|
||||
static bool TimesEqual(int64_t aLhs, int64_t aRhs)
|
||||
{
|
||||
return aLhs == aRhs;
|
||||
}
|
||||
|
||||
// Since we are going to accumulate error by adding 0.01 multiple time in a
|
||||
// loop, we want to fuzz the equality check in GetValueAtTime.
|
||||
static bool TimesEqual(double aLhs, double aRhs)
|
||||
{
|
||||
const float kEpsilon = 0.0000000001f;
|
||||
return fabs(aLhs - aRhs) < kEpsilon;
|
||||
}
|
||||
|
||||
template<class TimeType>
|
||||
float GetValueAtTime(TimeType aTime)
|
||||
{
|
||||
mComputedValue = GetValueAtTimeHelper(aTime);
|
||||
return mComputedValue;
|
||||
}
|
||||
|
||||
// This method computes the AudioParam value at a given time based on the event timeline
|
||||
template<class TimeType>
|
||||
float GetValueAtTime(TimeType aTime) const
|
||||
float GetValueAtTimeHelper(TimeType aTime)
|
||||
{
|
||||
const AudioTimelineEvent* previous = nullptr;
|
||||
const AudioTimelineEvent* next = nullptr;
|
||||
|
@ -252,7 +274,8 @@ public:
|
|||
case AudioTimelineEvent::LinearRamp:
|
||||
case AudioTimelineEvent::ExponentialRamp:
|
||||
case AudioTimelineEvent::SetValueCurve:
|
||||
if (aTime == mEvents[i].template Time<TimeType>()) {
|
||||
if (TimesEqual(aTime, mEvents[i].template Time<TimeType>())) {
|
||||
mLastComputedValue = mComputedValue;
|
||||
// Find the last event with the same time
|
||||
do {
|
||||
++i;
|
||||
|
@ -261,13 +284,14 @@ public:
|
|||
|
||||
// SetTarget nodes can be handled no matter what their next node is (if they have one)
|
||||
if (mEvents[i - 1].mType == AudioTimelineEvent::SetTarget) {
|
||||
// Follow the curve, without regard to the next node
|
||||
// Follow the curve, without regard to the next event, starting at
|
||||
// the last value of the last event.
|
||||
return ExponentialApproach(mEvents[i - 1].template Time<TimeType>(),
|
||||
mValue, mEvents[i - 1].mValue,
|
||||
mLastComputedValue, mEvents[i - 1].mValue,
|
||||
mEvents[i - 1].mTimeConstant, aTime);
|
||||
}
|
||||
|
||||
// SetValueCurve events can be handled no mattar what their next node is (if they have one)
|
||||
// SetValueCurve events can be handled no matter what their event node is (if they have one)
|
||||
if (mEvents[i - 1].mType == AudioTimelineEvent::SetValueCurve) {
|
||||
return ExtractValueFromCurve(mEvents[i - 1].template Time<TimeType>(),
|
||||
mEvents[i - 1].mCurve,
|
||||
|
@ -306,8 +330,8 @@ public:
|
|||
|
||||
// SetTarget nodes can be handled no matter what their next node is (if they have one)
|
||||
if (previous->mType == AudioTimelineEvent::SetTarget) {
|
||||
// Follow the curve, without regard to the next node
|
||||
return ExponentialApproach(previous->template Time<TimeType>(), mValue, previous->mValue,
|
||||
return ExponentialApproach(previous->template Time<TimeType>(),
|
||||
mLastComputedValue, previous->mValue,
|
||||
previous->mTimeConstant, aTime);
|
||||
}
|
||||
|
||||
|
@ -540,6 +564,10 @@ private:
|
|||
// being a bottleneck.
|
||||
nsTArray<AudioTimelineEvent> mEvents;
|
||||
float mValue;
|
||||
// This is the value of this AudioParam we computed at the last call.
|
||||
float mComputedValue;
|
||||
// This is the value of this AudioParam at the last tick of the previous event.
|
||||
float mLastComputedValue;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
// getting the value of an a-rate AudioParam for each tick inside an
|
||||
// AudioNodeEngine implementation.
|
||||
template<class TimeType>
|
||||
float GetValueAtTime(TimeType aTime, size_t aCounter = 0) const
|
||||
float GetValueAtTime(TimeType aTime, size_t aCounter = 0)
|
||||
{
|
||||
MOZ_ASSERT(aCounter < WEBAUDIO_BLOCK_SIZE);
|
||||
MOZ_ASSERT(!aCounter || !HasSimpleValue());
|
||||
|
|
|
@ -314,6 +314,15 @@ void TestAfterLastTargetValueEventWithValueSet()
|
|||
|
||||
timeline.SetValue(50.f);
|
||||
timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv);
|
||||
|
||||
// When using SetTargetValueAtTime, Timeline become stateful: the value for
|
||||
// time t may depend on the time t-1, so we can't just query the value at a
|
||||
// time and get the right value. We have to call GetValueAtTime for the
|
||||
// previous times.
|
||||
for (double i = 0.0; i < 9.99; i+=0.01) {
|
||||
timeline.GetValueAtTime(i);
|
||||
}
|
||||
|
||||
is(timeline.GetValueAtTime(10.), (20.f + (50.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after SetValue and the last SetTarget event based on the curve");
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var V0 = 0.1;
|
||||
var V1 = 0.9;
|
||||
var V0 = 0.9;
|
||||
var V1 = 0.1;
|
||||
var T0 = 0;
|
||||
var TimeConstant = 10;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче