LCOV - code coverage report
Current view: top level - dom/media/webaudio/blink - DynamicsCompressorKernel.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 200 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2011 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             :  *
       8             :  * 1.  Redistributions of source code must retain the above copyright
       9             :  *     notice, this list of conditions and the following disclaimer.
      10             :  * 2.  Redistributions in binary form must reproduce the above copyright
      11             :  *     notice, this list of conditions and the following disclaimer in the
      12             :  *     documentation and/or other materials provided with the distribution.
      13             :  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
      14             :  *     its contributors may be used to endorse or promote products derived
      15             :  *     from this software without specific prior written permission.
      16             :  *
      17             :  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
      18             :  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      19             :  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      20             :  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
      21             :  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      22             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      23             :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      24             :  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : 
      29             : #include "DynamicsCompressorKernel.h"
      30             : 
      31             : #include "DenormalDisabler.h"
      32             : #include <algorithm>
      33             : #include <cmath>
      34             : 
      35             : #include "mozilla/FloatingPoint.h"
      36             : #include "WebAudioUtils.h"
      37             : 
      38             : using namespace std;
      39             : 
      40             : using namespace mozilla::dom; // for WebAudioUtils
      41             : using mozilla::IsInfinite;
      42             : using mozilla::IsNaN;
      43             : using mozilla::MakeUnique;
      44             : 
      45             : namespace WebCore {
      46             : 
      47             : 
      48             : // Metering hits peaks instantly, but releases this fast (in seconds).
      49             : const float meteringReleaseTimeConstant = 0.325f;
      50             : 
      51             : const float uninitializedValue = -1;
      52             : 
      53           0 : DynamicsCompressorKernel::DynamicsCompressorKernel(float sampleRate, unsigned numberOfChannels)
      54             :     : m_sampleRate(sampleRate)
      55             :     , m_lastPreDelayFrames(DefaultPreDelayFrames)
      56             :     , m_preDelayReadIndex(0)
      57             :     , m_preDelayWriteIndex(DefaultPreDelayFrames)
      58             :     , m_ratio(uninitializedValue)
      59             :     , m_slope(uninitializedValue)
      60             :     , m_linearThreshold(uninitializedValue)
      61             :     , m_dbThreshold(uninitializedValue)
      62             :     , m_dbKnee(uninitializedValue)
      63             :     , m_kneeThreshold(uninitializedValue)
      64             :     , m_kneeThresholdDb(uninitializedValue)
      65             :     , m_ykneeThresholdDb(uninitializedValue)
      66           0 :     , m_K(uninitializedValue)
      67             : {
      68           0 :     setNumberOfChannels(numberOfChannels);
      69             : 
      70             :     // Initializes most member variables
      71           0 :     reset();
      72             : 
      73           0 :     m_meteringReleaseK =
      74           0 :         static_cast<float>(WebAudioUtils::DiscreteTimeConstantForSampleRate(meteringReleaseTimeConstant, sampleRate));
      75           0 : }
      76             : 
      77           0 : size_t DynamicsCompressorKernel::sizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
      78             : {
      79           0 :     size_t amount = 0;
      80           0 :     amount += m_preDelayBuffers.ShallowSizeOfExcludingThis(aMallocSizeOf);
      81           0 :     for (size_t i = 0; i < m_preDelayBuffers.Length(); i++) {
      82           0 :         amount += aMallocSizeOf(m_preDelayBuffers[i].get());
      83             :     }
      84             : 
      85           0 :     return amount;
      86             : }
      87             : 
      88           0 : void DynamicsCompressorKernel::setNumberOfChannels(unsigned numberOfChannels)
      89             : {
      90           0 :     if (m_preDelayBuffers.Length() == numberOfChannels)
      91           0 :         return;
      92             : 
      93           0 :     m_preDelayBuffers.Clear();
      94           0 :     for (unsigned i = 0; i < numberOfChannels; ++i)
      95           0 :       m_preDelayBuffers.AppendElement(MakeUnique<float[]>(MaxPreDelayFrames));
      96             : }
      97             : 
      98           0 : void DynamicsCompressorKernel::setPreDelayTime(float preDelayTime)
      99             : {
     100             :     // Re-configure look-ahead section pre-delay if delay time has changed.
     101           0 :     unsigned preDelayFrames = preDelayTime * sampleRate();
     102           0 :     if (preDelayFrames > MaxPreDelayFrames - 1)
     103           0 :         preDelayFrames = MaxPreDelayFrames - 1;
     104             : 
     105           0 :     if (m_lastPreDelayFrames != preDelayFrames) {
     106           0 :         m_lastPreDelayFrames = preDelayFrames;
     107           0 :         for (unsigned i = 0; i < m_preDelayBuffers.Length(); ++i)
     108           0 :           memset(m_preDelayBuffers[i].get(), 0, sizeof(float) * MaxPreDelayFrames);
     109             : 
     110           0 :         m_preDelayReadIndex = 0;
     111           0 :         m_preDelayWriteIndex = preDelayFrames;
     112             :     }
     113           0 : }
     114             : 
     115             : // Exponential curve for the knee.
     116             : // It is 1st derivative matched at m_linearThreshold and asymptotically approaches the value m_linearThreshold + 1 / k.
     117           0 : float DynamicsCompressorKernel::kneeCurve(float x, float k)
     118             : {
     119             :     // Linear up to threshold.
     120           0 :     if (x < m_linearThreshold)
     121           0 :         return x;
     122             : 
     123           0 :     return m_linearThreshold + (1 - expf(-k * (x - m_linearThreshold))) / k;
     124             : }
     125             : 
     126             : // Full compression curve with constant ratio after knee.
     127           0 : float DynamicsCompressorKernel::saturate(float x, float k)
     128             : {
     129             :     float y;
     130             : 
     131           0 :     if (x < m_kneeThreshold)
     132           0 :         y = kneeCurve(x, k);
     133             :     else {
     134             :         // Constant ratio after knee.
     135           0 :         float xDb = WebAudioUtils::ConvertLinearToDecibels(x, -1000.0f);
     136           0 :         float yDb = m_ykneeThresholdDb + m_slope * (xDb - m_kneeThresholdDb);
     137             : 
     138           0 :         y = WebAudioUtils::ConvertDecibelsToLinear(yDb);
     139             :     }
     140             : 
     141           0 :     return y;
     142             : }
     143             : 
     144             : // Approximate 1st derivative with input and output expressed in dB.
     145             : // This slope is equal to the inverse of the compression "ratio".
     146             : // In other words, a compression ratio of 20 would be a slope of 1/20.
     147           0 : float DynamicsCompressorKernel::slopeAt(float x, float k)
     148             : {
     149           0 :     if (x < m_linearThreshold)
     150           0 :         return 1;
     151             : 
     152           0 :     float x2 = x * 1.001;
     153             : 
     154           0 :     float xDb = WebAudioUtils::ConvertLinearToDecibels(x, -1000.0f);
     155           0 :     float x2Db = WebAudioUtils::ConvertLinearToDecibels(x2, -1000.0f);
     156             : 
     157           0 :     float yDb = WebAudioUtils::ConvertLinearToDecibels(kneeCurve(x, k), -1000.0f);
     158           0 :     float y2Db = WebAudioUtils::ConvertLinearToDecibels(kneeCurve(x2, k), -1000.0f);
     159             : 
     160           0 :     float m = (y2Db - yDb) / (x2Db - xDb);
     161             : 
     162           0 :     return m;
     163             : }
     164             : 
     165           0 : float DynamicsCompressorKernel::kAtSlope(float desiredSlope)
     166             : {
     167           0 :     float xDb = m_dbThreshold + m_dbKnee;
     168           0 :     float x = WebAudioUtils::ConvertDecibelsToLinear(xDb);
     169             : 
     170             :     // Approximate k given initial values.
     171           0 :     float minK = 0.1f;
     172           0 :     float maxK = 10000;
     173           0 :     float k = 5;
     174             : 
     175           0 :     for (int i = 0; i < 15; ++i) {
     176             :         // A high value for k will more quickly asymptotically approach a slope of 0.
     177           0 :         float slope = slopeAt(x, k);
     178             : 
     179           0 :         if (slope < desiredSlope) {
     180             :             // k is too high.
     181           0 :             maxK = k;
     182             :         } else {
     183             :             // k is too low.
     184           0 :             minK = k;
     185             :         }
     186             : 
     187             :         // Re-calculate based on geometric mean.
     188           0 :         k = sqrtf(minK * maxK);
     189             :     }
     190             : 
     191           0 :     return k;
     192             : }
     193             : 
     194           0 : float DynamicsCompressorKernel::updateStaticCurveParameters(float dbThreshold, float dbKnee, float ratio)
     195             : {
     196           0 :     if (dbThreshold != m_dbThreshold || dbKnee != m_dbKnee || ratio != m_ratio) {
     197             :         // Threshold and knee.
     198           0 :         m_dbThreshold = dbThreshold;
     199           0 :         m_linearThreshold = WebAudioUtils::ConvertDecibelsToLinear(dbThreshold);
     200           0 :         m_dbKnee = dbKnee;
     201             : 
     202             :         // Compute knee parameters.
     203           0 :         m_ratio = ratio;
     204           0 :         m_slope = 1 / m_ratio;
     205             : 
     206           0 :         float k = kAtSlope(1 / m_ratio);
     207             : 
     208           0 :         m_kneeThresholdDb = dbThreshold + dbKnee;
     209           0 :         m_kneeThreshold = WebAudioUtils::ConvertDecibelsToLinear(m_kneeThresholdDb);
     210             : 
     211           0 :         m_ykneeThresholdDb = WebAudioUtils::ConvertLinearToDecibels(kneeCurve(m_kneeThreshold, k), -1000.0f);
     212             : 
     213           0 :         m_K = k;
     214             :     }
     215           0 :     return m_K;
     216             : }
     217             : 
     218           0 : void DynamicsCompressorKernel::process(float* sourceChannels[],
     219             :                                        float* destinationChannels[],
     220             :                                        unsigned numberOfChannels,
     221             :                                        unsigned framesToProcess,
     222             : 
     223             :                                        float dbThreshold,
     224             :                                        float dbKnee,
     225             :                                        float ratio,
     226             :                                        float attackTime,
     227             :                                        float releaseTime,
     228             :                                        float preDelayTime,
     229             :                                        float dbPostGain,
     230             :                                        float effectBlend, /* equal power crossfade */
     231             : 
     232             :                                        float releaseZone1,
     233             :                                        float releaseZone2,
     234             :                                        float releaseZone3,
     235             :                                        float releaseZone4
     236             :                                        )
     237             : {
     238           0 :     MOZ_ASSERT(m_preDelayBuffers.Length() == numberOfChannels);
     239             : 
     240           0 :     float sampleRate = this->sampleRate();
     241             : 
     242           0 :     float dryMix = 1 - effectBlend;
     243           0 :     float wetMix = effectBlend;
     244             : 
     245           0 :     float k = updateStaticCurveParameters(dbThreshold, dbKnee, ratio);
     246             : 
     247             :     // Makeup gain.
     248           0 :     float fullRangeGain = saturate(1, k);
     249           0 :     float fullRangeMakeupGain = 1 / fullRangeGain;
     250             : 
     251             :     // Empirical/perceptual tuning.
     252           0 :     fullRangeMakeupGain = powf(fullRangeMakeupGain, 0.6f);
     253             : 
     254           0 :     float masterLinearGain = WebAudioUtils::ConvertDecibelsToLinear(dbPostGain) * fullRangeMakeupGain;
     255             : 
     256             :     // Attack parameters.
     257           0 :     attackTime = max(0.001f, attackTime);
     258           0 :     float attackFrames = attackTime * sampleRate;
     259             : 
     260             :     // Release parameters.
     261           0 :     float releaseFrames = sampleRate * releaseTime;
     262             : 
     263             :     // Detector release time.
     264           0 :     float satReleaseTime = 0.0025f;
     265           0 :     float satReleaseFrames = satReleaseTime * sampleRate;
     266             : 
     267             :     // Create a smooth function which passes through four points.
     268             : 
     269             :     // Polynomial of the form
     270             :     // y = a + b*x + c*x^2 + d*x^3 + e*x^4;
     271             : 
     272           0 :     float y1 = releaseFrames * releaseZone1;
     273           0 :     float y2 = releaseFrames * releaseZone2;
     274           0 :     float y3 = releaseFrames * releaseZone3;
     275           0 :     float y4 = releaseFrames * releaseZone4;
     276             : 
     277             :     // All of these coefficients were derived for 4th order polynomial curve fitting where the y values
     278             :     // match the evenly spaced x values as follows: (y1 : x == 0, y2 : x == 1, y3 : x == 2, y4 : x == 3)
     279           0 :     float kA = 0.9999999999999998f*y1 + 1.8432219684323923e-16f*y2 - 1.9373394351676423e-16f*y3 + 8.824516011816245e-18f*y4;
     280           0 :     float kB = -1.5788320352845888f*y1 + 2.3305837032074286f*y2 - 0.9141194204840429f*y3 + 0.1623677525612032f*y4;
     281           0 :     float kC = 0.5334142869106424f*y1 - 1.272736789213631f*y2 + 0.9258856042207512f*y3 - 0.18656310191776226f*y4;
     282           0 :     float kD = 0.08783463138207234f*y1 - 0.1694162967925622f*y2 + 0.08588057951595272f*y3 - 0.00429891410546283f*y4;
     283           0 :     float kE = -0.042416883008123074f*y1 + 0.1115693827987602f*y2 - 0.09764676325265872f*y3 + 0.028494263462021576f*y4;
     284             : 
     285             :     // x ranges from 0 -> 3       0    1    2   3
     286             :     //                           -15  -10  -5   0db
     287             : 
     288             :     // y calculates adaptive release frames depending on the amount of compression.
     289             : 
     290           0 :     setPreDelayTime(preDelayTime);
     291             : 
     292           0 :     const int nDivisionFrames = 32;
     293             : 
     294           0 :     const int nDivisions = framesToProcess / nDivisionFrames;
     295             : 
     296           0 :     unsigned frameIndex = 0;
     297           0 :     for (int i = 0; i < nDivisions; ++i) {
     298             :         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     299             :         // Calculate desired gain
     300             :         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     301             : 
     302             :         // Fix gremlins.
     303           0 :         if (IsNaN(m_detectorAverage))
     304           0 :             m_detectorAverage = 1;
     305           0 :         if (IsInfinite(m_detectorAverage))
     306           0 :             m_detectorAverage = 1;
     307             : 
     308           0 :         float desiredGain = m_detectorAverage;
     309             : 
     310             :         // Pre-warp so we get desiredGain after sin() warp below.
     311           0 :         float scaledDesiredGain = asinf(desiredGain) / (0.5f * M_PI);
     312             : 
     313             :         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     314             :         // Deal with envelopes
     315             :         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     316             : 
     317             :         // envelopeRate is the rate we slew from current compressor level to the desired level.
     318             :         // The exact rate depends on if we're attacking or releasing and by how much.
     319             :         float envelopeRate;
     320             : 
     321           0 :         bool isReleasing = scaledDesiredGain > m_compressorGain;
     322             : 
     323             :         // compressionDiffDb is the difference between current compression level and the desired level.
     324           0 :         float compressionDiffDb = WebAudioUtils::ConvertLinearToDecibels(m_compressorGain / scaledDesiredGain, -1000.0f);
     325             : 
     326           0 :         if (isReleasing) {
     327             :             // Release mode - compressionDiffDb should be negative dB
     328           0 :             m_maxAttackCompressionDiffDb = -1;
     329             : 
     330             :             // Fix gremlins.
     331           0 :             if (IsNaN(compressionDiffDb))
     332           0 :                 compressionDiffDb = -1;
     333           0 :             if (IsInfinite(compressionDiffDb))
     334           0 :                 compressionDiffDb = -1;
     335             : 
     336             :             // Adaptive release - higher compression (lower compressionDiffDb)  releases faster.
     337             : 
     338             :             // Contain within range: -12 -> 0 then scale to go from 0 -> 3
     339           0 :             float x = compressionDiffDb;
     340           0 :             x = max(-12.0f, x);
     341           0 :             x = min(0.0f, x);
     342           0 :             x = 0.25f * (x + 12);
     343             : 
     344             :             // Compute adaptive release curve using 4th order polynomial.
     345             :             // Normal values for the polynomial coefficients would create a monotonically increasing function.
     346           0 :             float x2 = x * x;
     347           0 :             float x3 = x2 * x;
     348           0 :             float x4 = x2 * x2;
     349           0 :             float releaseFrames = kA + kB * x + kC * x2 + kD * x3 + kE * x4;
     350             : 
     351             : #define kSpacingDb 5
     352           0 :             float dbPerFrame = kSpacingDb / releaseFrames;
     353             : 
     354           0 :             envelopeRate = WebAudioUtils::ConvertDecibelsToLinear(dbPerFrame);
     355             :         } else {
     356             :             // Attack mode - compressionDiffDb should be positive dB
     357             : 
     358             :             // Fix gremlins.
     359           0 :             if (IsNaN(compressionDiffDb))
     360           0 :                 compressionDiffDb = 1;
     361           0 :             if (IsInfinite(compressionDiffDb))
     362           0 :                 compressionDiffDb = 1;
     363             : 
     364             :             // As long as we're still in attack mode, use a rate based off
     365             :             // the largest compressionDiffDb we've encountered so far.
     366           0 :             if (m_maxAttackCompressionDiffDb == -1 || m_maxAttackCompressionDiffDb < compressionDiffDb)
     367           0 :                 m_maxAttackCompressionDiffDb = compressionDiffDb;
     368             : 
     369           0 :             float effAttenDiffDb = max(0.5f, m_maxAttackCompressionDiffDb);
     370             : 
     371           0 :             float x = 0.25f / effAttenDiffDb;
     372           0 :             envelopeRate = 1 - powf(x, 1 / attackFrames);
     373             :         }
     374             : 
     375             :         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     376             :         // Inner loop - calculate shaped power average - apply compression.
     377             :         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     378             : 
     379             :         {
     380           0 :             int preDelayReadIndex = m_preDelayReadIndex;
     381           0 :             int preDelayWriteIndex = m_preDelayWriteIndex;
     382           0 :             float detectorAverage = m_detectorAverage;
     383           0 :             float compressorGain = m_compressorGain;
     384             : 
     385           0 :             int loopFrames = nDivisionFrames;
     386           0 :             while (loopFrames--) {
     387           0 :                 float compressorInput = 0;
     388             : 
     389             :                 // Predelay signal, computing compression amount from un-delayed version.
     390           0 :                 for (unsigned i = 0; i < numberOfChannels; ++i) {
     391           0 :                     float* delayBuffer = m_preDelayBuffers[i].get();
     392           0 :                     float undelayedSource = sourceChannels[i][frameIndex];
     393           0 :                     delayBuffer[preDelayWriteIndex] = undelayedSource;
     394             : 
     395           0 :                     float absUndelayedSource = undelayedSource > 0 ? undelayedSource : -undelayedSource;
     396           0 :                     if (compressorInput < absUndelayedSource)
     397           0 :                         compressorInput = absUndelayedSource;
     398             :                 }
     399             : 
     400             :                 // Calculate shaped power on undelayed input.
     401             : 
     402           0 :                 float scaledInput = compressorInput;
     403           0 :                 float absInput = scaledInput > 0 ? scaledInput : -scaledInput;
     404             : 
     405             :                 // Put through shaping curve.
     406             :                 // This is linear up to the threshold, then enters a "knee" portion followed by the "ratio" portion.
     407             :                 // The transition from the threshold to the knee is smooth (1st derivative matched).
     408             :                 // The transition from the knee to the ratio portion is smooth (1st derivative matched).
     409           0 :                 float shapedInput = saturate(absInput, k);
     410             : 
     411           0 :                 float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absInput;
     412             : 
     413           0 :                 float attenuationDb = -WebAudioUtils::ConvertLinearToDecibels(attenuation, -1000.0f);
     414           0 :                 attenuationDb = max(2.0f, attenuationDb);
     415             : 
     416           0 :                 float dbPerFrame = attenuationDb / satReleaseFrames;
     417             : 
     418           0 :                 float satReleaseRate = WebAudioUtils::ConvertDecibelsToLinear(dbPerFrame) - 1;
     419             : 
     420           0 :                 bool isRelease = (attenuation > detectorAverage);
     421           0 :                 float rate = isRelease ? satReleaseRate : 1;
     422             : 
     423           0 :                 detectorAverage += (attenuation - detectorAverage) * rate;
     424           0 :                 detectorAverage = min(1.0f, detectorAverage);
     425             : 
     426             :                 // Fix gremlins.
     427           0 :                 if (IsNaN(detectorAverage))
     428           0 :                     detectorAverage = 1;
     429           0 :                 if (IsInfinite(detectorAverage))
     430           0 :                     detectorAverage = 1;
     431             : 
     432             :                 // Exponential approach to desired gain.
     433           0 :                 if (envelopeRate < 1) {
     434             :                     // Attack - reduce gain to desired.
     435           0 :                     compressorGain += (scaledDesiredGain - compressorGain) * envelopeRate;
     436             :                 } else {
     437             :                     // Release - exponentially increase gain to 1.0
     438           0 :                     compressorGain *= envelopeRate;
     439           0 :                     compressorGain = min(1.0f, compressorGain);
     440             :                 }
     441             : 
     442             :                 // Warp pre-compression gain to smooth out sharp exponential transition points.
     443           0 :                 float postWarpCompressorGain = sinf(0.5f * M_PI * compressorGain);
     444             : 
     445             :                 // Calculate total gain using master gain and effect blend.
     446           0 :                 float totalGain = dryMix + wetMix * masterLinearGain * postWarpCompressorGain;
     447             : 
     448             :                 // Calculate metering.
     449           0 :                 float dbRealGain = 20 * log10(postWarpCompressorGain);
     450           0 :                 if (dbRealGain < m_meteringGain)
     451           0 :                     m_meteringGain = dbRealGain;
     452             :                 else
     453           0 :                     m_meteringGain += (dbRealGain - m_meteringGain) * m_meteringReleaseK;
     454             : 
     455             :                 // Apply final gain.
     456           0 :                 for (unsigned i = 0; i < numberOfChannels; ++i) {
     457           0 :                     float* delayBuffer = m_preDelayBuffers[i].get();
     458           0 :                     destinationChannels[i][frameIndex] = delayBuffer[preDelayReadIndex] * totalGain;
     459             :                 }
     460             : 
     461           0 :                 frameIndex++;
     462           0 :                 preDelayReadIndex = (preDelayReadIndex + 1) & MaxPreDelayFramesMask;
     463           0 :                 preDelayWriteIndex = (preDelayWriteIndex + 1) & MaxPreDelayFramesMask;
     464             :             }
     465             : 
     466             :             // Locals back to member variables.
     467           0 :             m_preDelayReadIndex = preDelayReadIndex;
     468           0 :             m_preDelayWriteIndex = preDelayWriteIndex;
     469           0 :             m_detectorAverage = DenormalDisabler::flushDenormalFloatToZero(detectorAverage);
     470           0 :             m_compressorGain = DenormalDisabler::flushDenormalFloatToZero(compressorGain);
     471             :         }
     472             :     }
     473           0 : }
     474             : 
     475           0 : void DynamicsCompressorKernel::reset()
     476             : {
     477           0 :     m_detectorAverage = 0;
     478           0 :     m_compressorGain = 1;
     479           0 :     m_meteringGain = 1;
     480             : 
     481             :     // Predelay section.
     482           0 :     for (unsigned i = 0; i < m_preDelayBuffers.Length(); ++i)
     483           0 :         memset(m_preDelayBuffers[i].get(), 0, sizeof(float) * MaxPreDelayFrames);
     484             : 
     485           0 :     m_preDelayReadIndex = 0;
     486           0 :     m_preDelayWriteIndex = DefaultPreDelayFrames;
     487             : 
     488           0 :     m_maxAttackCompressionDiffDb = -1; // uninitialized state
     489           0 : }
     490             : 
     491             : } // namespace WebCore

Generated by: LCOV version 1.13