Bug 897092 - Fix setTargetAtTime glitch. r=ehsan

--HG--
extra : rebase_source : 8b1162e7721637df2b8a2faad849609d3177369b
This commit is contained in:
Paul Adenot 2013-08-09 15:11:03 +02:00
Родитель 54f5b5ae26
Коммит f2e69e21d4
4 изменённых файлов: 49 добавлений и 12 удалений

Просмотреть файл

@ -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;