2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
33 #include "DynamicsCompressor.h"
36 #include "AudioUtilities.h"
37 #include <wtf/MathExtras.h>
41 using namespace AudioUtilities;
43 DynamicsCompressor::DynamicsCompressor(bool isStereo, double sampleRate)
44 : m_isStereo(isStereo)
45 , m_sampleRate(sampleRate)
46 , m_compressor(sampleRate)
48 // Uninitialized state - for parameter recalculation.
49 m_lastFilterStageRatio = -1;
51 m_lastFilterStageGain = -1;
53 initializeParameters();
56 void DynamicsCompressor::initializeParameters()
58 // Initializes compressor to default values.
60 m_parameters[ParamThreshold] = -24; // dB
61 m_parameters[ParamHeadroom] = 21; // dB
62 m_parameters[ParamAttack] = 0.003; // seconds
63 m_parameters[ParamRelease] = 0.250; // seconds
64 m_parameters[ParamPreDelay] = 0.006; // seconds
66 // Release zone values 0 -> 1.
67 m_parameters[ParamReleaseZone1] = 0.09;
68 m_parameters[ParamReleaseZone2] = 0.16;
69 m_parameters[ParamReleaseZone3] = 0.42;
70 m_parameters[ParamReleaseZone4] = 0.98;
72 m_parameters[ParamFilterStageGain] = 4.4; // dB
73 m_parameters[ParamFilterStageRatio] = 2;
74 m_parameters[ParamFilterAnchor] = 15000 / nyquist();
76 m_parameters[ParamPostGain] = 0; // dB
78 // Linear crossfade (0 -> 1).
79 m_parameters[ParamEffectBlend] = 1;
82 double DynamicsCompressor::parameterValue(unsigned parameterID)
84 ASSERT(parameterID < ParamLast);
85 return m_parameters[parameterID];
88 void DynamicsCompressor::setEmphasisStageParameters(unsigned stageIndex, float gain, float normalizedFrequency /* 0 -> 1 */)
90 float gk = 1 - gain / 20;
91 float f1 = normalizedFrequency * gk;
92 float f2 = normalizedFrequency / gk;
93 float r1 = exp(-f1 * piDouble);
94 float r2 = exp(-f2 * piDouble);
96 // Set pre-filter zero and pole to create an emphasis filter.
97 m_preFilter[stageIndex].setZero(r1);
98 m_preFilter[stageIndex].setPole(r2);
99 m_preFilterR[stageIndex].setZero(r1);
100 m_preFilterR[stageIndex].setPole(r2);
102 // Set post-filter with zero and pole reversed to create the de-emphasis filter.
103 // If there were no compressor kernel in between, they would cancel each other out (allpass filter).
104 m_postFilter[stageIndex].setZero(r2);
105 m_postFilter[stageIndex].setPole(r1);
106 m_postFilterR[stageIndex].setZero(r2);
107 m_postFilterR[stageIndex].setPole(r1);
110 void DynamicsCompressor::setEmphasisParameters(float gain, float anchorFreq, float filterStageRatio)
112 setEmphasisStageParameters(0, gain, anchorFreq);
113 setEmphasisStageParameters(1, gain, anchorFreq / filterStageRatio);
114 setEmphasisStageParameters(2, gain, anchorFreq / (filterStageRatio * filterStageRatio));
115 setEmphasisStageParameters(3, gain, anchorFreq / (filterStageRatio * filterStageRatio * filterStageRatio));
118 void DynamicsCompressor::process(AudioBus* sourceBus, AudioBus* destinationBus, unsigned framesToProcess)
120 float* sourceL = sourceBus->channel(0)->data();
123 if (sourceBus->numberOfChannels() > 1)
124 sourceR = sourceBus->channel(1)->data();
128 ASSERT(destinationBus->numberOfChannels() == 2);
130 float* destinationL = destinationBus->channel(0)->data();
131 float* destinationR = destinationBus->channel(1)->data();
133 float filterStageGain = parameterValue(ParamFilterStageGain);
134 float filterStageRatio = parameterValue(ParamFilterStageRatio);
135 float anchor = parameterValue(ParamFilterAnchor);
137 if (filterStageGain != m_lastFilterStageGain || filterStageRatio != m_lastFilterStageRatio || anchor != m_lastAnchor) {
138 m_lastFilterStageGain = filterStageGain;
139 m_lastFilterStageRatio = filterStageRatio;
140 m_lastAnchor = anchor;
142 setEmphasisParameters(filterStageGain, anchor, filterStageRatio);
145 // Apply pre-emphasis filter.
146 // Note that the final three stages are computed in-place in the destination buffer.
147 m_preFilter[0].process(sourceL, destinationL, framesToProcess);
148 m_preFilter[1].process(destinationL, destinationL, framesToProcess);
149 m_preFilter[2].process(destinationL, destinationL, framesToProcess);
150 m_preFilter[3].process(destinationL, destinationL, framesToProcess);
153 m_preFilterR[0].process(sourceR, destinationR, framesToProcess);
154 m_preFilterR[1].process(destinationR, destinationR, framesToProcess);
155 m_preFilterR[2].process(destinationR, destinationR, framesToProcess);
156 m_preFilterR[3].process(destinationR, destinationR, framesToProcess);
159 float dbThreshold = parameterValue(ParamThreshold);
160 float dbHeadroom = parameterValue(ParamHeadroom);
161 float attackTime = parameterValue(ParamAttack);
162 float releaseTime = parameterValue(ParamRelease);
163 float preDelayTime = parameterValue(ParamPreDelay);
165 // This is effectively a master volume on the compressed signal (pre-blending).
166 float dbPostGain = parameterValue(ParamPostGain);
168 // Linear blending value from dry to completely processed (0 -> 1)
169 // 0 means the signal is completely unprocessed.
170 // 1 mixes in only the compressed signal.
171 float effectBlend = parameterValue(ParamEffectBlend);
173 double releaseZone1 = parameterValue(ParamReleaseZone1);
174 double releaseZone2 = parameterValue(ParamReleaseZone2);
175 double releaseZone3 = parameterValue(ParamReleaseZone3);
176 double releaseZone4 = parameterValue(ParamReleaseZone4);
178 // Apply compression to the pre-filtered signal.
179 // The processing is performed in place.
180 m_compressor.process(destinationL,
200 // Apply de-emphasis filter.
201 m_postFilter[0].process(destinationL, destinationL, framesToProcess);
202 m_postFilter[1].process(destinationL, destinationL, framesToProcess);
203 m_postFilter[2].process(destinationL, destinationL, framesToProcess);
204 m_postFilter[3].process(destinationL, destinationL, framesToProcess);
207 m_postFilterR[0].process(destinationR, destinationR, framesToProcess);
208 m_postFilterR[1].process(destinationR, destinationR, framesToProcess);
209 m_postFilterR[2].process(destinationR, destinationR, framesToProcess);
210 m_postFilterR[3].process(destinationR, destinationR, framesToProcess);
214 void DynamicsCompressor::reset()
216 m_lastFilterStageRatio = -1; // for recalc
218 m_lastFilterStageGain = -1;
220 for (unsigned i = 0; i < 4; ++i) {
221 m_preFilter[i].reset();
222 m_preFilterR[i].reset();
223 m_postFilter[i].reset();
224 m_postFilterR[i].reset();
227 m_compressor.reset();
230 } // namespace WebCore
232 #endif // ENABLE(WEB_AUDIO)