Index: Source/modules/webaudio/PannerNode.cpp |
diff --git a/Source/modules/webaudio/PannerNode.cpp b/Source/modules/webaudio/PannerNode.cpp |
index 27e06244babb4cedc8f5a3bf61d400684df839df..3f2dde89def0dc6e3f5920d71ebb7663e6bd3d12 100644 |
--- a/Source/modules/webaudio/PannerNode.cpp |
+++ b/Source/modules/webaudio/PannerNode.cpp |
@@ -49,7 +49,17 @@ static void fixNANs(double &x) |
PannerNode::PannerNode(AudioContext* context, float sampleRate) |
: AudioNode(context, sampleRate) |
, m_panningModel(Panner::PanningModelHRTF) |
+ , m_position(0, 0, 0) |
+ , m_orientation(1, 0, 0) |
+ , m_velocity(0, 0, 0) |
+ , m_cachedPosition(0, 0, 0) |
+ , m_cachedOrientation(1, 0, 0) |
+ , m_cachedVelocity(0, 0, 0) |
, m_lastGain(-1.0) |
+ , m_cachedAzimuth(0) |
+ , m_cachedElevation(0) |
+ , m_cachedDistanceConeGain(0) |
+ , m_cachedDopplerRate(1) |
, m_connectionCount(0) |
{ |
// Load the HRTF database asynchronously so we don't block the Javascript thread while creating the HRTF database. |
@@ -68,9 +78,7 @@ PannerNode::PannerNode(AudioContext* context, float sampleRate) |
m_distanceGain = AudioParam::create(context, "distanceGain", 1.0, 0.0, 1.0); |
m_coneGain = AudioParam::create(context, "coneGain", 1.0, 0.0, 1.0); |
- m_position = FloatPoint3D(0, 0, 0); |
- m_orientation = FloatPoint3D(1, 0, 0); |
- m_velocity = FloatPoint3D(0, 0, 0); |
+ m_cachedListener = AudioListener::create(); |
setNodeType(NodeTypePanner); |
@@ -131,11 +139,12 @@ void PannerNode::process(size_t framesToProcess) |
// Apply the panning effect. |
double azimuth; |
double elevation; |
- getAzimuthElevation(&azimuth, &elevation); |
+ azimuthElevation(&azimuth, &elevation); |
+ |
m_panner->pan(azimuth, elevation, source, destination, framesToProcess); |
// Get the distance and cone gain. |
- double totalGain = distanceConeGain(); |
+ float totalGain = distanceConeGain(); |
// Snap to desired gain at the beginning. |
if (m_lastGain == -1.0) |
@@ -143,6 +152,11 @@ void PannerNode::process(size_t framesToProcess) |
// Apply gain in-place with de-zippering. |
destination->copyWithGainFrom(*destination, &m_lastGain, totalGain); |
+ |
+ // Update the cached listener in case listener has moved. |
+ updateCachedListener(); |
+ // Now update the cached source location in case the source has changed. |
+ updateCachedSourceLocationInfo(); |
} else { |
// Too bad - The tryLock() failed. We must be in the middle of changing the panner. |
destination->zero(); |
@@ -217,6 +231,42 @@ bool PannerNode::setPanningModel(unsigned model) |
return true; |
} |
+void PannerNode::setPosition(float x, float y, float z) |
+{ |
+ // FIXME : consider thread safety about m_position in audio thread. |
+ // See http://crbugs.com/350583. |
+ FloatPoint3D position = FloatPoint3D(x, y, z); |
+ |
+ if (m_position == position) |
+ return; |
+ |
+ m_position = position; |
+} |
+ |
+void PannerNode::setOrientation(float x, float y, float z) |
+{ |
+ // FIXME : consider thread safety about m_orientation in audio thread. |
+ // See http://crbugs.com/350583. |
+ FloatPoint3D orientation = FloatPoint3D(x, y, z); |
+ |
+ if (m_orientation == orientation) |
+ return; |
+ |
+ m_orientation = orientation; |
+} |
+ |
+void PannerNode::setVelocity(float x, float y, float z) |
+{ |
+ // FIXME : consider thread safety about m_velocity in audio thread. |
+ // See http://crbugs.com/350583. |
+ FloatPoint3D velocity = FloatPoint3D(x, y, z); |
+ |
+ if (m_velocity == velocity) |
+ return; |
+ |
+ m_velocity = velocity; |
+} |
+ |
String PannerNode::distanceModel() const |
{ |
switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) { |
@@ -259,10 +309,8 @@ bool PannerNode::setDistanceModel(unsigned model) |
return true; |
} |
-void PannerNode::getAzimuthElevation(double* outAzimuth, double* outElevation) |
+void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevation) |
{ |
- // FIXME: we should cache azimuth and elevation (if possible), so we only re-calculate if a change has been made. |
- |
double azimuth = 0.0; |
// Calculate the source-listener vector |
@@ -323,11 +371,10 @@ void PannerNode::getAzimuthElevation(double* outAzimuth, double* outElevation) |
*outElevation = elevation; |
} |
-float PannerNode::dopplerRate() |
+ |
+double PannerNode::calculateDopplerRate() |
{ |
double dopplerShift = 1.0; |
- |
- // FIXME: optimize for case when neither source nor listener has changed... |
double dopplerFactor = listener()->dopplerFactor(); |
if (dopplerFactor > 0.0) { |
@@ -368,10 +415,10 @@ float PannerNode::dopplerRate() |
} |
} |
- return static_cast<float>(dopplerShift); |
+ return dopplerShift; |
} |
-float PannerNode::distanceConeGain() |
+float PannerNode::calculateDistanceConeGain() |
{ |
FloatPoint3D listenerPosition = listener()->position(); |
@@ -380,7 +427,6 @@ float PannerNode::distanceConeGain() |
m_distanceGain->setValue(static_cast<float>(distanceGain)); |
- // FIXME: could optimize by caching coneGain |
double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosition); |
m_coneGain->setValue(static_cast<float>(coneGain)); |
@@ -388,6 +434,72 @@ float PannerNode::distanceConeGain() |
return float(distanceGain * coneGain); |
} |
+void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation) |
+{ |
+ if (isAzimuthElevationDirty()) |
+ calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation); |
+ |
+ *outAzimuth = m_cachedAzimuth; |
+ *outElevation = m_cachedElevation; |
+} |
+ |
+double PannerNode::dopplerRate() |
+{ |
+ if (isDopplerRateDirty()) |
+ m_cachedDopplerRate = calculateDopplerRate(); |
+ |
+ return m_cachedDopplerRate; |
+} |
+ |
+float PannerNode::distanceConeGain() |
+{ |
+ if (isDistanceConeGainDirty()) |
+ m_cachedDistanceConeGain = calculateDistanceConeGain(); |
+ |
+ return m_cachedDistanceConeGain; |
+} |
+ |
+bool PannerNode::isAzimuthElevationDirty() |
+{ |
+ // Do a quick test and return if possible. |
+ if (m_cachedPosition != m_position) |
+ return true; |
+ |
+ if (m_cachedListener->position() != listener()->position() |
+ || m_cachedListener->orientation() != listener()->orientation() |
+ || m_cachedListener->upVector() != listener()->upVector()) |
+ return true; |
+ |
+ return false; |
+} |
+ |
+bool PannerNode::isDistanceConeGainDirty() |
+{ |
+ // Do a quick test and return if possible. |
+ if (m_cachedPosition != m_position || m_cachedOrientation != m_orientation) |
+ return true; |
+ |
+ if (m_cachedListener->position() != listener()->position()) |
+ return true; |
+ |
+ return false; |
+} |
+ |
+bool PannerNode::isDopplerRateDirty() |
+{ |
+ // Do a quick test and return if possible. |
+ if (m_cachedPosition != m_position || m_cachedVelocity != m_velocity) |
+ return true; |
+ |
+ if (m_cachedListener->position() != listener()->position() |
+ || m_cachedListener->velocity() != listener()->velocity() |
+ || m_cachedListener->dopplerFactor() != listener()->dopplerFactor() |
+ || m_cachedListener->speedOfSound() != listener()->speedOfSound()) |
+ return true; |
+ |
+ return false; |
+} |
+ |
void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<AudioNode*, bool>& visitedNodes) |
{ |
ASSERT(node); |
@@ -420,6 +532,23 @@ void PannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node, HashMap<Audi |
} |
} |
+void PannerNode::updateCachedListener() |
+{ |
+ m_cachedListener->setPosition(listener()->position()); |
+ m_cachedListener->setOrientation(listener()->orientation()); |
+ m_cachedListener->setUpVector(listener()->upVector()); |
+ m_cachedListener->setVelocity(listener()->velocity()); |
+ m_cachedListener->setDopplerFactor(listener()->dopplerFactor()); |
+ m_cachedListener->setSpeedOfSound(listener()->speedOfSound()); |
+} |
+ |
+void PannerNode::updateCachedSourceLocationInfo() |
+{ |
+ m_cachedPosition = m_position; |
+ m_cachedOrientation = m_orientation; |
+ m_cachedVelocity = m_velocity; |
+} |
+ |
} // namespace WebCore |
#endif // ENABLE(WEB_AUDIO) |