• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "platform/audio/EqualPowerPanner.h"
30 
31 #include <algorithm>
32 #include "platform/audio/AudioBus.h"
33 #include "platform/audio/AudioUtilities.h"
34 #include "wtf/MathExtras.h"
35 
36 // Use a 50ms smoothing / de-zippering time-constant.
37 const float SmoothingTimeConstant = 0.050f;
38 
39 namespace blink {
40 
EqualPowerPanner(float sampleRate)41 EqualPowerPanner::EqualPowerPanner(float sampleRate)
42     : Panner(PanningModelEqualPower)
43     , m_isFirstRender(true)
44     , m_gainL(0.0)
45     , m_gainR(0.0)
46 {
47     m_smoothingConstant = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate);
48 }
49 
pan(double azimuth,double,const AudioBus * inputBus,AudioBus * outputBus,size_t framesToProcess)50 void EqualPowerPanner::pan(double azimuth, double /*elevation*/, const AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess)
51 {
52     bool isInputSafe = inputBus && (inputBus->numberOfChannels() == 1 || inputBus->numberOfChannels() == 2) && framesToProcess <= inputBus->length();
53     ASSERT(isInputSafe);
54     if (!isInputSafe)
55         return;
56 
57     unsigned numberOfInputChannels = inputBus->numberOfChannels();
58 
59     bool isOutputSafe = outputBus && outputBus->numberOfChannels() == 2 && framesToProcess <= outputBus->length();
60     ASSERT(isOutputSafe);
61     if (!isOutputSafe)
62         return;
63 
64     const float* sourceL = inputBus->channel(0)->data();
65     const float* sourceR = numberOfInputChannels > 1 ? inputBus->channel(1)->data() : sourceL;
66     float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->mutableData();
67     float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->mutableData();
68 
69     if (!sourceL || !sourceR || !destinationL || !destinationR)
70         return;
71 
72     // Clamp azimuth to allowed range of -180 -> +180.
73     azimuth = std::max(-180.0, azimuth);
74     azimuth = std::min(180.0, azimuth);
75 
76     // Alias the azimuth ranges behind us to in front of us:
77     // -90 -> -180 to -90 -> 0 and 90 -> 180 to 90 -> 0
78     if (azimuth < -90)
79         azimuth = -180 - azimuth;
80     else if (azimuth > 90)
81         azimuth = 180 - azimuth;
82 
83     double desiredPanPosition;
84     double desiredGainL;
85     double desiredGainR;
86 
87     if (numberOfInputChannels == 1) { // For mono source case.
88         // Pan smoothly from left to right with azimuth going from -90 -> +90 degrees.
89         desiredPanPosition = (azimuth + 90) / 180;
90     } else { // For stereo source case.
91         if (azimuth <= 0) { // from -90 -> 0
92             // sourceL -> destL and "equal-power pan" sourceR as in mono case
93             // by transforming the "azimuth" value from -90 -> 0 degrees into the range -90 -> +90.
94             desiredPanPosition = (azimuth + 90) / 90;
95         } else { // from 0 -> +90
96             // sourceR -> destR and "equal-power pan" sourceL as in mono case
97             // by transforming the "azimuth" value from 0 -> +90 degrees into the range -90 -> +90.
98             desiredPanPosition = azimuth / 90;
99         }
100     }
101 
102     desiredGainL = std::cos(piOverTwoDouble * desiredPanPosition);
103     desiredGainR = std::sin(piOverTwoDouble * desiredPanPosition);
104 
105     // Don't de-zipper on first render call.
106     if (m_isFirstRender) {
107         m_isFirstRender = false;
108         m_gainL = desiredGainL;
109         m_gainR = desiredGainR;
110     }
111 
112     // Cache in local variables.
113     double gainL = m_gainL;
114     double gainR = m_gainR;
115 
116     // Get local copy of smoothing constant.
117     const double SmoothingConstant = m_smoothingConstant;
118 
119     int n = framesToProcess;
120 
121     if (numberOfInputChannels == 1) { // For mono source case.
122         while (n--) {
123             float inputL = *sourceL++;
124             gainL += (desiredGainL - gainL) * SmoothingConstant;
125             gainR += (desiredGainR - gainR) * SmoothingConstant;
126             *destinationL++ = static_cast<float>(inputL * gainL);
127             *destinationR++ = static_cast<float>(inputL * gainR);
128         }
129     } else { // For stereo source case.
130         if (azimuth <= 0) { // from -90 -> 0
131             while (n--) {
132                 float inputL = *sourceL++;
133                 float inputR = *sourceR++;
134                 gainL += (desiredGainL - gainL) * SmoothingConstant;
135                 gainR += (desiredGainR - gainR) * SmoothingConstant;
136                 *destinationL++ = static_cast<float>(inputL + inputR * gainL);
137                 *destinationR++ = static_cast<float>(inputR * gainR);
138             }
139         } else { // from 0 -> +90
140             while (n--) {
141                 float inputL = *sourceL++;
142                 float inputR = *sourceR++;
143                 gainL += (desiredGainL - gainL) * SmoothingConstant;
144                 gainR += (desiredGainR - gainR) * SmoothingConstant;
145                 *destinationL++ = static_cast<float>(inputL * gainL);
146                 *destinationR++ = static_cast<float>(inputR + inputL * gainR);
147             }
148         }
149     }
150 
151     m_gainL = gainL;
152     m_gainR = gainR;
153 }
154 
155 } // namespace blink
156 
157 #endif // ENABLE(WEB_AUDIO)
158