blob: 903536786376517b6c1f34408c7cb940e79335ef [file] [log] [blame]
crogers@google.com91927882010-10-05 07:45:05 +00001/*
2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26
27#if ENABLE(WEB_AUDIO)
28
29#include "EqualPowerPanner.h"
30
31#include "AudioBus.h"
32#include "AudioUtilities.h"
crogers@google.comd80c3f72011-05-18 23:14:25 +000033#include <algorithm>
kbr@google.comc0a4fef2010-12-07 21:45:04 +000034#include <wtf/MathExtras.h>
crogers@google.com91927882010-10-05 07:45:05 +000035
36// Use a 50ms smoothing / de-zippering time-constant.
jer.noble@apple.com817bc152011-10-05 20:53:43 +000037const float SmoothingTimeConstant = 0.050f;
crogers@google.comd80c3f72011-05-18 23:14:25 +000038
39using namespace std;
40
crogers@google.com91927882010-10-05 07:45:05 +000041namespace WebCore {
42
jer.noble@apple.com817bc152011-10-05 20:53:43 +000043EqualPowerPanner::EqualPowerPanner(float sampleRate)
crogers@google.com91927882010-10-05 07:45:05 +000044 : Panner(PanningModelEqualPower)
45 , m_isFirstRender(true)
46 , m_gainL(0.0)
47 , m_gainR(0.0)
48{
49 m_smoothingConstant = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate);
50}
51
jer.noble@apple.coma39a2382012-01-19 20:01:09 +000052void EqualPowerPanner::pan(double azimuth, double /*elevation*/, const AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess)
crogers@google.com91927882010-10-05 07:45:05 +000053{
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +000054 unsigned numberOfInputChannels = inputBus->numberOfChannels();
55 bool isInputSafe = inputBus && (numberOfInputChannels == 1 || numberOfInputChannels == 2) && framesToProcess <= inputBus->length();
crogers@google.com91927882010-10-05 07:45:05 +000056 ASSERT(isInputSafe);
57 if (!isInputSafe)
58 return;
59
60 bool isOutputSafe = outputBus && outputBus->numberOfChannels() == 2 && framesToProcess <= outputBus->length();
61 ASSERT(isOutputSafe);
62 if (!isOutputSafe)
63 return;
64
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +000065 const float* sourceL = inputBus->channel(0)->data();
66 const float* sourceR = numberOfInputChannels > 1 ? inputBus->channel(1)->data() : sourceL;
jer.noble@apple.coma39a2382012-01-19 20:01:09 +000067 float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->mutableData();
68 float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->mutableData();
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +000069
70 if (!sourceL || !sourceR || !destinationL || !destinationR)
crogers@google.com91927882010-10-05 07:45:05 +000071 return;
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +000072
crogers@google.comd80c3f72011-05-18 23:14:25 +000073 // Clamp azimuth to allowed range of -180 -> +180.
74 azimuth = max(-180.0, azimuth);
75 azimuth = min(180.0, azimuth);
76
77 // Alias the azimuth ranges behind us to in front of us:
78 // -90 -> -180 to -90 -> 0 and 90 -> 180 to 90 -> 0
79 if (azimuth < -90)
80 azimuth = -180 - azimuth;
81 else if (azimuth > 90)
82 azimuth = 180 - azimuth;
crogers@google.com91927882010-10-05 07:45:05 +000083
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +000084 double desiredPanPosition;
85 double desiredGainL;
86 double desiredGainR;
crogers@google.com91927882010-10-05 07:45:05 +000087
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +000088 if (numberOfInputChannels == 1) { // For mono source case.
89 // Pan smoothly from left to right with azimuth going from -90 -> +90 degrees.
90 desiredPanPosition = (azimuth + 90) / 180;
91 } else { // For stereo source case.
92 if (azimuth <= 0) { // from -90 -> 0
93 // sourceL -> destL and "equal-power pan" sourceR as in mono case
94 // by transforming the "azimuth" value from -90 -> 0 degrees into the range -90 -> +90.
95 desiredPanPosition = (azimuth + 90) / 90;
96 } else { // from 0 -> +90
97 // sourceR -> destR and "equal-power pan" sourceL as in mono case
98 // by transforming the "azimuth" value from 0 -> +90 degrees into the range -90 -> +90.
99 desiredPanPosition = azimuth / 90;
100 }
101 }
102
103 desiredGainL = cos(0.5 * piDouble * desiredPanPosition);
104 desiredGainR = sin(0.5 * piDouble * desiredPanPosition);
105
crogers@google.com91927882010-10-05 07:45:05 +0000106 // Don't de-zipper on first render call.
107 if (m_isFirstRender) {
108 m_isFirstRender = false;
109 m_gainL = desiredGainL;
110 m_gainR = desiredGainR;
111 }
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +0000112
crogers@google.com91927882010-10-05 07:45:05 +0000113 // Cache in local variables.
114 double gainL = m_gainL;
115 double gainR = m_gainR;
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +0000116
crogers@google.com91927882010-10-05 07:45:05 +0000117 // Get local copy of smoothing constant.
118 const double SmoothingConstant = m_smoothingConstant;
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +0000119
crogers@google.com91927882010-10-05 07:45:05 +0000120 int n = framesToProcess;
121
commit-queue@webkit.orgd193f5f2012-04-11 19:26:28 +0000122 if (numberOfInputChannels == 1) { // For mono source case.
123 while (n--) {
124 float inputL = *sourceL++;
125 gainL += (desiredGainL - gainL) * SmoothingConstant;
126 gainR += (desiredGainR - gainR) * SmoothingConstant;
127 *destinationL++ = static_cast<float>(inputL * gainL);
128 *destinationR++ = static_cast<float>(inputL * gainR);
129 }
130 } else { // For stereo source case.
131 if (azimuth <= 0) { // from -90 -> 0
132 while (n--) {
133 float inputL = *sourceL++;
134 float inputR = *sourceR++;
135 gainL += (desiredGainL - gainL) * SmoothingConstant;
136 gainR += (desiredGainR - gainR) * SmoothingConstant;
137 *destinationL++ = static_cast<float>(inputL + inputR * gainL);
138 *destinationR++ = static_cast<float>(inputR * gainR);
139 }
140 } else { // from 0 -> +90
141 while (n--) {
142 float inputL = *sourceL++;
143 float inputR = *sourceR++;
144 gainL += (desiredGainL - gainL) * SmoothingConstant;
145 gainR += (desiredGainR - gainR) * SmoothingConstant;
146 *destinationL++ = static_cast<float>(inputL * gainL);
147 *destinationR++ = static_cast<float>(inputR + inputL * gainR);
148 }
149 }
crogers@google.com91927882010-10-05 07:45:05 +0000150 }
151
152 m_gainL = gainL;
153 m_gainR = gainR;
154}
155
156} // namespace WebCore
157
158#endif // ENABLE(WEB_AUDIO)