Home | History | Annotate | Download | only in core
      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