1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webaudio/blink/DynamicsCompressorKernel.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,490 @@ 1.4 +/* 1.5 + * Copyright (C) 2011 Google Inc. All rights reserved. 1.6 + * 1.7 + * Redistribution and use in source and binary forms, with or without 1.8 + * modification, are permitted provided that the following conditions 1.9 + * are met: 1.10 + * 1.11 + * 1. Redistributions of source code must retain the above copyright 1.12 + * notice, this list of conditions and the following disclaimer. 1.13 + * 2. Redistributions in binary form must reproduce the above copyright 1.14 + * notice, this list of conditions and the following disclaimer in the 1.15 + * documentation and/or other materials provided with the distribution. 1.16 + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 1.17 + * its contributors may be used to endorse or promote products derived 1.18 + * from this software without specific prior written permission. 1.19 + * 1.20 + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 1.21 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1.22 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1.23 + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 1.24 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 1.25 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 1.26 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 1.27 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.28 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1.29 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +#include "DynamicsCompressorKernel.h" 1.33 + 1.34 +#include "DenormalDisabler.h" 1.35 +#include <algorithm> 1.36 + 1.37 +#include "mozilla/FloatingPoint.h" 1.38 +#include "mozilla/Constants.h" 1.39 +#include "WebAudioUtils.h" 1.40 + 1.41 +using namespace std; 1.42 + 1.43 +using namespace mozilla::dom; // for WebAudioUtils 1.44 +using mozilla::IsInfinite; 1.45 +using mozilla::IsNaN; 1.46 + 1.47 +namespace WebCore { 1.48 + 1.49 + 1.50 +// Metering hits peaks instantly, but releases this fast (in seconds). 1.51 +const float meteringReleaseTimeConstant = 0.325f; 1.52 + 1.53 +const float uninitializedValue = -1; 1.54 + 1.55 +DynamicsCompressorKernel::DynamicsCompressorKernel(float sampleRate, unsigned numberOfChannels) 1.56 + : m_sampleRate(sampleRate) 1.57 + , m_lastPreDelayFrames(DefaultPreDelayFrames) 1.58 + , m_preDelayReadIndex(0) 1.59 + , m_preDelayWriteIndex(DefaultPreDelayFrames) 1.60 + , m_ratio(uninitializedValue) 1.61 + , m_slope(uninitializedValue) 1.62 + , m_linearThreshold(uninitializedValue) 1.63 + , m_dbThreshold(uninitializedValue) 1.64 + , m_dbKnee(uninitializedValue) 1.65 + , m_kneeThreshold(uninitializedValue) 1.66 + , m_kneeThresholdDb(uninitializedValue) 1.67 + , m_ykneeThresholdDb(uninitializedValue) 1.68 + , m_K(uninitializedValue) 1.69 +{ 1.70 + setNumberOfChannels(numberOfChannels); 1.71 + 1.72 + // Initializes most member variables 1.73 + reset(); 1.74 + 1.75 + m_meteringReleaseK = 1.76 + static_cast<float>(WebAudioUtils::DiscreteTimeConstantForSampleRate(meteringReleaseTimeConstant, sampleRate)); 1.77 +} 1.78 + 1.79 +size_t DynamicsCompressorKernel::sizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.80 +{ 1.81 + size_t amount = 0; 1.82 + amount += m_preDelayBuffers.SizeOfExcludingThis(aMallocSizeOf); 1.83 + for (size_t i = 0; i < m_preDelayBuffers.Length(); i++) { 1.84 + amount += m_preDelayBuffers[i].SizeOfExcludingThis(aMallocSizeOf); 1.85 + } 1.86 + 1.87 + return amount; 1.88 +} 1.89 + 1.90 +void DynamicsCompressorKernel::setNumberOfChannels(unsigned numberOfChannels) 1.91 +{ 1.92 + if (m_preDelayBuffers.Length() == numberOfChannels) 1.93 + return; 1.94 + 1.95 + m_preDelayBuffers.Clear(); 1.96 + for (unsigned i = 0; i < numberOfChannels; ++i) 1.97 + m_preDelayBuffers.AppendElement(new float[MaxPreDelayFrames]); 1.98 +} 1.99 + 1.100 +void DynamicsCompressorKernel::setPreDelayTime(float preDelayTime) 1.101 +{ 1.102 + // Re-configure look-ahead section pre-delay if delay time has changed. 1.103 + unsigned preDelayFrames = preDelayTime * sampleRate(); 1.104 + if (preDelayFrames > MaxPreDelayFrames - 1) 1.105 + preDelayFrames = MaxPreDelayFrames - 1; 1.106 + 1.107 + if (m_lastPreDelayFrames != preDelayFrames) { 1.108 + m_lastPreDelayFrames = preDelayFrames; 1.109 + for (unsigned i = 0; i < m_preDelayBuffers.Length(); ++i) 1.110 + memset(m_preDelayBuffers[i], 0, sizeof(float) * MaxPreDelayFrames); 1.111 + 1.112 + m_preDelayReadIndex = 0; 1.113 + m_preDelayWriteIndex = preDelayFrames; 1.114 + } 1.115 +} 1.116 + 1.117 +// Exponential curve for the knee. 1.118 +// It is 1st derivative matched at m_linearThreshold and asymptotically approaches the value m_linearThreshold + 1 / k. 1.119 +float DynamicsCompressorKernel::kneeCurve(float x, float k) 1.120 +{ 1.121 + // Linear up to threshold. 1.122 + if (x < m_linearThreshold) 1.123 + return x; 1.124 + 1.125 + return m_linearThreshold + (1 - expf(-k * (x - m_linearThreshold))) / k; 1.126 +} 1.127 + 1.128 +// Full compression curve with constant ratio after knee. 1.129 +float DynamicsCompressorKernel::saturate(float x, float k) 1.130 +{ 1.131 + float y; 1.132 + 1.133 + if (x < m_kneeThreshold) 1.134 + y = kneeCurve(x, k); 1.135 + else { 1.136 + // Constant ratio after knee. 1.137 + float xDb = WebAudioUtils::ConvertLinearToDecibels(x, -1000.0f); 1.138 + float yDb = m_ykneeThresholdDb + m_slope * (xDb - m_kneeThresholdDb); 1.139 + 1.140 + y = WebAudioUtils::ConvertDecibelsToLinear(yDb); 1.141 + } 1.142 + 1.143 + return y; 1.144 +} 1.145 + 1.146 +// Approximate 1st derivative with input and output expressed in dB. 1.147 +// This slope is equal to the inverse of the compression "ratio". 1.148 +// In other words, a compression ratio of 20 would be a slope of 1/20. 1.149 +float DynamicsCompressorKernel::slopeAt(float x, float k) 1.150 +{ 1.151 + if (x < m_linearThreshold) 1.152 + return 1; 1.153 + 1.154 + float x2 = x * 1.001; 1.155 + 1.156 + float xDb = WebAudioUtils::ConvertLinearToDecibels(x, -1000.0f); 1.157 + float x2Db = WebAudioUtils::ConvertLinearToDecibels(x2, -1000.0f); 1.158 + 1.159 + float yDb = WebAudioUtils::ConvertLinearToDecibels(kneeCurve(x, k), -1000.0f); 1.160 + float y2Db = WebAudioUtils::ConvertLinearToDecibels(kneeCurve(x2, k), -1000.0f); 1.161 + 1.162 + float m = (y2Db - yDb) / (x2Db - xDb); 1.163 + 1.164 + return m; 1.165 +} 1.166 + 1.167 +float DynamicsCompressorKernel::kAtSlope(float desiredSlope) 1.168 +{ 1.169 + float xDb = m_dbThreshold + m_dbKnee; 1.170 + float x = WebAudioUtils::ConvertDecibelsToLinear(xDb); 1.171 + 1.172 + // Approximate k given initial values. 1.173 + float minK = 0.1; 1.174 + float maxK = 10000; 1.175 + float k = 5; 1.176 + 1.177 + for (int i = 0; i < 15; ++i) { 1.178 + // A high value for k will more quickly asymptotically approach a slope of 0. 1.179 + float slope = slopeAt(x, k); 1.180 + 1.181 + if (slope < desiredSlope) { 1.182 + // k is too high. 1.183 + maxK = k; 1.184 + } else { 1.185 + // k is too low. 1.186 + minK = k; 1.187 + } 1.188 + 1.189 + // Re-calculate based on geometric mean. 1.190 + k = sqrtf(minK * maxK); 1.191 + } 1.192 + 1.193 + return k; 1.194 +} 1.195 + 1.196 +float DynamicsCompressorKernel::updateStaticCurveParameters(float dbThreshold, float dbKnee, float ratio) 1.197 +{ 1.198 + if (dbThreshold != m_dbThreshold || dbKnee != m_dbKnee || ratio != m_ratio) { 1.199 + // Threshold and knee. 1.200 + m_dbThreshold = dbThreshold; 1.201 + m_linearThreshold = WebAudioUtils::ConvertDecibelsToLinear(dbThreshold); 1.202 + m_dbKnee = dbKnee; 1.203 + 1.204 + // Compute knee parameters. 1.205 + m_ratio = ratio; 1.206 + m_slope = 1 / m_ratio; 1.207 + 1.208 + float k = kAtSlope(1 / m_ratio); 1.209 + 1.210 + m_kneeThresholdDb = dbThreshold + dbKnee; 1.211 + m_kneeThreshold = WebAudioUtils::ConvertDecibelsToLinear(m_kneeThresholdDb); 1.212 + 1.213 + m_ykneeThresholdDb = WebAudioUtils::ConvertLinearToDecibels(kneeCurve(m_kneeThreshold, k), -1000.0f); 1.214 + 1.215 + m_K = k; 1.216 + } 1.217 + return m_K; 1.218 +} 1.219 + 1.220 +void DynamicsCompressorKernel::process(float* sourceChannels[], 1.221 + float* destinationChannels[], 1.222 + unsigned numberOfChannels, 1.223 + unsigned framesToProcess, 1.224 + 1.225 + float dbThreshold, 1.226 + float dbKnee, 1.227 + float ratio, 1.228 + float attackTime, 1.229 + float releaseTime, 1.230 + float preDelayTime, 1.231 + float dbPostGain, 1.232 + float effectBlend, /* equal power crossfade */ 1.233 + 1.234 + float releaseZone1, 1.235 + float releaseZone2, 1.236 + float releaseZone3, 1.237 + float releaseZone4 1.238 + ) 1.239 +{ 1.240 + MOZ_ASSERT(m_preDelayBuffers.Length() == numberOfChannels); 1.241 + 1.242 + float sampleRate = this->sampleRate(); 1.243 + 1.244 + float dryMix = 1 - effectBlend; 1.245 + float wetMix = effectBlend; 1.246 + 1.247 + float k = updateStaticCurveParameters(dbThreshold, dbKnee, ratio); 1.248 + 1.249 + // Makeup gain. 1.250 + float fullRangeGain = saturate(1, k); 1.251 + float fullRangeMakeupGain = 1 / fullRangeGain; 1.252 + 1.253 + // Empirical/perceptual tuning. 1.254 + fullRangeMakeupGain = powf(fullRangeMakeupGain, 0.6f); 1.255 + 1.256 + float masterLinearGain = WebAudioUtils::ConvertDecibelsToLinear(dbPostGain) * fullRangeMakeupGain; 1.257 + 1.258 + // Attack parameters. 1.259 + attackTime = max(0.001f, attackTime); 1.260 + float attackFrames = attackTime * sampleRate; 1.261 + 1.262 + // Release parameters. 1.263 + float releaseFrames = sampleRate * releaseTime; 1.264 + 1.265 + // Detector release time. 1.266 + float satReleaseTime = 0.0025f; 1.267 + float satReleaseFrames = satReleaseTime * sampleRate; 1.268 + 1.269 + // Create a smooth function which passes through four points. 1.270 + 1.271 + // Polynomial of the form 1.272 + // y = a + b*x + c*x^2 + d*x^3 + e*x^4; 1.273 + 1.274 + float y1 = releaseFrames * releaseZone1; 1.275 + float y2 = releaseFrames * releaseZone2; 1.276 + float y3 = releaseFrames * releaseZone3; 1.277 + float y4 = releaseFrames * releaseZone4; 1.278 + 1.279 + // All of these coefficients were derived for 4th order polynomial curve fitting where the y values 1.280 + // match the evenly spaced x values as follows: (y1 : x == 0, y2 : x == 1, y3 : x == 2, y4 : x == 3) 1.281 + float kA = 0.9999999999999998f*y1 + 1.8432219684323923e-16f*y2 - 1.9373394351676423e-16f*y3 + 8.824516011816245e-18f*y4; 1.282 + float kB = -1.5788320352845888f*y1 + 2.3305837032074286f*y2 - 0.9141194204840429f*y3 + 0.1623677525612032f*y4; 1.283 + float kC = 0.5334142869106424f*y1 - 1.272736789213631f*y2 + 0.9258856042207512f*y3 - 0.18656310191776226f*y4; 1.284 + float kD = 0.08783463138207234f*y1 - 0.1694162967925622f*y2 + 0.08588057951595272f*y3 - 0.00429891410546283f*y4; 1.285 + float kE = -0.042416883008123074f*y1 + 0.1115693827987602f*y2 - 0.09764676325265872f*y3 + 0.028494263462021576f*y4; 1.286 + 1.287 + // x ranges from 0 -> 3 0 1 2 3 1.288 + // -15 -10 -5 0db 1.289 + 1.290 + // y calculates adaptive release frames depending on the amount of compression. 1.291 + 1.292 + setPreDelayTime(preDelayTime); 1.293 + 1.294 + const int nDivisionFrames = 32; 1.295 + 1.296 + const int nDivisions = framesToProcess / nDivisionFrames; 1.297 + 1.298 + unsigned frameIndex = 0; 1.299 + for (int i = 0; i < nDivisions; ++i) { 1.300 + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.301 + // Calculate desired gain 1.302 + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.303 + 1.304 + // Fix gremlins. 1.305 + if (IsNaN(m_detectorAverage)) 1.306 + m_detectorAverage = 1; 1.307 + if (IsInfinite(m_detectorAverage)) 1.308 + m_detectorAverage = 1; 1.309 + 1.310 + float desiredGain = m_detectorAverage; 1.311 + 1.312 + // Pre-warp so we get desiredGain after sin() warp below. 1.313 + float scaledDesiredGain = asinf(desiredGain) / (0.5f * M_PI); 1.314 + 1.315 + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.316 + // Deal with envelopes 1.317 + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.318 + 1.319 + // envelopeRate is the rate we slew from current compressor level to the desired level. 1.320 + // The exact rate depends on if we're attacking or releasing and by how much. 1.321 + float envelopeRate; 1.322 + 1.323 + bool isReleasing = scaledDesiredGain > m_compressorGain; 1.324 + 1.325 + // compressionDiffDb is the difference between current compression level and the desired level. 1.326 + float compressionDiffDb = WebAudioUtils::ConvertLinearToDecibels(m_compressorGain / scaledDesiredGain, -1000.0f); 1.327 + 1.328 + if (isReleasing) { 1.329 + // Release mode - compressionDiffDb should be negative dB 1.330 + m_maxAttackCompressionDiffDb = -1; 1.331 + 1.332 + // Fix gremlins. 1.333 + if (IsNaN(compressionDiffDb)) 1.334 + compressionDiffDb = -1; 1.335 + if (IsInfinite(compressionDiffDb)) 1.336 + compressionDiffDb = -1; 1.337 + 1.338 + // Adaptive release - higher compression (lower compressionDiffDb) releases faster. 1.339 + 1.340 + // Contain within range: -12 -> 0 then scale to go from 0 -> 3 1.341 + float x = compressionDiffDb; 1.342 + x = max(-12.0f, x); 1.343 + x = min(0.0f, x); 1.344 + x = 0.25f * (x + 12); 1.345 + 1.346 + // Compute adaptive release curve using 4th order polynomial. 1.347 + // Normal values for the polynomial coefficients would create a monotonically increasing function. 1.348 + float x2 = x * x; 1.349 + float x3 = x2 * x; 1.350 + float x4 = x2 * x2; 1.351 + float releaseFrames = kA + kB * x + kC * x2 + kD * x3 + kE * x4; 1.352 + 1.353 +#define kSpacingDb 5 1.354 + float dbPerFrame = kSpacingDb / releaseFrames; 1.355 + 1.356 + envelopeRate = WebAudioUtils::ConvertDecibelsToLinear(dbPerFrame); 1.357 + } else { 1.358 + // Attack mode - compressionDiffDb should be positive dB 1.359 + 1.360 + // Fix gremlins. 1.361 + if (IsNaN(compressionDiffDb)) 1.362 + compressionDiffDb = 1; 1.363 + if (IsInfinite(compressionDiffDb)) 1.364 + compressionDiffDb = 1; 1.365 + 1.366 + // As long as we're still in attack mode, use a rate based off 1.367 + // the largest compressionDiffDb we've encountered so far. 1.368 + if (m_maxAttackCompressionDiffDb == -1 || m_maxAttackCompressionDiffDb < compressionDiffDb) 1.369 + m_maxAttackCompressionDiffDb = compressionDiffDb; 1.370 + 1.371 + float effAttenDiffDb = max(0.5f, m_maxAttackCompressionDiffDb); 1.372 + 1.373 + float x = 0.25f / effAttenDiffDb; 1.374 + envelopeRate = 1 - powf(x, 1 / attackFrames); 1.375 + } 1.376 + 1.377 + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.378 + // Inner loop - calculate shaped power average - apply compression. 1.379 + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.380 + 1.381 + { 1.382 + int preDelayReadIndex = m_preDelayReadIndex; 1.383 + int preDelayWriteIndex = m_preDelayWriteIndex; 1.384 + float detectorAverage = m_detectorAverage; 1.385 + float compressorGain = m_compressorGain; 1.386 + 1.387 + int loopFrames = nDivisionFrames; 1.388 + while (loopFrames--) { 1.389 + float compressorInput = 0; 1.390 + 1.391 + // Predelay signal, computing compression amount from un-delayed version. 1.392 + for (unsigned i = 0; i < numberOfChannels; ++i) { 1.393 + float* delayBuffer = m_preDelayBuffers[i]; 1.394 + float undelayedSource = sourceChannels[i][frameIndex]; 1.395 + delayBuffer[preDelayWriteIndex] = undelayedSource; 1.396 + 1.397 + float absUndelayedSource = undelayedSource > 0 ? undelayedSource : -undelayedSource; 1.398 + if (compressorInput < absUndelayedSource) 1.399 + compressorInput = absUndelayedSource; 1.400 + } 1.401 + 1.402 + // Calculate shaped power on undelayed input. 1.403 + 1.404 + float scaledInput = compressorInput; 1.405 + float absInput = scaledInput > 0 ? scaledInput : -scaledInput; 1.406 + 1.407 + // Put through shaping curve. 1.408 + // This is linear up to the threshold, then enters a "knee" portion followed by the "ratio" portion. 1.409 + // The transition from the threshold to the knee is smooth (1st derivative matched). 1.410 + // The transition from the knee to the ratio portion is smooth (1st derivative matched). 1.411 + float shapedInput = saturate(absInput, k); 1.412 + 1.413 + float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absInput; 1.414 + 1.415 + float attenuationDb = -WebAudioUtils::ConvertLinearToDecibels(attenuation, -1000.0f); 1.416 + attenuationDb = max(2.0f, attenuationDb); 1.417 + 1.418 + float dbPerFrame = attenuationDb / satReleaseFrames; 1.419 + 1.420 + float satReleaseRate = WebAudioUtils::ConvertDecibelsToLinear(dbPerFrame) - 1; 1.421 + 1.422 + bool isRelease = (attenuation > detectorAverage); 1.423 + float rate = isRelease ? satReleaseRate : 1; 1.424 + 1.425 + detectorAverage += (attenuation - detectorAverage) * rate; 1.426 + detectorAverage = min(1.0f, detectorAverage); 1.427 + 1.428 + // Fix gremlins. 1.429 + if (IsNaN(detectorAverage)) 1.430 + detectorAverage = 1; 1.431 + if (IsInfinite(detectorAverage)) 1.432 + detectorAverage = 1; 1.433 + 1.434 + // Exponential approach to desired gain. 1.435 + if (envelopeRate < 1) { 1.436 + // Attack - reduce gain to desired. 1.437 + compressorGain += (scaledDesiredGain - compressorGain) * envelopeRate; 1.438 + } else { 1.439 + // Release - exponentially increase gain to 1.0 1.440 + compressorGain *= envelopeRate; 1.441 + compressorGain = min(1.0f, compressorGain); 1.442 + } 1.443 + 1.444 + // Warp pre-compression gain to smooth out sharp exponential transition points. 1.445 + float postWarpCompressorGain = sinf(0.5f * M_PI * compressorGain); 1.446 + 1.447 + // Calculate total gain using master gain and effect blend. 1.448 + float totalGain = dryMix + wetMix * masterLinearGain * postWarpCompressorGain; 1.449 + 1.450 + // Calculate metering. 1.451 + float dbRealGain = 20 * log10(postWarpCompressorGain); 1.452 + if (dbRealGain < m_meteringGain) 1.453 + m_meteringGain = dbRealGain; 1.454 + else 1.455 + m_meteringGain += (dbRealGain - m_meteringGain) * m_meteringReleaseK; 1.456 + 1.457 + // Apply final gain. 1.458 + for (unsigned i = 0; i < numberOfChannels; ++i) { 1.459 + float* delayBuffer = m_preDelayBuffers[i]; 1.460 + destinationChannels[i][frameIndex] = delayBuffer[preDelayReadIndex] * totalGain; 1.461 + } 1.462 + 1.463 + frameIndex++; 1.464 + preDelayReadIndex = (preDelayReadIndex + 1) & MaxPreDelayFramesMask; 1.465 + preDelayWriteIndex = (preDelayWriteIndex + 1) & MaxPreDelayFramesMask; 1.466 + } 1.467 + 1.468 + // Locals back to member variables. 1.469 + m_preDelayReadIndex = preDelayReadIndex; 1.470 + m_preDelayWriteIndex = preDelayWriteIndex; 1.471 + m_detectorAverage = DenormalDisabler::flushDenormalFloatToZero(detectorAverage); 1.472 + m_compressorGain = DenormalDisabler::flushDenormalFloatToZero(compressorGain); 1.473 + } 1.474 + } 1.475 +} 1.476 + 1.477 +void DynamicsCompressorKernel::reset() 1.478 +{ 1.479 + m_detectorAverage = 0; 1.480 + m_compressorGain = 1; 1.481 + m_meteringGain = 1; 1.482 + 1.483 + // Predelay section. 1.484 + for (unsigned i = 0; i < m_preDelayBuffers.Length(); ++i) 1.485 + memset(m_preDelayBuffers[i], 0, sizeof(float) * MaxPreDelayFrames); 1.486 + 1.487 + m_preDelayReadIndex = 0; 1.488 + m_preDelayWriteIndex = DefaultPreDelayFrames; 1.489 + 1.490 + m_maxAttackCompressionDiffDb = -1; // uninitialized state 1.491 +} 1.492 + 1.493 +} // namespace WebCore