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