gecko/content/media/webaudio/PannerNode.h
Karl Tomlinson 077bb360ad 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
2013-09-04 21:20:59 +12:00

277 lines
7.3 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PannerNode_h_
#define PannerNode_h_
#include "AudioNode.h"
#include "mozilla/dom/PannerNodeBinding.h"
#include "ThreeDPoint.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/Preferences.h"
#include "WebAudioUtils.h"
#include <set>
namespace mozilla {
namespace dom {
class AudioContext;
class AudioBufferSourceNode;
class PannerNode : public AudioNode,
public SupportsWeakPtr<PannerNode>
{
public:
explicit PannerNode(AudioContext* aContext);
virtual ~PannerNode();
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
virtual void DestroyMediaStream() MOZ_OVERRIDE;
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PannerNode, AudioNode)
PanningModelType PanningModel() const
{
return mPanningModel;
}
void SetPanningModel(PanningModelType aPanningModel)
{
if (!Preferences::GetBool("media.webaudio.legacy.PannerNode")) {
// Do not accept the alternate enum values unless the legacy pref
// has been turned on.
switch (aPanningModel) {
case PanningModelType::_0:
case PanningModelType::_1:
// Do nothing in order to emulate setting an invalid enum value.
return;
default:
// Shut up the compiler warning
break;
}
}
// Handle the alternate enum values
switch (aPanningModel) {
case PanningModelType::_0: aPanningModel = PanningModelType::Equalpower; break;
case PanningModelType::_1: aPanningModel = PanningModelType::HRTF; break;
default:
// Shut up the compiler warning
break;
}
mPanningModel = aPanningModel;
SendInt32ParameterToStream(PANNING_MODEL, int32_t(mPanningModel));
}
DistanceModelType DistanceModel() const
{
return mDistanceModel;
}
void SetDistanceModel(DistanceModelType aDistanceModel)
{
if (!Preferences::GetBool("media.webaudio.legacy.PannerNode")) {
// Do not accept the alternate enum values unless the legacy pref
// has been turned on.
switch (aDistanceModel) {
case DistanceModelType::_0:
case DistanceModelType::_1:
case DistanceModelType::_2:
// Do nothing in order to emulate setting an invalid enum value.
return;
default:
// Shut up the compiler warning
break;
}
}
// Handle the alternate enum values
switch (aDistanceModel) {
case DistanceModelType::_0: aDistanceModel = DistanceModelType::Linear; break;
case DistanceModelType::_1: aDistanceModel = DistanceModelType::Inverse; break;
case DistanceModelType::_2: aDistanceModel = DistanceModelType::Exponential; break;
default:
// Shut up the compiler warning
break;
}
mDistanceModel = aDistanceModel;
SendInt32ParameterToStream(DISTANCE_MODEL, int32_t(mDistanceModel));
}
void SetPosition(double aX, double aY, double aZ)
{
if (WebAudioUtils::FuzzyEqual(mPosition.x, aX) &&
WebAudioUtils::FuzzyEqual(mPosition.y, aY) &&
WebAudioUtils::FuzzyEqual(mPosition.z, aZ)) {
return;
}
mPosition.x = aX;
mPosition.y = aY;
mPosition.z = aZ;
SendThreeDPointParameterToStream(POSITION, mPosition);
}
void SetOrientation(double aX, double aY, double aZ)
{
ThreeDPoint orientation(aX, aY, aZ);
if (!orientation.IsZero()) {
orientation.Normalize();
}
if (mOrientation.FuzzyEqual(orientation)) {
return;
}
mOrientation = orientation;
SendThreeDPointParameterToStream(ORIENTATION, mOrientation);
}
void SetVelocity(double aX, double aY, double aZ)
{
if (WebAudioUtils::FuzzyEqual(mVelocity.x, aX) &&
WebAudioUtils::FuzzyEqual(mVelocity.y, aY) &&
WebAudioUtils::FuzzyEqual(mVelocity.z, aZ)) {
return;
}
mVelocity.x = aX;
mVelocity.y = aY;
mVelocity.z = aZ;
SendThreeDPointParameterToStream(VELOCITY, mVelocity);
SendDopplerToSourcesIfNeeded();
}
double RefDistance() const
{
return mRefDistance;
}
void SetRefDistance(double aRefDistance)
{
if (WebAudioUtils::FuzzyEqual(mRefDistance, aRefDistance)) {
return;
}
mRefDistance = aRefDistance;
SendDoubleParameterToStream(REF_DISTANCE, mRefDistance);
}
double MaxDistance() const
{
return mMaxDistance;
}
void SetMaxDistance(double aMaxDistance)
{
if (WebAudioUtils::FuzzyEqual(mMaxDistance, aMaxDistance)) {
return;
}
mMaxDistance = aMaxDistance;
SendDoubleParameterToStream(MAX_DISTANCE, mMaxDistance);
}
double RolloffFactor() const
{
return mRolloffFactor;
}
void SetRolloffFactor(double aRolloffFactor)
{
if (WebAudioUtils::FuzzyEqual(mRolloffFactor, aRolloffFactor)) {
return;
}
mRolloffFactor = aRolloffFactor;
SendDoubleParameterToStream(ROLLOFF_FACTOR, mRolloffFactor);
}
double ConeInnerAngle() const
{
return mConeInnerAngle;
}
void SetConeInnerAngle(double aConeInnerAngle)
{
if (WebAudioUtils::FuzzyEqual(mConeInnerAngle, aConeInnerAngle)) {
return;
}
mConeInnerAngle = aConeInnerAngle;
SendDoubleParameterToStream(CONE_INNER_ANGLE, mConeInnerAngle);
}
double ConeOuterAngle() const
{
return mConeOuterAngle;
}
void SetConeOuterAngle(double aConeOuterAngle)
{
if (WebAudioUtils::FuzzyEqual(mConeOuterAngle, aConeOuterAngle)) {
return;
}
mConeOuterAngle = aConeOuterAngle;
SendDoubleParameterToStream(CONE_OUTER_ANGLE, mConeOuterAngle);
}
double ConeOuterGain() const
{
return mConeOuterGain;
}
void SetConeOuterGain(double aConeOuterGain)
{
if (WebAudioUtils::FuzzyEqual(mConeOuterGain, aConeOuterGain)) {
return;
}
mConeOuterGain = aConeOuterGain;
SendDoubleParameterToStream(CONE_OUTER_GAIN, mConeOuterGain);
}
float ComputeDopplerShift();
void SendDopplerToSourcesIfNeeded();
void FindConnectedSources();
void FindConnectedSources(AudioNode* aNode, nsTArray<AudioBufferSourceNode*>& aSources, std::set<AudioNode*>& aSeenNodes);
private:
friend class AudioListener;
friend class PannerNodeEngine;
enum EngineParameters {
LISTENER_POSITION,
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, // unit length or zero
VELOCITY,
REF_DISTANCE,
MAX_DISTANCE,
ROLLOFF_FACTOR,
CONE_INNER_ANGLE,
CONE_OUTER_ANGLE,
CONE_OUTER_GAIN
};
private:
PanningModelType mPanningModel;
DistanceModelType mDistanceModel;
ThreeDPoint mPosition;
ThreeDPoint mOrientation;
ThreeDPoint mVelocity;
double mRefDistance;
double mMaxDistance;
double mRolloffFactor;
double mConeInnerAngle;
double mConeOuterAngle;
double mConeOuterGain;
// An array of all the AudioBufferSourceNode connected directly or indirectly
// to this AudioPannerNode.
nsTArray<AudioBufferSourceNode*> mSources;
};
}
}
#endif