mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 836076 - Part 5: Provide an API for converting event times to tick values; r=roc
This commit is contained in:
parent
030416b20c
commit
61bbd92228
@ -33,6 +33,9 @@ struct AudioTimelineEvent {
|
||||
: mType(aType)
|
||||
, mTimeConstant(aTimeConstant)
|
||||
, mDuration(aDuration)
|
||||
#ifdef DEBUG
|
||||
, mTimeIsInTicks(false)
|
||||
#endif
|
||||
{
|
||||
if (aType == AudioTimelineEvent::SetValueCurve) {
|
||||
mCurve = aCurve;
|
||||
@ -51,17 +54,39 @@ struct AudioTimelineEvent {
|
||||
IsValid(mDuration);
|
||||
}
|
||||
|
||||
template <class TimeType>
|
||||
TimeType Time() const;
|
||||
|
||||
void SetTimeInTicks(int64_t aTimeInTicks)
|
||||
{
|
||||
mTimeInTicks = aTimeInTicks;
|
||||
#ifdef DEBUG
|
||||
mTimeIsInTicks = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Type mType;
|
||||
union {
|
||||
float mValue;
|
||||
uint32_t mCurveLength;
|
||||
};
|
||||
union {
|
||||
double mTime;
|
||||
// The time for an event can either be in absolute value or in ticks.
|
||||
// Initially the time of the event is always in absolute value.
|
||||
// In order to convert it to ticks, call SetTimeInTicks. Once this
|
||||
// method has been called for an event, the time cannot be converted
|
||||
// back to absolute value.
|
||||
union {
|
||||
double mTime;
|
||||
int64_t mTimeInTicks;
|
||||
};
|
||||
float* mCurve;
|
||||
};
|
||||
double mTimeConstant;
|
||||
double mDuration;
|
||||
#ifdef DEBUG
|
||||
bool mTimeIsInTicks;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static bool IsValid(double value)
|
||||
@ -70,6 +95,20 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
inline double AudioTimelineEvent::Time<double>() const
|
||||
{
|
||||
MOZ_ASSERT(!mTimeIsInTicks);
|
||||
return mTime;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int64_t AudioTimelineEvent::Time<int64_t>() const
|
||||
{
|
||||
MOZ_ASSERT(mTimeIsInTicks);
|
||||
return mTimeInTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class will be instantiated with different template arguments for testing and
|
||||
* production code.
|
||||
@ -151,7 +190,8 @@ public:
|
||||
}
|
||||
|
||||
// This method computes the AudioParam value at a given time based on the event timeline
|
||||
float GetValueAtTime(double aTime) const
|
||||
template<class TimeType>
|
||||
float GetValueAtTime(TimeType aTime) const
|
||||
{
|
||||
const AudioTimelineEvent* previous = nullptr;
|
||||
const AudioTimelineEvent* next = nullptr;
|
||||
@ -163,17 +203,17 @@ public:
|
||||
case AudioTimelineEvent::SetTarget:
|
||||
case AudioTimelineEvent::LinearRamp:
|
||||
case AudioTimelineEvent::ExponentialRamp:
|
||||
if (aTime == mEvents[i].mTime) {
|
||||
if (aTime == mEvents[i].template Time<TimeType>()) {
|
||||
// Find the last event with the same time
|
||||
do {
|
||||
++i;
|
||||
} while (i < mEvents.Length() &&
|
||||
aTime == mEvents[i].mTime);
|
||||
aTime == mEvents[i].template Time<TimeType>());
|
||||
return mEvents[i - 1].mValue;
|
||||
}
|
||||
previous = next;
|
||||
next = &mEvents[i];
|
||||
if (aTime < mEvents[i].mTime) {
|
||||
if (aTime < mEvents[i].template Time<TimeType>()) {
|
||||
bailOut = true;
|
||||
}
|
||||
break;
|
||||
@ -204,10 +244,10 @@ public:
|
||||
return mValue;
|
||||
case AudioTimelineEvent::LinearRamp:
|
||||
// Use t=0 as T0 and v=defaultValue as V0
|
||||
return LinearInterpolate(0.0, mValue, next->mTime, next->mValue, aTime);
|
||||
return LinearInterpolate(0.0, mValue, next->template Time<TimeType>(), next->mValue, aTime);
|
||||
case AudioTimelineEvent::ExponentialRamp:
|
||||
// Use t=0 as T0 and v=defaultValue as V0
|
||||
return ExponentialInterpolate(0.0, mValue, next->mTime, next->mValue, aTime);
|
||||
return ExponentialInterpolate(0.0, mValue, next->template Time<TimeType>(), next->mValue, aTime);
|
||||
case AudioTimelineEvent::SetValueCurve:
|
||||
// TODO: implement
|
||||
return 0.0f;
|
||||
@ -218,7 +258,7 @@ 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->mTime, mValue, previous->mValue,
|
||||
return ExponentialApproach(previous->template Time<TimeType>(), mValue, previous->mValue,
|
||||
previous->mTimeConstant, aTime);
|
||||
}
|
||||
|
||||
@ -244,9 +284,9 @@ public:
|
||||
// First, handle the case where our range ends up in a ramp event
|
||||
switch (next->mType) {
|
||||
case AudioTimelineEvent::LinearRamp:
|
||||
return LinearInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime);
|
||||
return LinearInterpolate(previous->template Time<TimeType>(), previous->mValue, next->template Time<TimeType>(), next->mValue, aTime);
|
||||
case AudioTimelineEvent::ExponentialRamp:
|
||||
return ExponentialInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime);
|
||||
return ExponentialInterpolate(previous->template Time<TimeType>(), previous->mValue, next->template Time<TimeType>(), next->mValue, aTime);
|
||||
case AudioTimelineEvent::SetValue:
|
||||
case AudioTimelineEvent::SetTarget:
|
||||
case AudioTimelineEvent::SetValueCurve:
|
||||
@ -293,6 +333,13 @@ public:
|
||||
return v1 + (v0 - v1) * expf(-(t - t0) / timeConstant);
|
||||
}
|
||||
|
||||
void ConvertEventTimesToTicks(int64_t (*aConvertor)(double aTime, void* aClosure), void* aClosure)
|
||||
{
|
||||
for (unsigned i = 0; i < mEvents.Length(); ++i) {
|
||||
mEvents[i].SetTimeInTicks(aConvertor(mEvents[i].template Time<double>(), aClosure));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const AudioTimelineEvent* GetPreviousEvent(double aTime) const
|
||||
{
|
||||
|
@ -91,14 +91,14 @@ void TestSpecExample()
|
||||
ErrorResultMock rv;
|
||||
|
||||
// This test is copied from the example in the Web Audio spec
|
||||
const float t0 = 0.0,
|
||||
t1 = 0.1,
|
||||
t2 = 0.2,
|
||||
t3 = 0.3,
|
||||
t4 = 0.4,
|
||||
t5 = 0.6,
|
||||
t6 = 0.7/*,
|
||||
t7 = 1.0*/;
|
||||
const double t0 = 0.0,
|
||||
t1 = 0.1,
|
||||
t2 = 0.2,
|
||||
t3 = 0.3,
|
||||
t4 = 0.4,
|
||||
t5 = 0.6,
|
||||
t6 = 0.7/*,
|
||||
t7 = 1.0*/;
|
||||
timeline.SetValueAtTime(0.2f, t0, rv);
|
||||
is(rv, NS_OK, "SetValueAtTime succeeded");
|
||||
timeline.SetValueAtTime(0.3f, t1, rv);
|
||||
@ -115,22 +115,22 @@ void TestSpecExample()
|
||||
is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded");
|
||||
// TODO: Add the SetValueCurveAtTime test
|
||||
|
||||
is(timeline.GetValueAtTime(0.0f), 0.2f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.05f), 0.2f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.1f), 0.3f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.15f), 0.3f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.2f), 0.4f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.25f), (0.4f + 1.0f) / 2, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.3f), 1.0f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.35f), (1.0f + 0.15f) / 2, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.4f), 0.15f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.45f), (0.15f * powf(0.75f / 0.15f, 0.05f / 0.2f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.5f), (0.15f * powf(0.75f / 0.15f, 0.5f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.55f), (0.15f * powf(0.75f / 0.15f, 0.15f / 0.2f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.6f), 0.75f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.65f), (0.75f * powf(0.05 / 0.75f, 0.5f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.7f), 0.05f, "Correct value");
|
||||
is(timeline.GetValueAtTime(1.0f), 0.05f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.0), 0.2f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.05), 0.2f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.1), 0.3f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.15), 0.3f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.2), 0.4f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.25), (0.4f + 1.0f) / 2, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.3), 1.0f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.35), (1.0f + 0.15f) / 2, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.4), 0.15f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.45), (0.15f * powf(0.75f / 0.15f, 0.05f / 0.2f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.5), (0.15f * powf(0.75f / 0.15f, 0.5f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.55), (0.15f * powf(0.75f / 0.15f, 0.15f / 0.2f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.6), 0.75f, "Correct value");
|
||||
is(timeline.GetValueAtTime(0.65), (0.75f * powf(0.05 / 0.75f, 0.5f)), "Correct value");
|
||||
is(timeline.GetValueAtTime(0.7), 0.05f, "Correct value");
|
||||
is(timeline.GetValueAtTime(1.0), 0.05f, "Correct value");
|
||||
}
|
||||
|
||||
void TestInvalidEvents()
|
||||
@ -189,11 +189,11 @@ void TestEventReplacement()
|
||||
timeline.SetValueAtTime(20.0f, 0.1, rv);
|
||||
is(rv, NS_OK, "Event scheduling should be successful");
|
||||
is(timeline.GetEventCount(), 1u, "Event should be replaced");
|
||||
is(timeline.GetValueAtTime(0.1f), 20.0f, "The first event should be overwritten");
|
||||
is(timeline.GetValueAtTime(0.1), 20.0f, "The first event should be overwritten");
|
||||
timeline.LinearRampToValueAtTime(30.0f, 0.1, rv);
|
||||
is(rv, NS_OK, "Event scheduling should be successful");
|
||||
is(timeline.GetEventCount(), 2u, "Different event type should be appended");
|
||||
is(timeline.GetValueAtTime(0.1f), 30.0f, "The first event should be overwritten");
|
||||
is(timeline.GetValueAtTime(0.1), 30.0f, "The first event should be overwritten");
|
||||
}
|
||||
|
||||
void TestEventRemoval()
|
||||
@ -222,7 +222,7 @@ void TestBeforeFirstEvent()
|
||||
ErrorResultMock rv;
|
||||
|
||||
timeline.SetValueAtTime(20.0f, 1.0, rv);
|
||||
is(timeline.GetValueAtTime(0.5f), 10.0f, "Retrun the default value before the first event");
|
||||
is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event");
|
||||
}
|
||||
|
||||
void TestAfterLastValueEvent()
|
||||
@ -232,7 +232,7 @@ void TestAfterLastValueEvent()
|
||||
ErrorResultMock rv;
|
||||
|
||||
timeline.SetValueAtTime(20.0f, 1.0, rv);
|
||||
is(timeline.GetValueAtTime(1.5f), 20.0f, "Return the last value after the last SetValue event");
|
||||
is(timeline.GetValueAtTime(1.5), 20.0f, "Return the last value after the last SetValue event");
|
||||
}
|
||||
|
||||
void TestAfterLastTargetValueEvent()
|
||||
@ -242,7 +242,7 @@ void TestAfterLastTargetValueEvent()
|
||||
ErrorResultMock rv;
|
||||
|
||||
timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv);
|
||||
is(timeline.GetValueAtTime(10.f), (20.f + (10.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after the last SetTarget event based on the curve");
|
||||
is(timeline.GetValueAtTime(10.), (20.f + (10.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after the last SetTarget event based on the curve");
|
||||
}
|
||||
|
||||
void TestAfterLastTargetValueEventWithValueSet()
|
||||
@ -253,7 +253,7 @@ void TestAfterLastTargetValueEventWithValueSet()
|
||||
|
||||
timeline.SetValue(50.f);
|
||||
timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv);
|
||||
is(timeline.GetValueAtTime(10.f), (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");
|
||||
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");
|
||||
}
|
||||
|
||||
void TestValue()
|
||||
@ -279,7 +279,7 @@ void TestLinearRampAtZero()
|
||||
ErrorResultMock rv;
|
||||
|
||||
timeline.LinearRampToValueAtTime(20.0f, 0.0, rv);
|
||||
is(timeline.GetValueAtTime(0.0f), 20.0f, "Should get the correct value when t0 == t1 == 0");
|
||||
is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0");
|
||||
}
|
||||
|
||||
void TestExponentialRampAtZero()
|
||||
@ -289,7 +289,7 @@ void TestExponentialRampAtZero()
|
||||
ErrorResultMock rv;
|
||||
|
||||
timeline.ExponentialRampToValueAtTime(20.0f, 0.0, rv);
|
||||
is(timeline.GetValueAtTime(0.0f), 20.0f, "Should get the correct value when t0 == t1 == 0");
|
||||
is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0");
|
||||
}
|
||||
|
||||
void TestLinearRampAtSameTime()
|
||||
@ -300,7 +300,7 @@ void TestLinearRampAtSameTime()
|
||||
|
||||
timeline.SetValueAtTime(5.0f, 1.0, rv);
|
||||
timeline.LinearRampToValueAtTime(20.0f, 1.0, rv);
|
||||
is(timeline.GetValueAtTime(1.0f), 20.0f, "Should get the correct value when t0 == t1");
|
||||
is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1");
|
||||
}
|
||||
|
||||
void TestExponentialRampAtSameTime()
|
||||
@ -311,7 +311,7 @@ void TestExponentialRampAtSameTime()
|
||||
|
||||
timeline.SetValueAtTime(5.0f, 1.0, rv);
|
||||
timeline.ExponentialRampToValueAtTime(20.0f, 1.0, rv);
|
||||
is(timeline.GetValueAtTime(1.0f), 20.0f, "Should get the correct value when t0 == t1");
|
||||
is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1");
|
||||
}
|
||||
|
||||
void TestSetTargetZeroTimeConstant()
|
||||
@ -321,7 +321,7 @@ void TestSetTargetZeroTimeConstant()
|
||||
ErrorResultMock rv;
|
||||
|
||||
timeline.SetTargetAtTime(20.0f, 1.0, 0.0, rv);
|
||||
is(timeline.GetValueAtTime(10.f), 20.f, "Should get the correct value with timeConstant == 0");
|
||||
is(timeline.GetValueAtTime(10.), 20.f, "Should get the correct value with timeConstant == 0");
|
||||
}
|
||||
|
||||
void TestExponentialInvalidPreviousZeroValue()
|
||||
|
Loading…
Reference in New Issue
Block a user