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