mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
b=907986 normalize orientation vectors early and keep existing state if directions are undefined r=padenot
Normalizing the AudioListener front orientation vectors before taking their cross product avoids the possibility of overflow. The panning effect and the azimuth and elevation calculation in the Web Audio spec becomes undefined with linearly dependent listener vectors, so keep existing state in these situations. PannerNode orientation is normalized for consistency, but zero is permitted for this vector because the sound cone algorithm in the Web Audio specifies behavior for this case. --HG-- extra : transplant_source : %DA%C7e%E7%90%14%AF%EA%08%94x%C1%A2g%F1%9A%EE%16%EB%29
This commit is contained in:
parent
b88e8922d4
commit
2a2ab79432
@ -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<JSObject*> 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);
|
||||
|
@ -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<AudioContext> mContext;
|
||||
ThreeDPoint mPosition;
|
||||
ThreeDPoint mOrientation;
|
||||
ThreeDPoint mUpVector;
|
||||
ThreeDPoint mFrontVector;
|
||||
ThreeDPoint mRightVector;
|
||||
ThreeDPoint mVelocity;
|
||||
double mDopplerFactor;
|
||||
double mSpeedOfSound;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user