| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 */ | 23 */ |
| 24 | 24 |
| 25 #include "platform/audio/EqualPowerPanner.h" | 25 #include "platform/audio/EqualPowerPanner.h" |
| 26 #include "platform/audio/AudioBus.h" | 26 #include "platform/audio/AudioBus.h" |
| 27 #include "platform/audio/AudioUtilities.h" | 27 #include "platform/audio/AudioUtilities.h" |
| 28 #include "wtf/MathExtras.h" | 28 #include "wtf/MathExtras.h" |
| 29 #include <algorithm> | 29 #include <algorithm> |
| 30 #include <cmath> | 30 #include <cmath> |
| 31 | 31 |
| 32 // Use a 50ms smoothing / de-zippering time-constant. | |
| 33 const float SmoothingTimeConstant = 0.050f; | |
| 34 | |
| 35 namespace blink { | 32 namespace blink { |
| 36 | 33 |
| 37 EqualPowerPanner::EqualPowerPanner(float sampleRate) | 34 EqualPowerPanner::EqualPowerPanner(float sampleRate) |
| 38 : Panner(PanningModelEqualPower) | 35 : Panner(PanningModelEqualPower) |
| 39 , m_isFirstRender(true) | |
| 40 , m_gainL(0.0) | |
| 41 , m_gainR(0.0) | |
| 42 { | 36 { |
| 43 m_smoothingConstant = AudioUtilities::discreteTimeConstantForSampleRate(Smoo
thingTimeConstant, sampleRate); | |
| 44 } | 37 } |
| 45 | 38 |
| 46 void EqualPowerPanner::pan(double azimuth, double /*elevation*/, const AudioBus*
inputBus, AudioBus* outputBus, size_t framesToProcess) | 39 void EqualPowerPanner::pan(double azimuth, double /*elevation*/, const AudioBus*
inputBus, AudioBus* outputBus, size_t framesToProcess) |
| 47 { | 40 { |
| 48 bool isInputSafe = inputBus && (inputBus->numberOfChannels() == 1 || inputBu
s->numberOfChannels() == 2) && framesToProcess <= inputBus->length(); | 41 bool isInputSafe = inputBus && (inputBus->numberOfChannels() == 1 || inputBu
s->numberOfChannels() == 2) && framesToProcess <= inputBus->length(); |
| 49 ASSERT(isInputSafe); | 42 ASSERT(isInputSafe); |
| 50 if (!isInputSafe) | 43 if (!isInputSafe) |
| 51 return; | 44 return; |
| 52 | 45 |
| 53 unsigned numberOfInputChannels = inputBus->numberOfChannels(); | 46 unsigned numberOfInputChannels = inputBus->numberOfChannels(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 } else { // from 0 -> +90 | 83 } else { // from 0 -> +90 |
| 91 // sourceR -> destR and "equal-power pan" sourceL as in mono case | 84 // sourceR -> destR and "equal-power pan" sourceL as in mono case |
| 92 // by transforming the "azimuth" value from 0 -> +90 degrees into th
e range -90 -> +90. | 85 // by transforming the "azimuth" value from 0 -> +90 degrees into th
e range -90 -> +90. |
| 93 desiredPanPosition = azimuth / 90; | 86 desiredPanPosition = azimuth / 90; |
| 94 } | 87 } |
| 95 } | 88 } |
| 96 | 89 |
| 97 desiredGainL = std::cos(piOverTwoDouble * desiredPanPosition); | 90 desiredGainL = std::cos(piOverTwoDouble * desiredPanPosition); |
| 98 desiredGainR = std::sin(piOverTwoDouble * desiredPanPosition); | 91 desiredGainR = std::sin(piOverTwoDouble * desiredPanPosition); |
| 99 | 92 |
| 100 // Don't de-zipper on first render call. | |
| 101 if (m_isFirstRender) { | |
| 102 m_isFirstRender = false; | |
| 103 m_gainL = desiredGainL; | |
| 104 m_gainR = desiredGainR; | |
| 105 } | |
| 106 | |
| 107 // Cache in local variables. | |
| 108 double gainL = m_gainL; | |
| 109 double gainR = m_gainR; | |
| 110 | |
| 111 // Get local copy of smoothing constant. | |
| 112 const double SmoothingConstant = m_smoothingConstant; | |
| 113 | |
| 114 int n = framesToProcess; | 93 int n = framesToProcess; |
| 115 | 94 |
| 116 if (numberOfInputChannels == 1) { // For mono source case. | 95 if (numberOfInputChannels == 1) { // For mono source case. |
| 117 while (n--) { | 96 while (n--) { |
| 118 float inputL = *sourceL++; | 97 float inputL = *sourceL++; |
| 119 gainL += (desiredGainL - gainL) * SmoothingConstant; | 98 |
| 120 gainR += (desiredGainR - gainR) * SmoothingConstant; | 99 *destinationL++ = static_cast<float>(inputL * desiredGainL); |
| 121 *destinationL++ = static_cast<float>(inputL * gainL); | 100 *destinationR++ = static_cast<float>(inputL * desiredGainR); |
| 122 *destinationR++ = static_cast<float>(inputL * gainR); | |
| 123 } | 101 } |
| 124 } else { // For stereo source case. | 102 } else { // For stereo source case. |
| 125 if (azimuth <= 0) { // from -90 -> 0 | 103 if (azimuth <= 0) { // from -90 -> 0 |
| 126 while (n--) { | 104 while (n--) { |
| 127 float inputL = *sourceL++; | 105 float inputL = *sourceL++; |
| 128 float inputR = *sourceR++; | 106 float inputR = *sourceR++; |
| 129 gainL += (desiredGainL - gainL) * SmoothingConstant; | 107 |
| 130 gainR += (desiredGainR - gainR) * SmoothingConstant; | 108 *destinationL++ = static_cast<float>(inputL + inputR * desiredGa
inL); |
| 131 *destinationL++ = static_cast<float>(inputL + inputR * gainL); | 109 *destinationR++ = static_cast<float>(inputR * desiredGainR); |
| 132 *destinationR++ = static_cast<float>(inputR * gainR); | |
| 133 } | 110 } |
| 134 } else { // from 0 -> +90 | 111 } else { // from 0 -> +90 |
| 135 while (n--) { | 112 while (n--) { |
| 136 float inputL = *sourceL++; | 113 float inputL = *sourceL++; |
| 137 float inputR = *sourceR++; | 114 float inputR = *sourceR++; |
| 138 gainL += (desiredGainL - gainL) * SmoothingConstant; | 115 |
| 139 gainR += (desiredGainR - gainR) * SmoothingConstant; | 116 *destinationL++ = static_cast<float>(inputL * desiredGainL); |
| 140 *destinationL++ = static_cast<float>(inputL * gainL); | 117 *destinationR++ = static_cast<float>(inputR + inputL * desiredGa
inR); |
| 141 *destinationR++ = static_cast<float>(inputR + inputL * gainR); | |
| 142 } | 118 } |
| 143 } | 119 } |
| 144 } | 120 } |
| 121 } |
| 145 | 122 |
| 146 m_gainL = gainL; | 123 void EqualPowerPanner::calculateDesiredGain(double& desiredGainL, double& desire
dGainR, double azimuth, int numberOfInputChannels) |
| 147 m_gainR = gainR; | 124 { |
| 125 // Clamp azimuth to allowed range of -180 -> +180. |
| 126 azimuth = clampTo(azimuth, -180.0, 180.0); |
| 127 |
| 128 // Alias the azimuth ranges behind us to in front of us: |
| 129 // -90 -> -180 to -90 -> 0 and 90 -> 180 to 90 -> 0 |
| 130 if (azimuth < -90) |
| 131 azimuth = -180 - azimuth; |
| 132 else if (azimuth > 90) |
| 133 azimuth = 180 - azimuth; |
| 134 |
| 135 double desiredPanPosition; |
| 136 |
| 137 if (numberOfInputChannels == 1) { // For mono source case. |
| 138 // Pan smoothly from left to right with azimuth going from -90 -> +90 de
grees. |
| 139 desiredPanPosition = (azimuth + 90) / 180; |
| 140 } else { // For stereo source case. |
| 141 if (azimuth <= 0) { // from -90 -> 0 |
| 142 // sourceL -> destL and "equal-power pan" sourceR as in mono case |
| 143 // by transforming the "azimuth" value from -90 -> 0 degrees into th
e range -90 -> +90. |
| 144 desiredPanPosition = (azimuth + 90) / 90; |
| 145 } else { // from 0 -> +90 |
| 146 // sourceR -> destR and "equal-power pan" sourceL as in mono case |
| 147 // by transforming the "azimuth" value from 0 -> +90 degrees into th
e range -90 -> +90. |
| 148 desiredPanPosition = azimuth / 90; |
| 149 } |
| 150 } |
| 151 |
| 152 desiredGainL = std::cos(piOverTwoDouble * desiredPanPosition); |
| 153 desiredGainR = std::sin(piOverTwoDouble * desiredPanPosition); |
| 154 } |
| 155 |
| 156 void EqualPowerPanner::panWithSampleAccurateValues(double* azimuth, double* /*el
evation*/, const AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess
) |
| 157 { |
| 158 bool isInputSafe = inputBus && (inputBus->numberOfChannels() == 1 || inputBu
s->numberOfChannels() == 2) && framesToProcess <= inputBus->length(); |
| 159 DCHECK(isInputSafe); |
| 160 if (!isInputSafe) |
| 161 return; |
| 162 |
| 163 unsigned numberOfInputChannels = inputBus->numberOfChannels(); |
| 164 |
| 165 bool isOutputSafe = outputBus && outputBus->numberOfChannels() == 2 && frame
sToProcess <= outputBus->length(); |
| 166 DCHECK(isOutputSafe); |
| 167 if (!isOutputSafe) |
| 168 return; |
| 169 |
| 170 const float* sourceL = inputBus->channel(0)->data(); |
| 171 const float* sourceR = numberOfInputChannels > 1 ? inputBus->channel(1)->dat
a() : sourceL; |
| 172 float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->mutab
leData(); |
| 173 float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->muta
bleData(); |
| 174 |
| 175 if (!sourceL || !sourceR || !destinationL || !destinationR) |
| 176 return; |
| 177 |
| 178 int n = framesToProcess; |
| 179 |
| 180 if (numberOfInputChannels == 1) { // For mono source case. |
| 181 for (int k = 0; k < n; ++k) { |
| 182 double desiredGainL; |
| 183 double desiredGainR; |
| 184 float inputL = *sourceL++; |
| 185 |
| 186 calculateDesiredGain(desiredGainL, desiredGainR, azimuth[k], numberO
fInputChannels); |
| 187 *destinationL++ = static_cast<float>(inputL * desiredGainL); |
| 188 *destinationR++ = static_cast<float>(inputL * desiredGainR); |
| 189 } |
| 190 } else { // For stereo source case. |
| 191 for (int k = 0; k < n; ++k) { |
| 192 double desiredGainL; |
| 193 double desiredGainR; |
| 194 |
| 195 calculateDesiredGain(desiredGainL, desiredGainR, azimuth[k], numberO
fInputChannels); |
| 196 if (azimuth[k] <= 0) { // from -90 -> 0 |
| 197 float inputL = *sourceL++; |
| 198 float inputR = *sourceR++; |
| 199 *destinationL++ = static_cast<float>(inputL + inputR * desiredGa
inL); |
| 200 *destinationR++ = static_cast<float>(inputR * desiredGainR); |
| 201 } else { // from 0 -> +90 |
| 202 float inputL = *sourceL++; |
| 203 float inputR = *sourceR++; |
| 204 *destinationL++ = static_cast<float>(inputL * desiredGainL); |
| 205 *destinationR++ = static_cast<float>(inputR + inputL * desiredGa
inR); |
| 206 } |
| 207 } |
| 208 } |
| 148 } | 209 } |
| 149 | 210 |
| 150 } // namespace blink | 211 } // namespace blink |
| 151 | 212 |
| OLD | NEW |