Bug 836076 - Part 4: Move AudioEventTimeline::Event outside of AudioEventTimeline to be able to specialize its template members; r=roc

This commit is contained in:
Ehsan Akhgari 2013-03-01 17:01:43 -05:00
parent 6bc6665342
commit 030416b20c

View File

@ -18,6 +18,58 @@ namespace mozilla {
namespace dom { namespace dom {
// This is an internal helper class and should not be used outside of this header.
struct AudioTimelineEvent {
enum Type MOZ_ENUM_TYPE(uint32_t) {
SetValue,
LinearRamp,
ExponentialRamp,
SetTarget,
SetValueCurve
};
AudioTimelineEvent(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
float aDuration = 0.0, float* aCurve = nullptr, uint32_t aCurveLength = 0)
: mType(aType)
, mTimeConstant(aTimeConstant)
, mDuration(aDuration)
{
if (aType == AudioTimelineEvent::SetValueCurve) {
mCurve = aCurve;
mCurveLength = aCurveLength;
} else {
mValue = aValue;
mTime = aTime;
}
}
bool IsValid() const
{
return IsValid(mTime) &&
IsValid(mValue) &&
IsValid(mTimeConstant) &&
IsValid(mDuration);
}
Type mType;
union {
float mValue;
uint32_t mCurveLength;
};
union {
double mTime;
float* mCurve;
};
double mTimeConstant;
double mDuration;
private:
static bool IsValid(double value)
{
return MOZ_DOUBLE_IS_FINITE(value);
}
};
/** /**
* This class will be instantiated with different template arguments for testing and * This class will be instantiated with different template arguments for testing and
* production code. * production code.
@ -28,58 +80,6 @@ namespace dom {
template <class ErrorResult> template <class ErrorResult>
class AudioEventTimeline class AudioEventTimeline
{ {
private:
struct Event {
enum Type MOZ_ENUM_TYPE(uint32_t) {
SetValue,
LinearRamp,
ExponentialRamp,
SetTarget,
SetValueCurve
};
Event(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
float aDuration = 0.0, float* aCurve = nullptr, uint32_t aCurveLength = 0)
: mType(aType)
, mTimeConstant(aTimeConstant)
, mDuration(aDuration)
{
if (aType == Event::SetValueCurve) {
mCurve = aCurve;
mCurveLength = aCurveLength;
} else {
mValue = aValue;
mTime = aTime;
}
}
bool IsValid() const
{
return IsValid(mTime) &&
IsValid(mValue) &&
IsValid(mTimeConstant) &&
IsValid(mDuration);
}
Type mType;
union {
float mValue;
uint32_t mCurveLength;
};
union {
double mTime;
float* mCurve;
};
double mTimeConstant;
double mDuration;
private:
static bool IsValid(double value)
{
return MOZ_DOUBLE_IS_FINITE(value);
}
};
public: public:
explicit AudioEventTimeline(float aDefaultValue) explicit AudioEventTimeline(float aDefaultValue)
: mValue(aDefaultValue) : mValue(aDefaultValue)
@ -108,29 +108,29 @@ public:
void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv) void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
{ {
InsertEvent(Event(Event::SetValue, aStartTime, aValue), aRv); InsertEvent(AudioTimelineEvent(AudioTimelineEvent::SetValue, aStartTime, aValue), aRv);
} }
void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv) void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
{ {
InsertEvent(Event(Event::LinearRamp, aEndTime, aValue), aRv); InsertEvent(AudioTimelineEvent(AudioTimelineEvent::LinearRamp, aEndTime, aValue), aRv);
} }
void ExponentialRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv) void ExponentialRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
{ {
InsertEvent(Event(Event::ExponentialRamp, aEndTime, aValue), aRv); InsertEvent(AudioTimelineEvent(AudioTimelineEvent::ExponentialRamp, aEndTime, aValue), aRv);
} }
void SetTargetAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv) void SetTargetAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv)
{ {
InsertEvent(Event(Event::SetTarget, aStartTime, aTarget, aTimeConstant), aRv); InsertEvent(AudioTimelineEvent(AudioTimelineEvent::SetTarget, aStartTime, aTarget, aTimeConstant), aRv);
} }
void SetValueCurveAtTime(const float* aValues, uint32_t aValuesLength, double aStartTime, double aDuration, ErrorResult& aRv) void SetValueCurveAtTime(const float* aValues, uint32_t aValuesLength, double aStartTime, double aDuration, ErrorResult& aRv)
{ {
// TODO: implement // TODO: implement
// Note that we will need to copy the buffer here. // Note that we will need to copy the buffer here.
// InsertEvent(Event(Event::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues, aValuesLength), aRv); // InsertEvent(AudioTimelineEvent(AudioTimelineEvent::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues, aValuesLength), aRv);
} }
void CancelScheduledValues(double aStartTime) void CancelScheduledValues(double aStartTime)
@ -153,16 +153,16 @@ public:
// This method computes the AudioParam value at a given time based on the event timeline // This method computes the AudioParam value at a given time based on the event timeline
float GetValueAtTime(double aTime) const float GetValueAtTime(double aTime) const
{ {
const Event* previous = nullptr; const AudioTimelineEvent* previous = nullptr;
const Event* next = nullptr; const AudioTimelineEvent* next = nullptr;
bool bailOut = false; bool bailOut = false;
for (unsigned i = 0; !bailOut && i < mEvents.Length(); ++i) { for (unsigned i = 0; !bailOut && i < mEvents.Length(); ++i) {
switch (mEvents[i].mType) { switch (mEvents[i].mType) {
case Event::SetValue: case AudioTimelineEvent::SetValue:
case Event::SetTarget: case AudioTimelineEvent::SetTarget:
case Event::LinearRamp: case AudioTimelineEvent::LinearRamp:
case Event::ExponentialRamp: case AudioTimelineEvent::ExponentialRamp:
if (aTime == mEvents[i].mTime) { if (aTime == mEvents[i].mTime) {
// Find the last event with the same time // Find the last event with the same time
do { do {
@ -177,7 +177,7 @@ public:
bailOut = true; bailOut = true;
} }
break; break;
case Event::SetValueCurve: case AudioTimelineEvent::SetValueCurve:
// TODO: implement // TODO: implement
break; break;
default: default:
@ -198,17 +198,17 @@ public:
// If the requested time is before all of the existing events // If the requested time is before all of the existing events
if (!previous) { if (!previous) {
switch (next->mType) { switch (next->mType) {
case Event::SetValue: case AudioTimelineEvent::SetValue:
case Event::SetTarget: case AudioTimelineEvent::SetTarget:
// The requested time is before the first event // The requested time is before the first event
return mValue; return mValue;
case Event::LinearRamp: case AudioTimelineEvent::LinearRamp:
// Use t=0 as T0 and v=defaultValue as V0 // 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->mTime, next->mValue, aTime);
case Event::ExponentialRamp: case AudioTimelineEvent::ExponentialRamp:
// Use t=0 as T0 and v=defaultValue as V0 // 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->mTime, next->mValue, aTime);
case Event::SetValueCurve: case AudioTimelineEvent::SetValueCurve:
// TODO: implement // TODO: implement
return 0.0f; return 0.0f;
} }
@ -216,7 +216,7 @@ public:
} }
// SetTarget nodes can be handled no matter what their next node is (if they have one) // SetTarget nodes can be handled no matter what their next node is (if they have one)
if (previous->mType == Event::SetTarget) { if (previous->mType == AudioTimelineEvent::SetTarget) {
// Follow the curve, without regard to the next node // Follow the curve, without regard to the next node
return ExponentialApproach(previous->mTime, mValue, previous->mValue, return ExponentialApproach(previous->mTime, mValue, previous->mValue,
previous->mTimeConstant, aTime); previous->mTimeConstant, aTime);
@ -225,15 +225,15 @@ public:
// If the requested time is after all of the existing events // If the requested time is after all of the existing events
if (!next) { if (!next) {
switch (previous->mType) { switch (previous->mType) {
case Event::SetValue: case AudioTimelineEvent::SetValue:
case Event::LinearRamp: case AudioTimelineEvent::LinearRamp:
case Event::ExponentialRamp: case AudioTimelineEvent::ExponentialRamp:
// The value will be constant after the last event // The value will be constant after the last event
return previous->mValue; return previous->mValue;
case Event::SetValueCurve: case AudioTimelineEvent::SetValueCurve:
// TODO: implement // TODO: implement
return 0.0f; return 0.0f;
case Event::SetTarget: case AudioTimelineEvent::SetTarget:
MOZ_ASSERT(false, "unreached"); MOZ_ASSERT(false, "unreached");
} }
MOZ_ASSERT(false, "unreached"); MOZ_ASSERT(false, "unreached");
@ -243,28 +243,28 @@ public:
// First, handle the case where our range ends up in a ramp event // First, handle the case where our range ends up in a ramp event
switch (next->mType) { switch (next->mType) {
case Event::LinearRamp: case AudioTimelineEvent::LinearRamp:
return LinearInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime); return LinearInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime);
case Event::ExponentialRamp: case AudioTimelineEvent::ExponentialRamp:
return ExponentialInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime); return ExponentialInterpolate(previous->mTime, previous->mValue, next->mTime, next->mValue, aTime);
case Event::SetValue: case AudioTimelineEvent::SetValue:
case Event::SetTarget: case AudioTimelineEvent::SetTarget:
case Event::SetValueCurve: case AudioTimelineEvent::SetValueCurve:
break; break;
} }
// Now handle all other cases // Now handle all other cases
switch (previous->mType) { switch (previous->mType) {
case Event::SetValue: case AudioTimelineEvent::SetValue:
case Event::LinearRamp: case AudioTimelineEvent::LinearRamp:
case Event::ExponentialRamp: case AudioTimelineEvent::ExponentialRamp:
// If the next event type is neither linear or exponential ramp, the // If the next event type is neither linear or exponential ramp, the
// value is constant. // value is constant.
return previous->mValue; return previous->mValue;
case Event::SetValueCurve: case AudioTimelineEvent::SetValueCurve:
// TODO: implement // TODO: implement
return 0.0f; return 0.0f;
case Event::SetTarget: case AudioTimelineEvent::SetTarget:
MOZ_ASSERT(false, "unreached"); MOZ_ASSERT(false, "unreached");
} }
@ -294,18 +294,18 @@ public:
} }
private: private:
const Event* GetPreviousEvent(double aTime) const const AudioTimelineEvent* GetPreviousEvent(double aTime) const
{ {
const Event* previous = nullptr; const AudioTimelineEvent* previous = nullptr;
const Event* next = nullptr; const AudioTimelineEvent* next = nullptr;
bool bailOut = false; bool bailOut = false;
for (unsigned i = 0; !bailOut && i < mEvents.Length(); ++i) { for (unsigned i = 0; !bailOut && i < mEvents.Length(); ++i) {
switch (mEvents[i].mType) { switch (mEvents[i].mType) {
case Event::SetValue: case AudioTimelineEvent::SetValue:
case Event::SetTarget: case AudioTimelineEvent::SetTarget:
case Event::LinearRamp: case AudioTimelineEvent::LinearRamp:
case Event::ExponentialRamp: case AudioTimelineEvent::ExponentialRamp:
if (aTime == mEvents[i].mTime) { if (aTime == mEvents[i].mTime) {
// Find the last event with the same time // Find the last event with the same time
do { do {
@ -320,7 +320,7 @@ private:
bailOut = true; bailOut = true;
} }
break; break;
case Event::SetValueCurve: case AudioTimelineEvent::SetValueCurve:
// TODO: implement // TODO: implement
break; break;
default: default:
@ -335,7 +335,7 @@ private:
return previous; return previous;
} }
void InsertEvent(const Event& aEvent, ErrorResult& aRv) void InsertEvent(const AudioTimelineEvent& aEvent, ErrorResult& aRv)
{ {
if (!aEvent.IsValid()) { if (!aEvent.IsValid()) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
@ -345,7 +345,7 @@ private:
// Make sure that non-curve events don't fall within the duration of a // Make sure that non-curve events don't fall within the duration of a
// curve event. // curve event.
for (unsigned i = 0; i < mEvents.Length(); ++i) { for (unsigned i = 0; i < mEvents.Length(); ++i) {
if (mEvents[i].mType == Event::SetValueCurve && if (mEvents[i].mType == AudioTimelineEvent::SetValueCurve &&
mEvents[i].mTime <= aEvent.mTime && mEvents[i].mTime <= aEvent.mTime &&
(mEvents[i].mTime + mEvents[i].mDuration) >= aEvent.mTime) { (mEvents[i].mTime + mEvents[i].mDuration) >= aEvent.mTime) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
@ -355,7 +355,7 @@ private:
// Make sure that curve events don't fall in a range which includes other // Make sure that curve events don't fall in a range which includes other
// events. // events.
if (aEvent.mType == Event::SetValueCurve) { if (aEvent.mType == AudioTimelineEvent::SetValueCurve) {
for (unsigned i = 0; i < mEvents.Length(); ++i) { for (unsigned i = 0; i < mEvents.Length(); ++i) {
if (mEvents[i].mTime >= aEvent.mTime && if (mEvents[i].mTime >= aEvent.mTime &&
mEvents[i].mTime <= (aEvent.mTime + aEvent.mDuration)) { mEvents[i].mTime <= (aEvent.mTime + aEvent.mDuration)) {
@ -366,12 +366,12 @@ private:
} }
// Make sure that invalid values are not used for exponential curves // Make sure that invalid values are not used for exponential curves
if (aEvent.mType == Event::ExponentialRamp) { if (aEvent.mType == AudioTimelineEvent::ExponentialRamp) {
if (aEvent.mValue <= 0.f) { if (aEvent.mValue <= 0.f) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return; return;
} }
const Event* previousEvent = GetPreviousEvent(aEvent.mTime); const AudioTimelineEvent* previousEvent = GetPreviousEvent(aEvent.mTime);
if (previousEvent) { if (previousEvent) {
if (previousEvent->mValue <= 0.f) { if (previousEvent->mValue <= 0.f) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
@ -418,7 +418,7 @@ private:
// and that is the reason why we're using a simple array as the data structure. // and that is the reason why we're using a simple array as the data structure.
// We can optimize this in the future if the performance of the array ends up // We can optimize this in the future if the performance of the array ends up
// being a bottleneck. // being a bottleneck.
nsTArray<Event> mEvents; nsTArray<AudioTimelineEvent> mEvents;
float mValue; float mValue;
}; };