1a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch/* 228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * Copyright (C) 2010, Google Inc. All rights reserved. 3a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 4a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Redistribution and use in source and binary forms, with or without 5a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * modification, are permitted provided that the following conditions 6a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * are met: 7a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 1. Redistributions of source code must retain the above copyright 828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * notice, this list of conditions and the following disclaimer. 9a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright 1028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * notice, this list of conditions and the following disclaimer in the 1128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * documentation and/or other materials provided with the distribution. 12a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 1328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 1928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 2028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch */ 24a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 25a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "config.h" 26a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 27a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#if ENABLE(WEB_AUDIO) 28a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 29a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioPannerNode.h" 30a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 31a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioBufferSourceNode.h" 32a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioBus.h" 33a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioContext.h" 34a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioNodeInput.h" 35a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "AudioNodeOutput.h" 36a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "HRTFPanner.h" 37a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include <wtf/MathExtras.h> 38a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 39a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochusing namespace std; 40a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 41a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochnamespace WebCore { 42a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 43a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochstatic void fixNANs(double &x) 44a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 45a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (isnan(x) || isinf(x)) 46a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch x = 0.0; 47a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 48a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 49a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochAudioPannerNode::AudioPannerNode(AudioContext* context, double sampleRate) 50a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch : AudioNode(context, sampleRate) 51a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_panningModel(Panner::PanningModelHRTF) 52a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_lastGain(-1.0) 53a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_connectionCount(0) 54a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 55a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch addInput(adoptPtr(new AudioNodeInput(this))); 56a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch addOutput(adoptPtr(new AudioNodeOutput(this, 2))); 57a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 58a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_distanceGain = AudioGain::create("distanceGain", 1.0, 0.0, 1.0); 59a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_coneGain = AudioGain::create("coneGain", 1.0, 0.0, 1.0); 60a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 61f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_position = FloatPoint3D(0, 0, 0); 62f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_orientation = FloatPoint3D(1, 0, 0); 63f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_velocity = FloatPoint3D(0, 0, 0); 64a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 65a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch setType(NodeTypePanner); 66a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch initialize(); 68a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 70a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochAudioPannerNode::~AudioPannerNode() 71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch uninitialize(); 73a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 74a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 75a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::pullInputs(size_t framesToProcess) 76a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 77a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // We override pullInputs(), so we can detect new AudioSourceNodes which have connected to us when new connections are made. 78a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // These AudioSourceNodes need to be made aware of our existence in order to handle doppler shift pitch changes. 79a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_connectionCount != context()->connectionCount()) { 80a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_connectionCount = context()->connectionCount(); 81a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 82a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Recursively go through all nodes connected to us. 83a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch notifyAudioSourcesConnectedToNode(this); 84a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 85a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 86a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioNode::pullInputs(framesToProcess); 87a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 89a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::process(size_t framesToProcess) 90a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 91a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioBus* destination = output(0)->bus(); 92a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 93a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!isInitialized() || !input(0)->isConnected() || !m_panner.get()) { 94a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destination->zero(); 95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 97a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 98a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioBus* source = input(0)->bus(); 99a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 100a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!source) { 101a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destination->zero(); 102a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 103a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 104a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 105a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Apply the panning effect. 106a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double azimuth; 107a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double elevation; 108a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch getAzimuthElevation(&azimuth, &elevation); 109a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_panner->pan(azimuth, elevation, source, destination, framesToProcess); 110a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 111a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Get the distance and cone gain. 112a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double totalGain = distanceConeGain(); 113a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 114a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Snap to desired gain at the beginning. 115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_lastGain == -1.0) 116a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_lastGain = totalGain; 117a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 118a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Apply gain in-place with de-zippering. 119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destination->copyWithGainFrom(*destination, &m_lastGain, totalGain); 120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 121a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 122a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::reset() 123a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 124a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_lastGain = -1.0; // force to snap to initial gain 125a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_panner.get()) 126a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_panner->reset(); 127a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 128a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 129a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::initialize() 130a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 131a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (isInitialized()) 132a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 133a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 134a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_panner = Panner::create(m_panningModel, sampleRate()); 135a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 136a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioNode::initialize(); 137a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 138a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 139a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::uninitialize() 140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 141a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!isInitialized()) 142a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 143a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 144a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_panner.clear(); 145a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioNode::uninitialize(); 146a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 147a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 148a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochAudioListener* AudioPannerNode::listener() 149a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 150a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return context()->listener(); 151a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 152a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 153a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::setPanningModel(unsigned short model) 154a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 155a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!m_panner.get() || model != m_panningModel) { 156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch OwnPtr<Panner> newPanner = Panner::create(model, sampleRate()); 157a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_panner = newPanner.release(); 158a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 159a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 160a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 161a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::getAzimuthElevation(double* outAzimuth, double* outElevation) 162a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 163a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // FIXME: we should cache azimuth and elevation (if possible), so we only re-calculate if a change has been made. 164a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 165a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double azimuth = 0.0; 166a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 167a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Calculate the source-listener vector 168f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D listenerPosition = listener()->position(); 169f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D sourceListener = m_position - listenerPosition; 170a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 171a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (sourceListener.isZero()) { 172a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // degenerate case if source and listener are at the same point 173a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *outAzimuth = 0.0; 174a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *outElevation = 0.0; 175a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 176a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 177a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 178a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch sourceListener.normalize(); 179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 180a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Align axes 181f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D listenerFront = listener()->orientation(); 182f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D listenerUp = listener()->upVector(); 183f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D listenerRight = listenerFront.cross(listenerUp); 184a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch listenerRight.normalize(); 185a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 186f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D listenerFrontNorm = listenerFront; 187a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch listenerFrontNorm.normalize(); 188a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 189f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D up = listenerRight.cross(listenerFrontNorm); 190a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 191f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch double upProjection = sourceListener.dot(up); 192a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 193f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D projectedSource = sourceListener - upProjection * up; 194a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch projectedSource.normalize(); 195a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 196f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch azimuth = 180.0 * acos(projectedSource.dot(listenerRight)) / piDouble; 197a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch fixNANs(azimuth); // avoid illegal values 198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 199a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Source in front or behind the listener 200f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch double frontBack = projectedSource.dot(listenerFrontNorm); 201a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (frontBack < 0.0) 202a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch azimuth = 360.0 - azimuth; 203a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 204a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Make azimuth relative to "front" and not "right" listener vector 205a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if ((azimuth >= 0.0) && (azimuth <= 270.0)) 206a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch azimuth = 90.0 - azimuth; 207a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch else 208a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch azimuth = 450.0 - azimuth; 209a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 210a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Elevation 211f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch double elevation = 90.0 - 180.0 * acos(sourceListener.dot(up)) / piDouble; 212a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch fixNANs(azimuth); // avoid illegal values 213a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 214a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (elevation > 90.0) 215a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch elevation = 180.0 - elevation; 216a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch else if (elevation < -90.0) 217a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch elevation = -180.0 - elevation; 218a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 219a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (outAzimuth) 220a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *outAzimuth = azimuth; 221a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (outElevation) 222a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *outElevation = elevation; 223a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 224a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 225a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochfloat AudioPannerNode::dopplerRate() 226a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 227a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double dopplerShift = 1.0; 228a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 229a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // FIXME: optimize for case when neither source nor listener has changed... 230a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double dopplerFactor = listener()->dopplerFactor(); 231a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 232a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (dopplerFactor > 0.0) { 233a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double speedOfSound = listener()->speedOfSound(); 234a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 235f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch const FloatPoint3D &sourceVelocity = m_velocity; 236f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch const FloatPoint3D &listenerVelocity = listener()->velocity(); 237a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 238a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Don't bother if both source and listener have no velocity 239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch bool sourceHasVelocity = !sourceVelocity.isZero(); 240a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch bool listenerHasVelocity = !listenerVelocity.isZero(); 241a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 242a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (sourceHasVelocity || listenerHasVelocity) { 243a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Calculate the source to listener vector 244f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D listenerPosition = listener()->position(); 245f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D sourceToListener = m_position - listenerPosition; 246a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 247f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch double sourceListenerMagnitude = sourceToListener.length(); 248a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 249f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch double listenerProjection = sourceToListener.dot(listenerVelocity) / sourceListenerMagnitude; 250f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch double sourceProjection = sourceToListener.dot(sourceVelocity) / sourceListenerMagnitude; 251a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 252a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch listenerProjection = -listenerProjection; 253a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch sourceProjection = -sourceProjection; 254a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 255a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double scaledSpeedOfSound = speedOfSound / dopplerFactor; 256a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch listenerProjection = min(listenerProjection, scaledSpeedOfSound); 257a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch sourceProjection = min(sourceProjection, scaledSpeedOfSound); 258a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 259a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch dopplerShift = ((speedOfSound - dopplerFactor * listenerProjection) / (speedOfSound - dopplerFactor * sourceProjection)); 260a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch fixNANs(dopplerShift); // avoid illegal values 261a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 262a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Limit the pitch shifting to 4 octaves up and 3 octaves down. 263a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (dopplerShift > 16.0) 264a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch dopplerShift = 16.0; 265a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch else if (dopplerShift < 0.125) 266a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch dopplerShift = 0.125; 267a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 268a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 269a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 270a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return static_cast<float>(dopplerShift); 271a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 272a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 273a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochfloat AudioPannerNode::distanceConeGain() 274a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 275f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch FloatPoint3D listenerPosition = listener()->position(); 276a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 277f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch double listenerDistance = m_position.distanceTo(listenerPosition); 278a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double distanceGain = m_distanceEffect.gain(listenerDistance); 279a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 280a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_distanceGain->setValue(static_cast<float>(distanceGain)); 281a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 282a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // FIXME: could optimize by caching coneGain 283a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosition); 284a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 285a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_coneGain->setValue(static_cast<float>(coneGain)); 286a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 287a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return float(distanceGain * coneGain); 288a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 289a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 290a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid AudioPannerNode::notifyAudioSourcesConnectedToNode(AudioNode* node) 291a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 292a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(node); 293a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!node) 294a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 295a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 296a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // First check if this node is an AudioBufferSourceNode. If so, let it know about us so that doppler shift pitch can be taken into account. 297a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (node->type() == NodeTypeAudioBufferSource) { 298a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioBufferSourceNode* bufferSourceNode = reinterpret_cast<AudioBufferSourceNode*>(node); 299a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch bufferSourceNode->setPannerNode(this); 300a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } else { 301a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Go through all inputs to this node. 302a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch for (unsigned i = 0; i < node->numberOfInputs(); ++i) { 303a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioNodeInput* input = node->input(i); 304a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 305a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // For each input, go through all of its connections, looking for AudioBufferSourceNodes. 30628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu for (unsigned j = 0; j < input->numberOfRenderingConnections(); ++j) { 30728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu AudioNodeOutput* connectedOutput = input->renderingOutput(j); 308a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch AudioNode* connectedNode = connectedOutput->node(); 309a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch notifyAudioSourcesConnectedToNode(connectedNode); // recurse 310a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 311a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 312a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 313a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 314a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 315a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} // namespace WebCore 316a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 317a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif // ENABLE(WEB_AUDIO) 318