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