3e943d120757aa7e9ff16eb54507bcad55c438b1
[WebKit-https.git] / Source / WebCore / platform / audio / DynamicsCompressorKernel.cpp
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 "config.h"
30
31 #if ENABLE(WEB_AUDIO)
32
33 #include "DynamicsCompressorKernel.h"
34
35 #include "AudioUtilities.h"
36 #include "DenormalDisabler.h"
37 #include <algorithm>
38 #include <wtf/MathExtras.h>
39
40 using namespace std;
41
42 namespace WebCore {
43
44 using namespace AudioUtilities;
45
46 // Metering hits peaks instantly, but releases this fast (in seconds).
47 const float meteringReleaseTimeConstant = 0.325f;
48     
49 // Exponential saturation curve.
50 static float saturate(float x, float k)
51 {
52     return 1 - exp(-k * x);
53 }
54
55 DynamicsCompressorKernel::DynamicsCompressorKernel(float sampleRate, unsigned numberOfChannels)
56     : m_sampleRate(sampleRate)
57     , m_lastPreDelayFrames(DefaultPreDelayFrames)
58     , m_preDelayReadIndex(0)
59     , m_preDelayWriteIndex(DefaultPreDelayFrames)
60 {
61     setNumberOfChannels(numberOfChannels);
62
63     // Initializes most member variables
64     reset();
65     
66     m_meteringReleaseK = discreteTimeConstantForSampleRate(meteringReleaseTimeConstant, sampleRate);
67 }
68
69 void DynamicsCompressorKernel::setNumberOfChannels(unsigned numberOfChannels)
70 {
71     if (m_preDelayBuffers.size() == numberOfChannels)
72         return;
73
74     m_preDelayBuffers.clear();
75     for (unsigned i = 0; i < numberOfChannels; ++i)
76         m_preDelayBuffers.append(adoptPtr(new AudioFloatArray(MaxPreDelayFrames)));
77 }
78
79 void DynamicsCompressorKernel::setPreDelayTime(float preDelayTime)
80 {
81     // Re-configure look-ahead section pre-delay if delay time has changed.
82     unsigned preDelayFrames = preDelayTime * sampleRate();
83     if (preDelayFrames > MaxPreDelayFrames - 1)
84         preDelayFrames = MaxPreDelayFrames - 1;
85         
86     if (m_lastPreDelayFrames != preDelayFrames) {
87         m_lastPreDelayFrames = preDelayFrames;
88         for (unsigned i = 0; i < m_preDelayBuffers.size(); ++i)
89             m_preDelayBuffers[i]->zero();
90
91         m_preDelayReadIndex = 0;
92         m_preDelayWriteIndex = preDelayFrames;
93     }
94 }
95
96 void DynamicsCompressorKernel::process(float* sourceChannels[],
97                                        float* destinationChannels[],
98                                        unsigned numberOfChannels,
99                                        unsigned framesToProcess,
100
101                                        float dbThreshold,
102                                        float dbHeadroom,
103                                        float attackTime,
104                                        float releaseTime,
105                                        float preDelayTime,
106                                        float dbPostGain,
107                                        float effectBlend, /* equal power crossfade */
108
109                                        float releaseZone1,
110                                        float releaseZone2,
111                                        float releaseZone3,
112                                        float releaseZone4
113                                        )
114 {
115     ASSERT(m_preDelayBuffers.size() == numberOfChannels);
116
117     float sampleRate = this->sampleRate();
118
119     float dryMix = 1 - effectBlend;
120     float wetMix = effectBlend;
121
122     // Threshold and headroom.
123     float linearThreshold = decibelsToLinear(dbThreshold);
124     float linearHeadroom = decibelsToLinear(dbHeadroom);
125
126     // Makeup gain.
127     float maximum = 1.05f * linearHeadroom * linearThreshold;
128     float kk = (maximum - linearThreshold);
129     float inverseKK = 1 / kk;
130
131     float fullRangeGain = (linearThreshold + kk * saturate(1 - linearThreshold, 1));
132     float fullRangeMakeupGain = 1 / fullRangeGain;
133     // Empirical/perceptual tuning.
134     fullRangeMakeupGain = powf(fullRangeMakeupGain, 0.6f);
135
136     float masterLinearGain = decibelsToLinear(dbPostGain) * fullRangeMakeupGain;
137
138     // Attack parameters.
139     attackTime = max(0.001f, attackTime);
140     float attackFrames = attackTime * sampleRate;
141
142     // Release parameters.
143     float releaseFrames = sampleRate * releaseTime;
144     
145     // Detector release time.
146     float satReleaseTime = 0.0025f;
147     float satReleaseFrames = satReleaseTime * sampleRate;
148
149     // Create a smooth function which passes through four points.
150
151     // Polynomial of the form
152     // y = a + b*x + c*x^2 + d*x^3 + e*x^4;
153
154     float y1 = releaseFrames * releaseZone1;
155     float y2 = releaseFrames * releaseZone2;
156     float y3 = releaseFrames * releaseZone3;
157     float y4 = releaseFrames * releaseZone4;
158
159     // All of these coefficients were derived for 4th order polynomial curve fitting where the y values
160     // match the evenly spaced x values as follows: (y1 : x == 0, y2 : x == 1, y3 : x == 2, y4 : x == 3)
161     float kA = 0.9999999999999998f*y1 + 1.8432219684323923e-16f*y2 - 1.9373394351676423e-16f*y3 + 8.824516011816245e-18f*y4;
162     float kB = -1.5788320352845888f*y1 + 2.3305837032074286f*y2 - 0.9141194204840429f*y3 + 0.1623677525612032f*y4;
163     float kC = 0.5334142869106424f*y1 - 1.272736789213631f*y2 + 0.9258856042207512f*y3 - 0.18656310191776226f*y4;
164     float kD = 0.08783463138207234f*y1 - 0.1694162967925622f*y2 + 0.08588057951595272f*y3 - 0.00429891410546283f*y4;
165     float kE = -0.042416883008123074f*y1 + 0.1115693827987602f*y2 - 0.09764676325265872f*y3 + 0.028494263462021576f*y4;
166
167     // x ranges from 0 -> 3       0    1    2   3
168     //                           -15  -10  -5   0db
169
170     // y calculates adaptive release frames depending on the amount of compression.
171
172     setPreDelayTime(preDelayTime);
173     
174     const int nDivisionFrames = 32;
175
176     const int nDivisions = framesToProcess / nDivisionFrames;
177
178     unsigned frameIndex = 0;
179     for (int i = 0; i < nDivisions; ++i) {
180         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
181         // Calculate desired gain
182         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
183
184         // Fix gremlins.
185         if (isnan(m_detectorAverage))
186             m_detectorAverage = 1;
187         if (isinf(m_detectorAverage))
188             m_detectorAverage = 1;
189
190         float desiredGain = m_detectorAverage;
191
192         // Pre-warp so we get desiredGain after sin() warp below.
193         float scaledDesiredGain = asinf(desiredGain) / (0.5f * piFloat);
194
195         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196         // Deal with envelopes
197         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
198
199         // envelopeRate is the rate we slew from current compressor level to the desired level.
200         // The exact rate depends on if we're attacking or releasing and by how much.
201         float envelopeRate;
202
203         bool isReleasing = scaledDesiredGain > m_compressorGain;
204
205         // compressionDiffDb is the difference between current compression level and the desired level.
206         float compressionDiffDb = linearToDecibels(m_compressorGain / scaledDesiredGain);
207
208         if (isReleasing) {
209             // Release mode - compressionDiffDb should be negative dB
210             m_maxAttackCompressionDiffDb = -1;
211
212             // Fix gremlins.
213             if (isnan(compressionDiffDb))
214                 compressionDiffDb = -1;
215             if (isinf(compressionDiffDb))
216                 compressionDiffDb = -1;
217
218             // Adaptive release - higher compression (lower compressionDiffDb)  releases faster.
219
220             // Contain within range: -12 -> 0 then scale to go from 0 -> 3
221             float x = compressionDiffDb;
222             x = max(-12.0f, x);
223             x = min(0.0f, x);
224             x = 0.25f * (x + 12);
225
226             // Compute adaptive release curve using 4th order polynomial.
227             // Normal values for the polynomial coefficients would create a monotonically increasing function.
228             float x2 = x * x;
229             float x3 = x2 * x;
230             float x4 = x2 * x2;
231             float releaseFrames = kA + kB * x + kC * x2 + kD * x3 + kE * x4;
232
233 #define kSpacingDb 5
234             float dbPerFrame = kSpacingDb / releaseFrames;
235
236             envelopeRate = decibelsToLinear(dbPerFrame);
237         } else {
238             // Attack mode - compressionDiffDb should be positive dB
239
240             // Fix gremlins.
241             if (isnan(compressionDiffDb))
242                 compressionDiffDb = 1;
243             if (isinf(compressionDiffDb))
244                 compressionDiffDb = 1;
245
246             // As long as we're still in attack mode, use a rate based off
247             // the largest compressionDiffDb we've encountered so far.
248             if (m_maxAttackCompressionDiffDb == -1 || m_maxAttackCompressionDiffDb < compressionDiffDb)
249                 m_maxAttackCompressionDiffDb = compressionDiffDb;
250
251             float effAttenDiffDb = max(0.5f, m_maxAttackCompressionDiffDb);
252
253             float x = 0.25f / effAttenDiffDb;
254             envelopeRate = 1 - powf(x, 1 / attackFrames);
255         }
256
257         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
258         // Inner loop - calculate shaped power average - apply compression.
259         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
260
261         {
262             int preDelayReadIndex = m_preDelayReadIndex;
263             int preDelayWriteIndex = m_preDelayWriteIndex;
264             float detectorAverage = m_detectorAverage;
265             float compressorGain = m_compressorGain;
266
267             int loopFrames = nDivisionFrames;
268             while (loopFrames--) {
269                 float compressorInput = 0;
270
271                 // Predelay signal, computing compression amount from un-delayed version.
272                 for (unsigned i = 0; i < numberOfChannels; ++i) {
273                     float* delayBuffer = m_preDelayBuffers[i]->data();
274                     float undelayedSource = sourceChannels[i][frameIndex];
275                     delayBuffer[preDelayWriteIndex] = undelayedSource;
276
277                     float absUndelayedSource = undelayedSource > 0 ? undelayedSource : -undelayedSource;
278                     if (compressorInput < absUndelayedSource)
279                         compressorInput = absUndelayedSource;
280                 }
281
282                 // Calculate shaped power on undelayed input.
283
284                 float scaledInput = compressorInput;
285                 float absInput = scaledInput > 0 ? scaledInput : -scaledInput;
286
287                 // Put through shaping curve.
288                 // This is linear up to the threshold, then exponentially approaches the maximum (headroom amount above threshold).
289                 // The transition from the threshold to the exponential portion is smooth (1st derivative matched).
290                 float shapedInput = absInput < linearThreshold ? absInput : linearThreshold + kk * saturate(absInput - linearThreshold, inverseKK);
291
292                 float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absInput;
293
294                 float attenuationDb = -linearToDecibels(attenuation);
295                 attenuationDb = max(2.0f, attenuationDb);
296
297                 float dbPerFrame = attenuationDb / satReleaseFrames;
298
299                 float satReleaseRate = decibelsToLinear(dbPerFrame) - 1;
300
301                 bool isRelease = (attenuation > detectorAverage);
302                 float rate = isRelease ? satReleaseRate : 1;
303
304                 detectorAverage += (attenuation - detectorAverage) * rate;
305                 detectorAverage = min(1.0f, detectorAverage);
306
307                 // Fix gremlins.
308                 if (isnan(detectorAverage))
309                     detectorAverage = 1;
310                 if (isinf(detectorAverage))
311                     detectorAverage = 1;
312
313                 // Exponential approach to desired gain.
314                 if (envelopeRate < 1) {
315                     // Attack - reduce gain to desired.
316                     compressorGain += (scaledDesiredGain - compressorGain) * envelopeRate;
317                 } else {
318                     // Release - exponentially increase gain to 1.0
319                     compressorGain *= envelopeRate;
320                     compressorGain = min(1.0f, compressorGain);
321                 }
322
323                 // Warp pre-compression gain to smooth out sharp exponential transition points.
324                 float postWarpCompressorGain = sinf(0.5f * piFloat * compressorGain);
325
326                 // Calculate total gain using master gain and effect blend.
327                 float totalGain = dryMix + wetMix * masterLinearGain * postWarpCompressorGain;
328
329                 // Calculate metering.
330                 float dbRealGain = 20 * log10(postWarpCompressorGain);
331                 if (dbRealGain < m_meteringGain)
332                     m_meteringGain = dbRealGain;
333                 else
334                     m_meteringGain += (dbRealGain - m_meteringGain) * m_meteringReleaseK;
335
336                 // Apply final gain.
337                 for (unsigned i = 0; i < numberOfChannels; ++i) {
338                     float* delayBuffer = m_preDelayBuffers[i]->data();
339                     destinationChannels[i][frameIndex] = delayBuffer[preDelayReadIndex] * totalGain;
340                 }
341
342                 frameIndex++;
343                 preDelayReadIndex = (preDelayReadIndex + 1) & MaxPreDelayFramesMask;
344                 preDelayWriteIndex = (preDelayWriteIndex + 1) & MaxPreDelayFramesMask;
345             }
346
347             // Locals back to member variables.
348             m_preDelayReadIndex = preDelayReadIndex;
349             m_preDelayWriteIndex = preDelayWriteIndex;
350             m_detectorAverage = DenormalDisabler::flushDenormalFloatToZero(detectorAverage);
351             m_compressorGain = DenormalDisabler::flushDenormalFloatToZero(compressorGain);
352         }
353     }
354 }
355
356 void DynamicsCompressorKernel::reset()
357 {
358     m_detectorAverage = 0;
359     m_compressorGain = 1;
360     m_meteringGain = 1;
361
362     // Predelay section.
363     for (unsigned i = 0; i < m_preDelayBuffers.size(); ++i)
364         m_preDelayBuffers[i]->zero();
365
366     m_preDelayReadIndex = 0;
367     m_preDelayWriteIndex = DefaultPreDelayFrames;
368
369     m_maxAttackCompressionDiffDb = -1; // uninitialized state
370 }
371
372 } // namespace WebCore
373
374 #endif // ENABLE(WEB_AUDIO)