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)
|
AudioListener::AudioListener(AudioContext* aContext)
|
||||||
: mContext(aContext)
|
: mContext(aContext)
|
||||||
, mPosition()
|
, mPosition()
|
||||||
, mOrientation(0., 0., -1.)
|
, mFrontVector(0., 0., -1.)
|
||||||
, mUpVector(0., 1., 0.)
|
, mRightVector(1., 0., 0.)
|
||||||
, mVelocity()
|
, mVelocity()
|
||||||
, mDopplerFactor(1.)
|
, mDopplerFactor(1.)
|
||||||
, mSpeedOfSound(343.3) // meters/second
|
, mSpeedOfSound(343.3) // meters/second
|
||||||
@ -35,6 +35,40 @@ AudioListener::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
|||||||
return AudioListenerBinding::Wrap(aCx, aScope, this);
|
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
|
void
|
||||||
AudioListener::RegisterPannerNode(PannerNode* aPannerNode)
|
AudioListener::RegisterPannerNode(PannerNode* aPannerNode)
|
||||||
{
|
{
|
||||||
@ -42,8 +76,8 @@ AudioListener::RegisterPannerNode(PannerNode* aPannerNode)
|
|||||||
|
|
||||||
// Let the panner node know about our parameters
|
// Let the panner node know about our parameters
|
||||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_POSITION, mPosition);
|
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_POSITION, mPosition);
|
||||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_ORIENTATION, mOrientation);
|
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_FRONT_VECTOR, mFrontVector);
|
||||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_UPVECTOR, mUpVector);
|
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_RIGHT_VECTOR, mRightVector);
|
||||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_VELOCITY, mVelocity);
|
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_VELOCITY, mVelocity);
|
||||||
aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_DOPPLER_FACTOR, mDopplerFactor);
|
aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_DOPPLER_FACTOR, mDopplerFactor);
|
||||||
aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_SPEED_OF_SOUND, mSpeedOfSound);
|
aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_SPEED_OF_SOUND, mSpeedOfSound);
|
||||||
|
@ -84,25 +84,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetOrientation(double aX, double aY, double aZ,
|
void SetOrientation(double aX, double aY, double aZ,
|
||||||
double aXUp, double aYUp, double aZUp)
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ThreeDPoint& Velocity() const
|
const ThreeDPoint& Velocity() const
|
||||||
{
|
{
|
||||||
@ -135,8 +117,8 @@ private:
|
|||||||
friend class PannerNode;
|
friend class PannerNode;
|
||||||
nsRefPtr<AudioContext> mContext;
|
nsRefPtr<AudioContext> mContext;
|
||||||
ThreeDPoint mPosition;
|
ThreeDPoint mPosition;
|
||||||
ThreeDPoint mOrientation;
|
ThreeDPoint mFrontVector;
|
||||||
ThreeDPoint mUpVector;
|
ThreeDPoint mRightVector;
|
||||||
ThreeDPoint mVelocity;
|
ThreeDPoint mVelocity;
|
||||||
double mDopplerFactor;
|
double mDopplerFactor;
|
||||||
double mSpeedOfSound;
|
double mSpeedOfSound;
|
||||||
|
@ -109,8 +109,8 @@ public:
|
|||||||
{
|
{
|
||||||
switch (aIndex) {
|
switch (aIndex) {
|
||||||
case PannerNode::LISTENER_POSITION: mListenerPosition = aParam; break;
|
case PannerNode::LISTENER_POSITION: mListenerPosition = aParam; break;
|
||||||
case PannerNode::LISTENER_ORIENTATION: mListenerOrientation = aParam; break;
|
case PannerNode::LISTENER_FRONT_VECTOR: mListenerFrontVector = aParam; break;
|
||||||
case PannerNode::LISTENER_UPVECTOR: mListenerUpVector = aParam; break;
|
case PannerNode::LISTENER_RIGHT_VECTOR: mListenerRightVector = aParam; break;
|
||||||
case PannerNode::LISTENER_VELOCITY: mListenerVelocity = aParam; break;
|
case PannerNode::LISTENER_VELOCITY: mListenerVelocity = aParam; break;
|
||||||
case PannerNode::POSITION: mPosition = aParam; break;
|
case PannerNode::POSITION: mPosition = aParam; break;
|
||||||
case PannerNode::ORIENTATION: mOrientation = aParam; break;
|
case PannerNode::ORIENTATION: mOrientation = aParam; break;
|
||||||
@ -178,8 +178,8 @@ public:
|
|||||||
double mConeOuterAngle;
|
double mConeOuterAngle;
|
||||||
double mConeOuterGain;
|
double mConeOuterGain;
|
||||||
ThreeDPoint mListenerPosition;
|
ThreeDPoint mListenerPosition;
|
||||||
ThreeDPoint mListenerOrientation;
|
ThreeDPoint mListenerFrontVector;
|
||||||
ThreeDPoint mListenerUpVector;
|
ThreeDPoint mListenerRightVector;
|
||||||
ThreeDPoint mListenerVelocity;
|
ThreeDPoint mListenerVelocity;
|
||||||
double mListenerDopplerFactor;
|
double mListenerDopplerFactor;
|
||||||
double mListenerSpeedOfSound;
|
double mListenerSpeedOfSound;
|
||||||
@ -376,7 +376,7 @@ PannerNodeEngine::DistanceAndConeGain(AudioChunk* aChunk, float aGain)
|
|||||||
AudioBufferInPlaceScale(samples, channelCount, aGain);
|
AudioBufferInPlaceScale(samples, channelCount, aGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This algorithm is specicied in the webaudio spec.
|
// This algorithm is specified in the webaudio spec.
|
||||||
void
|
void
|
||||||
PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation)
|
PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation)
|
||||||
{
|
{
|
||||||
@ -391,14 +391,9 @@ PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation)
|
|||||||
sourceListener.Normalize();
|
sourceListener.Normalize();
|
||||||
|
|
||||||
// Project the source-listener vector on the x-z plane.
|
// Project the source-listener vector on the x-z plane.
|
||||||
ThreeDPoint& listenerFront = mListenerOrientation;
|
const ThreeDPoint& listenerFront = mListenerFrontVector;
|
||||||
ThreeDPoint listenerRightNorm = listenerFront.CrossProduct(mListenerUpVector);
|
const ThreeDPoint& listenerRight = mListenerRightVector;
|
||||||
listenerRightNorm.Normalize();
|
ThreeDPoint up = listenerRight.CrossProduct(listenerFront);
|
||||||
|
|
||||||
ThreeDPoint listenerFrontNorm(listenerFront);
|
|
||||||
listenerFrontNorm.Normalize();
|
|
||||||
|
|
||||||
ThreeDPoint up = listenerRightNorm.CrossProduct(listenerFrontNorm);
|
|
||||||
|
|
||||||
double upProjection = sourceListener.DotProduct(up);
|
double upProjection = sourceListener.DotProduct(up);
|
||||||
|
|
||||||
@ -406,11 +401,11 @@ PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation)
|
|||||||
projectedSource.Normalize();
|
projectedSource.Normalize();
|
||||||
|
|
||||||
// Actually compute the angle, and convert to degrees
|
// Actually compute the angle, and convert to degrees
|
||||||
double projection = projectedSource.DotProduct(listenerRightNorm);
|
double projection = projectedSource.DotProduct(listenerRight);
|
||||||
aAzimuth = 180 * acos(projection) / M_PI;
|
aAzimuth = 180 * acos(projection) / M_PI;
|
||||||
|
|
||||||
// Compute whether the source is in front or behind the listener.
|
// Compute whether the source is in front or behind the listener.
|
||||||
double frontBack = projectedSource.DotProduct(listenerFrontNorm);
|
double frontBack = projectedSource.DotProduct(listenerFront);
|
||||||
if (frontBack < 0) {
|
if (frontBack < 0) {
|
||||||
aAzimuth = 360 - aAzimuth;
|
aAzimuth = 360 - aAzimuth;
|
||||||
}
|
}
|
||||||
@ -444,11 +439,8 @@ PannerNodeEngine::ComputeConeGain()
|
|||||||
ThreeDPoint sourceToListener = mListenerPosition - mPosition;
|
ThreeDPoint sourceToListener = mListenerPosition - mPosition;
|
||||||
sourceToListener.Normalize();
|
sourceToListener.Normalize();
|
||||||
|
|
||||||
ThreeDPoint normalizedSourceOrientation = mOrientation;
|
|
||||||
normalizedSourceOrientation.Normalize();
|
|
||||||
|
|
||||||
// Angle between the source orientation vector and the source-listener vector
|
// 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 angle = 180 * acos(dotProduct) / M_PI;
|
||||||
double absAngle = fabs(angle);
|
double absAngle = fabs(angle);
|
||||||
|
|
||||||
|
@ -120,14 +120,14 @@ public:
|
|||||||
|
|
||||||
void SetOrientation(double aX, double aY, double aZ)
|
void SetOrientation(double aX, double aY, double aZ)
|
||||||
{
|
{
|
||||||
if (WebAudioUtils::FuzzyEqual(mOrientation.x, aX) &&
|
ThreeDPoint orientation(aX, aY, aZ);
|
||||||
WebAudioUtils::FuzzyEqual(mOrientation.y, aY) &&
|
if (!orientation.IsZero()) {
|
||||||
WebAudioUtils::FuzzyEqual(mOrientation.z, aZ)) {
|
orientation.Normalize();
|
||||||
|
}
|
||||||
|
if (mOrientation.FuzzyEqual(orientation)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mOrientation.x = aX;
|
mOrientation = orientation;
|
||||||
mOrientation.y = aY;
|
|
||||||
mOrientation.z = aZ;
|
|
||||||
SendThreeDPointParameterToStream(ORIENTATION, mOrientation);
|
SendThreeDPointParameterToStream(ORIENTATION, mOrientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,15 +233,15 @@ private:
|
|||||||
friend class PannerNodeEngine;
|
friend class PannerNodeEngine;
|
||||||
enum EngineParameters {
|
enum EngineParameters {
|
||||||
LISTENER_POSITION,
|
LISTENER_POSITION,
|
||||||
LISTENER_ORIENTATION,
|
LISTENER_FRONT_VECTOR, // unit length
|
||||||
LISTENER_UPVECTOR,
|
LISTENER_RIGHT_VECTOR, // unit length, orthogonal to LISTENER_FRONT_VECTOR
|
||||||
LISTENER_VELOCITY,
|
LISTENER_VELOCITY,
|
||||||
LISTENER_DOPPLER_FACTOR,
|
LISTENER_DOPPLER_FACTOR,
|
||||||
LISTENER_SPEED_OF_SOUND,
|
LISTENER_SPEED_OF_SOUND,
|
||||||
PANNING_MODEL,
|
PANNING_MODEL,
|
||||||
DISTANCE_MODEL,
|
DISTANCE_MODEL,
|
||||||
POSITION,
|
POSITION,
|
||||||
ORIENTATION,
|
ORIENTATION, // unit length or zero
|
||||||
VELOCITY,
|
VELOCITY,
|
||||||
REF_DISTANCE,
|
REF_DISTANCE,
|
||||||
MAX_DISTANCE,
|
MAX_DISTANCE,
|
||||||
|
@ -9,11 +9,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ThreeDPoint.h"
|
#include "ThreeDPoint.h"
|
||||||
|
#include "WebAudioUtils.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
namespace dom {
|
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)
|
ThreeDPoint operator-(const ThreeDPoint& lhs, const ThreeDPoint& rhs)
|
||||||
{
|
{
|
||||||
return ThreeDPoint(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z);
|
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;
|
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;
|
double x, y, z;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user