• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 blink {
40 
41 using namespace AudioUtilities;
42 
DynamicsCompressor(float sampleRate,unsigned numberOfChannels)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 
setParameterValue(unsigned parameterID,float value)57 void DynamicsCompressor::setParameterValue(unsigned parameterID, float value)
58 {
59     ASSERT(parameterID < ParamLast);
60     if (parameterID < ParamLast)
61         m_parameters[parameterID] = value;
62 }
63 
initializeParameters()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 
parameterValue(unsigned parameterID)92 float DynamicsCompressor::parameterValue(unsigned parameterID)
93 {
94     ASSERT(parameterID < ParamLast);
95     return m_parameters[parameterID];
96 }
97 
process(const AudioBus * sourceBus,AudioBus * destinationBus,unsigned framesToProcess)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 
reset()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 
setNumberOfChannels(unsigned numberOfChannels)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 blink
211 
212 #endif // ENABLE(WEB_AUDIO)
213