16cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi/*
26cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * Copyright (C) 2013 The Android Open Source Project
36cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *
46cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
56cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * you may not use this file except in compliance with the License.
66cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * You may obtain a copy of the License at
76cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *
86cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
96cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *
106cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
116cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
126cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * See the License for the specific language governing permissions and
146cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * limitations under the License.
156cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi */
166cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#ifndef LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#define LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "common/core/types.h"
206cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "common/core/math.h"
216cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "dsp/core/basic.h"
226cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "dsp/core/interpolation.h"
236cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
246cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//#define LOG_NDEBUG 0
256cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <cutils/log.h>
266cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
276cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
286cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivinamespace le_fx {
296cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
306cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// An adaptive dynamic range compression algorithm. The gain adaptation is made
316cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// at the logarithmic domain and it is based on a Branching-Smooth compensated
326cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// digital peak detector with different time constants for attack and release.
336cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviclass AdaptiveDynamicRangeCompression {
346cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi public:
356cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    AdaptiveDynamicRangeCompression();
366cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
376cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // Initializes the compressor using prior information. It assumes that the
386cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // input signal is speech from high-quality recordings that is scaled and then
396cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // fed to the compressor. The compressor is tuned according to the target gain
406cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // that is expected to be applied.
416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    //
426cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // Target gain receives values between 0.0 and 10.0. The knee threshold is
436cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // reduced as the target gain increases in order to fit the increased range of
446cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // values.
456cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    //
466cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // Values between 1.0 and 2.0 will only mildly affect your signal. Higher
476cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // values will reduce the dynamic range of the signal to the benefit of
486cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // increased loudness.
496cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    //
506cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // If nothing is known regarding the input, a `target_gain` of 1.0f is a
516cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // relatively safe choice for many signals.
526cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    bool Initialize(float target_gain, float sampling_rate);
536cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
546cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // A fast version of the algorithm that uses approximate computations for the
556cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // log(.) and exp(.).
566cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float Compress(float x);
576cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
58cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi  // Stereo channel version of the compressor
59cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi  void Compress(float *x1, float *x2);
60cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi
616cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // This version is slower than Compress(.) but faster than CompressSlow(.)
626cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float CompressNormalSpeed(float x);
636cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
646cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // A slow version of the algorithm that is easier for further developement,
656cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // tuning and debugging
666cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float CompressSlow(float x);
676cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
686cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // Sets knee threshold (in decibel).
696cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  void set_knee_threshold(float decibel);
706cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
716cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // Sets knee threshold via the target gain using an experimentally derived
726cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // relationship.
736cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  void set_knee_threshold_via_target_gain(float target_gain);
746cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
756cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi private:
766cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // The minimum accepted absolute input value and it's natural logarithm. This
776cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // is to prevent numerical issues when the input is close to zero
786cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kMinAbsValue;
796cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kMinLogAbsValue;
806cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // Fixed-point arithmetic limits
816cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kFixedPointLimit;
826cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kInverseFixedPointLimit;
836cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // The default knee threshold in decibel. The knee threshold defines when the
846cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // compressor is actually starting to compress the value of the input samples
856cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kDefaultKneeThresholdInDecibel;
866cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // The compression ratio is the reciprocal of the slope of the line segment
876cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // above the threshold (in the log-domain). The ratio controls the
886cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // effectiveness of the compression.
896cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kCompressionRatio;
906cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // The attack time of the envelope detector
916cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kTauAttack;
926cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // The release time of the envelope detector
936cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  static const float kTauRelease;
946cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
956cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float sampling_rate_;
966cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // the internal state of the envelope detector
976cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float state_;
986cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // the latest gain factor that was applied to the input signal
996cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float compressor_gain_;
1006cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // attack constant for exponential dumping
1016cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float alpha_attack_;
1026cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // release constant for exponential dumping
1036cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float alpha_release_;
1046cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float slope_;
1056cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // The knee threshold
1066cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float knee_threshold_;
1076cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  float knee_threshold_in_decibel_;
1086cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // This interpolator provides the function that relates target gain to knee
1096cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  // threshold.
1106cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  sigmod::InterpolatorLinear<float> target_gain_to_knee_threshold_;
1116cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1126cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi  LE_FX_DISALLOW_COPY_AND_ASSIGN(AdaptiveDynamicRangeCompression);
1136cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi};
1146cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1156cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}  // namespace le_fx
1166cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "dsp/core/dynamic_range_compression-inl.h"
1186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#endif  // LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
120