1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
17 #define LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
18 
19 //#define LOG_NDEBUG 0
20 
21 #include "common/core/types.h"
22 #include "common/core/math.h"
23 #include "dsp/core/basic.h"
24 #include "dsp/core/interpolation.h"
25 
26 #include <android/log.h>
27 
28 namespace le_fx {
29 
30 // An adaptive dynamic range compression algorithm. The gain adaptation is made
31 // at the logarithmic domain and it is based on a Branching-Smooth compensated
32 // digital peak detector with different time constants for attack and release.
33 class AdaptiveDynamicRangeCompression {
34  public:
35     AdaptiveDynamicRangeCompression();
36 
37     // Initializes the compressor using prior information. It assumes that the
38     // input signal is speech from high-quality recordings that is scaled and then
39     // fed to the compressor. The compressor is tuned according to the target gain
40     // that is expected to be applied.
41     //
42     // Target gain receives values between 0.0 and 10.0. The knee threshold is
43     // reduced as the target gain increases in order to fit the increased range of
44     // values.
45     //
46     // Values between 1.0 and 2.0 will only mildly affect your signal. Higher
47     // values will reduce the dynamic range of the signal to the benefit of
48     // increased loudness.
49     //
50     // If nothing is known regarding the input, a `target_gain` of 1.0f is a
51     // relatively safe choice for many signals.
52     bool Initialize(float target_gain, float sampling_rate);
53 
54   // A fast version of the algorithm that uses approximate computations for the
55   // log(.) and exp(.).
56   float Compress(float x);
57 
58   // Stereo channel version of the compressor
59   void Compress(float *x1, float *x2);
60 
61   // This version is slower than Compress(.) but faster than CompressSlow(.)
62   float CompressNormalSpeed(float x);
63 
64   // A slow version of the algorithm that is easier for further developement,
65   // tuning and debugging
66   float CompressSlow(float x);
67 
68   // Sets knee threshold (in decibel).
69   void set_knee_threshold(float decibel);
70 
71   // Sets knee threshold via the target gain using an experimentally derived
72   // relationship.
73   void set_knee_threshold_via_target_gain(float target_gain);
74 
75  private:
76   // The minimum accepted absolute input value and it's natural logarithm. This
77   // is to prevent numerical issues when the input is close to zero
78   static const float kMinAbsValue;
79   static const float kMinLogAbsValue;
80   // Fixed-point arithmetic limits
81   static const float kFixedPointLimit;
82   static const float kInverseFixedPointLimit;
83   // The default knee threshold in decibel. The knee threshold defines when the
84   // compressor is actually starting to compress the value of the input samples
85   static const float kDefaultKneeThresholdInDecibel;
86   // The compression ratio is the reciprocal of the slope of the line segment
87   // above the threshold (in the log-domain). The ratio controls the
88   // effectiveness of the compression.
89   static const float kCompressionRatio;
90   // The attack time of the envelope detector
91   static const float kTauAttack;
92   // The release time of the envelope detector
93   static const float kTauRelease;
94 
95   float sampling_rate_;
96   // the internal state of the envelope detector
97   float state_;
98   // the latest gain factor that was applied to the input signal
99   float compressor_gain_;
100   // attack constant for exponential dumping
101   float alpha_attack_;
102   // release constant for exponential dumping
103   float alpha_release_;
104   float slope_;
105   // The knee threshold
106   float knee_threshold_;
107   float knee_threshold_in_decibel_;
108   // This interpolator provides the function that relates target gain to knee
109   // threshold.
110   sigmod::InterpolatorLinear<float> target_gain_to_knee_threshold_;
111 
112   LE_FX_DISALLOW_COPY_AND_ASSIGN(AdaptiveDynamicRangeCompression);
113 };
114 
115 }  // namespace le_fx
116 
117 #include "dsp/core/dynamic_range_compression-inl.h"
118 
119 #endif  // LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
120