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