Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / audio / DynamicsCompressor.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/DynamicsCompressor.h"
34
35 #include "platform/audio/AudioBus.h"
36 #include "platform/audio/AudioUtilities.h"
37 #include "wtf/MathExtras.h"
38
39 namespace WebCore {
40
41 using namespace AudioUtilities;
42
43 DynamicsCompressor::DynamicsCompressor(float sampleRate, unsigned numberOfChannels)
44     : m_numberOfChannels(numberOfChannels)
45     , m_sampleRate(sampleRate)
46     , m_compressor(sampleRate, numberOfChannels)
47 {
48     // Uninitialized state - for parameter recalculation.
49     m_lastFilterStageRatio = -1;
50     m_lastAnchor = -1;
51     m_lastFilterStageGain = -1;
52
53     setNumberOfChannels(numberOfChannels);
54     initializeParameters();
55 }
56
57 void DynamicsCompressor::setParameterValue(unsigned parameterID, float value)
58 {
59     ASSERT(parameterID < ParamLast);
60     if (parameterID < ParamLast)
61         m_parameters[parameterID] = value;
62 }
63
64 void DynamicsCompressor::initializeParameters()
65 {
66     // Initializes compressor to default values.
67
68     m_parameters[ParamThreshold] = -24; // dB
69     m_parameters[ParamKnee] = 30; // dB
70     m_parameters[ParamRatio] = 12; // unit-less
71     m_parameters[ParamAttack] = 0.003f; // seconds
72     m_parameters[ParamRelease] = 0.250f; // seconds
73     m_parameters[ParamPreDelay] = 0.006f; // seconds
74
75     // Release zone values 0 -> 1.
76     m_parameters[ParamReleaseZone1] = 0.09f;
77     m_parameters[ParamReleaseZone2] = 0.16f;
78     m_parameters[ParamReleaseZone3] = 0.42f;
79     m_parameters[ParamReleaseZone4] = 0.98f;
80
81     m_parameters[ParamFilterStageGain] = 4.4f; // dB
82     m_parameters[ParamFilterStageRatio] = 2;
83     m_parameters[ParamFilterAnchor] = 15000 / nyquist();
84
85     m_parameters[ParamPostGain] = 0; // dB
86     m_parameters[ParamReduction] = 0; // dB
87
88     // Linear crossfade (0 -> 1).
89     m_parameters[ParamEffectBlend] = 1;
90 }
91
92 float DynamicsCompressor::parameterValue(unsigned parameterID)
93 {
94     ASSERT(parameterID < ParamLast);
95     return m_parameters[parameterID];
96 }
97
98 void DynamicsCompressor::process(const AudioBus* sourceBus, AudioBus* destinationBus, unsigned framesToProcess)
99 {
100     // Though numberOfChannels is retrived from destinationBus, we still name it numberOfChannels instead of numberOfDestinationChannels.
101     // It's because we internally match sourceChannels's size to destinationBus by channel up/down mix. Thus we need numberOfChannels
102     // to do the loop work for both m_sourceChannels and m_destinationChannels.
103
104     unsigned numberOfChannels = destinationBus->numberOfChannels();
105     unsigned numberOfSourceChannels = sourceBus->numberOfChannels();
106
107     ASSERT(numberOfChannels == m_numberOfChannels && numberOfSourceChannels);
108
109     if (numberOfChannels != m_numberOfChannels || !numberOfSourceChannels) {
110         destinationBus->zero();
111         return;
112     }
113
114     switch (numberOfChannels) {
115     case 2: // stereo
116         m_sourceChannels[0] = sourceBus->channel(0)->data();
117
118         if (numberOfSourceChannels > 1)
119             m_sourceChannels[1] = sourceBus->channel(1)->data();
120         else
121             // Simply duplicate mono channel input data to right channel for stereo processing.
122             m_sourceChannels[1] = m_sourceChannels[0];
123
124         break;
125     default:
126         // FIXME : support other number of channels.
127         ASSERT_NOT_REACHED();
128         destinationBus->zero();
129         return;
130     }
131
132     for (unsigned i = 0; i < numberOfChannels; ++i)
133         m_destinationChannels[i] = destinationBus->channel(i)->mutableData();
134
135     float filterStageGain = parameterValue(ParamFilterStageGain);
136     float filterStageRatio = parameterValue(ParamFilterStageRatio);
137     float anchor = parameterValue(ParamFilterAnchor);
138
139     if (filterStageGain != m_lastFilterStageGain || filterStageRatio != m_lastFilterStageRatio || anchor != m_lastAnchor) {
140         m_lastFilterStageGain = filterStageGain;
141         m_lastFilterStageRatio = filterStageRatio;
142         m_lastAnchor = anchor;
143
144     }
145
146     float dbThreshold = parameterValue(ParamThreshold);
147     float dbKnee = parameterValue(ParamKnee);
148     float ratio = parameterValue(ParamRatio);
149     float attackTime = parameterValue(ParamAttack);
150     float releaseTime = parameterValue(ParamRelease);
151     float preDelayTime = parameterValue(ParamPreDelay);
152
153     // This is effectively a master volume on the compressed signal (pre-blending).
154     float dbPostGain = parameterValue(ParamPostGain);
155
156     // Linear blending value from dry to completely processed (0 -> 1)
157     // 0 means the signal is completely unprocessed.
158     // 1 mixes in only the compressed signal.
159     float effectBlend = parameterValue(ParamEffectBlend);
160
161     float releaseZone1 = parameterValue(ParamReleaseZone1);
162     float releaseZone2 = parameterValue(ParamReleaseZone2);
163     float releaseZone3 = parameterValue(ParamReleaseZone3);
164     float releaseZone4 = parameterValue(ParamReleaseZone4);
165
166     // Apply compression to the source signal.
167     m_compressor.process(m_sourceChannels.get(),
168                          m_destinationChannels.get(),
169                          numberOfChannels,
170                          framesToProcess,
171
172                          dbThreshold,
173                          dbKnee,
174                          ratio,
175                          attackTime,
176                          releaseTime,
177                          preDelayTime,
178                          dbPostGain,
179                          effectBlend,
180
181                          releaseZone1,
182                          releaseZone2,
183                          releaseZone3,
184                          releaseZone4
185                          );
186
187     // Update the compression amount.
188     setParameterValue(ParamReduction, m_compressor.meteringGain());
189
190 }
191
192 void DynamicsCompressor::reset()
193 {
194     m_lastFilterStageRatio = -1; // for recalc
195     m_lastAnchor = -1;
196     m_lastFilterStageGain = -1;
197
198     m_compressor.reset();
199 }
200
201 void DynamicsCompressor::setNumberOfChannels(unsigned numberOfChannels)
202 {
203     m_sourceChannels = adoptArrayPtr(new const float* [numberOfChannels]);
204     m_destinationChannels = adoptArrayPtr(new float* [numberOfChannels]);
205
206     m_compressor.setNumberOfChannels(numberOfChannels);
207     m_numberOfChannels = numberOfChannels;
208 }
209
210 } // namespace WebCore
211
212 #endif // ENABLE(WEB_AUDIO)