diff --git a/content/media/webaudio/AudioListener.cpp b/content/media/webaudio/AudioListener.cpp index 1d52a41673f..7e1ad8d50a0 100644 --- a/content/media/webaudio/AudioListener.cpp +++ b/content/media/webaudio/AudioListener.cpp @@ -19,8 +19,8 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioListener, Release) AudioListener::AudioListener(AudioContext* aContext) : mContext(aContext) , mPosition() - , mOrientation(0., 0., -1.) - , mUpVector(0., 1., 0.) + , mFrontVector(0., 0., -1.) + , mRightVector(1., 0., 0.) , mVelocity() , mDopplerFactor(1.) , mSpeedOfSound(343.3) // meters/second @@ -35,6 +35,40 @@ AudioListener::WrapObject(JSContext* aCx, JS::Handle aScope) return AudioListenerBinding::Wrap(aCx, aScope, this); } +void +AudioListener::SetOrientation(double aX, double aY, double aZ, + double aXUp, double aYUp, double aZUp) +{ + ThreeDPoint front(aX, aY, aZ); + // The panning effect and the azimuth and elevation calculation in the Web + // Audio spec becomes undefined with linearly dependent vectors, so keep + // existing state in these situations. + if (front.IsZero()) { + return; + } + // Normalize before using CrossProduct() to avoid overflow. + front.Normalize(); + ThreeDPoint up(aXUp, aYUp, aZUp); + if (up.IsZero()) { + return; + } + up.Normalize(); + ThreeDPoint right = front.CrossProduct(up); + if (right.IsZero()) { + return; + } + right.Normalize(); + + if (!mFrontVector.FuzzyEqual(front)) { + mFrontVector = front; + SendThreeDPointParameterToStream(PannerNode::LISTENER_FRONT_VECTOR, front); + } + if (!mRightVector.FuzzyEqual(right)) { + mRightVector = right; + SendThreeDPointParameterToStream(PannerNode::LISTENER_RIGHT_VECTOR, right); + } +} + void AudioListener::RegisterPannerNode(PannerNode* aPannerNode) { @@ -42,8 +76,8 @@ AudioListener::RegisterPannerNode(PannerNode* aPannerNode) // Let the panner node know about our parameters aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_POSITION, mPosition); - aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_ORIENTATION, mOrientation); - aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_UPVECTOR, mUpVector); + aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_FRONT_VECTOR, mFrontVector); + aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_RIGHT_VECTOR, mRightVector); aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_VELOCITY, mVelocity); aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_DOPPLER_FACTOR, mDopplerFactor); aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_SPEED_OF_SOUND, mSpeedOfSound); diff --git a/content/media/webaudio/AudioListener.h b/content/media/webaudio/AudioListener.h index 91bd4733529..4fb1ef18a2f 100644 --- a/content/media/webaudio/AudioListener.h +++ b/content/media/webaudio/AudioListener.h @@ -84,25 +84,7 @@ public: } void SetOrientation(double aX, double aY, double aZ, - double aXUp, double aYUp, double aZUp) - { - if (WebAudioUtils::FuzzyEqual(mOrientation.x, aX) && - WebAudioUtils::FuzzyEqual(mOrientation.y, aY) && - WebAudioUtils::FuzzyEqual(mOrientation.z, aZ) && - WebAudioUtils::FuzzyEqual(mUpVector.x, aX) && - WebAudioUtils::FuzzyEqual(mUpVector.y, aY) && - WebAudioUtils::FuzzyEqual(mUpVector.z, aZ)) { - return; - } - mOrientation.x = aX; - mOrientation.y = aY; - mOrientation.z = aZ; - mUpVector.x = aXUp; - mUpVector.y = aYUp; - mUpVector.z = aZUp; - SendThreeDPointParameterToStream(PannerNode::LISTENER_ORIENTATION, mOrientation); - SendThreeDPointParameterToStream(PannerNode::LISTENER_UPVECTOR, mUpVector); - } + double aXUp, double aYUp, double aZUp); const ThreeDPoint& Velocity() const { @@ -135,8 +117,8 @@ private: friend class PannerNode; nsRefPtr mContext; ThreeDPoint mPosition; - ThreeDPoint mOrientation; - ThreeDPoint mUpVector; + ThreeDPoint mFrontVector; + ThreeDPoint mRightVector; ThreeDPoint mVelocity; double mDopplerFactor; double mSpeedOfSound; diff --git a/content/media/webaudio/PannerNode.cpp b/content/media/webaudio/PannerNode.cpp index c218f6a410e..ef77af59d5a 100644 --- a/content/media/webaudio/PannerNode.cpp +++ b/content/media/webaudio/PannerNode.cpp @@ -109,8 +109,8 @@ public: { switch (aIndex) { case PannerNode::LISTENER_POSITION: mListenerPosition = aParam; break; - case PannerNode::LISTENER_ORIENTATION: mListenerOrientation = aParam; break; - case PannerNode::LISTENER_UPVECTOR: mListenerUpVector = aParam; break; + case PannerNode::LISTENER_FRONT_VECTOR: mListenerFrontVector = aParam; break; + case PannerNode::LISTENER_RIGHT_VECTOR: mListenerRightVector = aParam; break; case PannerNode::LISTENER_VELOCITY: mListenerVelocity = aParam; break; case PannerNode::POSITION: mPosition = aParam; break; case PannerNode::ORIENTATION: mOrientation = aParam; break; @@ -178,8 +178,8 @@ public: double mConeOuterAngle; double mConeOuterGain; ThreeDPoint mListenerPosition; - ThreeDPoint mListenerOrientation; - ThreeDPoint mListenerUpVector; + ThreeDPoint mListenerFrontVector; + ThreeDPoint mListenerRightVector; ThreeDPoint mListenerVelocity; double mListenerDopplerFactor; double mListenerSpeedOfSound; @@ -376,7 +376,7 @@ PannerNodeEngine::DistanceAndConeGain(AudioChunk* aChunk, float aGain) AudioBufferInPlaceScale(samples, channelCount, aGain); } -// This algorithm is specicied in the webaudio spec. +// This algorithm is specified in the webaudio spec. void PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation) { @@ -391,14 +391,9 @@ PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation) sourceListener.Normalize(); // Project the source-listener vector on the x-z plane. - ThreeDPoint& listenerFront = mListenerOrientation; - ThreeDPoint listenerRightNorm = listenerFront.CrossProduct(mListenerUpVector); - listenerRightNorm.Normalize(); - - ThreeDPoint listenerFrontNorm(listenerFront); - listenerFrontNorm.Normalize(); - - ThreeDPoint up = listenerRightNorm.CrossProduct(listenerFrontNorm); + const ThreeDPoint& listenerFront = mListenerFrontVector; + const ThreeDPoint& listenerRight = mListenerRightVector; + ThreeDPoint up = listenerRight.CrossProduct(listenerFront); double upProjection = sourceListener.DotProduct(up); @@ -406,11 +401,11 @@ PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation) projectedSource.Normalize(); // Actually compute the angle, and convert to degrees - double projection = projectedSource.DotProduct(listenerRightNorm); + double projection = projectedSource.DotProduct(listenerRight); aAzimuth = 180 * acos(projection) / M_PI; // Compute whether the source is in front or behind the listener. - double frontBack = projectedSource.DotProduct(listenerFrontNorm); + double frontBack = projectedSource.DotProduct(listenerFront); if (frontBack < 0) { aAzimuth = 360 - aAzimuth; } @@ -444,11 +439,8 @@ PannerNodeEngine::ComputeConeGain() ThreeDPoint sourceToListener = mListenerPosition - mPosition; sourceToListener.Normalize(); - ThreeDPoint normalizedSourceOrientation = mOrientation; - normalizedSourceOrientation.Normalize(); - // Angle between the source orientation vector and the source-listener vector - double dotProduct = sourceToListener.DotProduct(normalizedSourceOrientation); + double dotProduct = sourceToListener.DotProduct(mOrientation); double angle = 180 * acos(dotProduct) / M_PI; double absAngle = fabs(angle); diff --git a/content/media/webaudio/PannerNode.h b/content/media/webaudio/PannerNode.h index 9d06f97191f..eb8e764e8df 100644 --- a/content/media/webaudio/PannerNode.h +++ b/content/media/webaudio/PannerNode.h @@ -120,14 +120,14 @@ public: void SetOrientation(double aX, double aY, double aZ) { - if (WebAudioUtils::FuzzyEqual(mOrientation.x, aX) && - WebAudioUtils::FuzzyEqual(mOrientation.y, aY) && - WebAudioUtils::FuzzyEqual(mOrientation.z, aZ)) { + ThreeDPoint orientation(aX, aY, aZ); + if (!orientation.IsZero()) { + orientation.Normalize(); + } + if (mOrientation.FuzzyEqual(orientation)) { return; } - mOrientation.x = aX; - mOrientation.y = aY; - mOrientation.z = aZ; + mOrientation = orientation; SendThreeDPointParameterToStream(ORIENTATION, mOrientation); } @@ -233,15 +233,15 @@ private: friend class PannerNodeEngine; enum EngineParameters { LISTENER_POSITION, - LISTENER_ORIENTATION, - LISTENER_UPVECTOR, + LISTENER_FRONT_VECTOR, // unit length + LISTENER_RIGHT_VECTOR, // unit length, orthogonal to LISTENER_FRONT_VECTOR LISTENER_VELOCITY, LISTENER_DOPPLER_FACTOR, LISTENER_SPEED_OF_SOUND, PANNING_MODEL, DISTANCE_MODEL, POSITION, - ORIENTATION, + ORIENTATION, // unit length or zero VELOCITY, REF_DISTANCE, MAX_DISTANCE, diff --git a/content/media/webaudio/ThreeDPoint.cpp b/content/media/webaudio/ThreeDPoint.cpp index f4187e7b37f..422c36078ac 100644 --- a/content/media/webaudio/ThreeDPoint.cpp +++ b/content/media/webaudio/ThreeDPoint.cpp @@ -9,11 +9,20 @@ */ #include "ThreeDPoint.h" +#include "WebAudioUtils.h" namespace mozilla { namespace dom { +bool +ThreeDPoint::FuzzyEqual(const ThreeDPoint& other) +{ + return WebAudioUtils::FuzzyEqual(x, other.x) && + WebAudioUtils::FuzzyEqual(y, other.y) && + WebAudioUtils::FuzzyEqual(z, other.z); +} + ThreeDPoint operator-(const ThreeDPoint& lhs, const ThreeDPoint& rhs) { return ThreeDPoint(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); diff --git a/content/media/webaudio/ThreeDPoint.h b/content/media/webaudio/ThreeDPoint.h index 45aaed5cac7..c9c8eba068d 100644 --- a/content/media/webaudio/ThreeDPoint.h +++ b/content/media/webaudio/ThreeDPoint.h @@ -68,6 +68,10 @@ struct ThreeDPoint { { return x == 0 && y == 0 && z == 0; } + + // For comparing two vectors of close to unit magnitude. + bool FuzzyEqual(const ThreeDPoint& other); + double x, y, z; private: