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 176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <cmath> 186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "common/core/math.h" 206cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "common/core/types.h" 216cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "dsp/core/basic.h" 226cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "dsp/core/interpolation.h" 236cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "dsp/core/dynamic_range_compression.h" 246cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 256cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//#define LOG_NDEBUG 0 266cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <cutils/log.h> 276cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 286cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 296cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivinamespace le_fx { 306cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 316cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Definitions for static const class members declared in 326cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// dynamic_range_compression.h. 336cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kMinAbsValue = 0.000001f; 346cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kMinLogAbsValue = 356cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 0.032766999999999997517097227728299912996590137481689453125f; 366cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kFixedPointLimit = 32767.0f; 376cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kInverseFixedPointLimit = 386cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 1.0f / AdaptiveDynamicRangeCompression::kFixedPointLimit; 396cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kDefaultKneeThresholdInDecibel = 406cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi -8.0f; 416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kCompressionRatio = 7.0f; 426cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kTauAttack = 0.001f; 436cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst float AdaptiveDynamicRangeCompression::kTauRelease = 0.015f; 446cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 456cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel TriviAdaptiveDynamicRangeCompression::AdaptiveDynamicRangeCompression() { 466cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi static const float kTargetGain[] = { 476cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; 486cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi static const float kKneeThreshold[] = { 496cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi -8.0f, -8.0f, -8.5f, -9.0f, -10.0f }; 506cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi target_gain_to_knee_threshold_.Initialize( 516cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi &kTargetGain[0], &kKneeThreshold[0], 526cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi sizeof(kTargetGain) / sizeof(kTargetGain[0])); 536cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi} 546cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 556cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivibool AdaptiveDynamicRangeCompression::Initialize( 566cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi float target_gain, float sampling_rate) { 576cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi set_knee_threshold_via_target_gain(target_gain); 586cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi sampling_rate_ = sampling_rate; 596cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi state_ = 0.0f; 606cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi compressor_gain_ = 1.0f; 616cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi if (kTauAttack > 0.0f) { 626cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float taufs = kTauAttack * sampling_rate_; 636cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi alpha_attack_ = std::exp(-1.0f / taufs); 646cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } else { 656cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi alpha_attack_ = 0.0f; 666cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } 676cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi if (kTauRelease > 0.0f) { 686cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float taufs = kTauRelease * sampling_rate_; 696cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi alpha_release_ = std::exp(-1.0f / taufs); 706cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } else { 716cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi alpha_release_ = 0.0f; 726cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } 736cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi // Feed-forward topology 746cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi slope_ = 1.0f / kCompressionRatio - 1.0f; 756cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi return true; 766cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi} 776cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 786cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivifloat AdaptiveDynamicRangeCompression::Compress(float x) { 796cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float max_abs_x = std::max(std::fabs(x), kMinLogAbsValue); 806cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float max_abs_x_dB = math::fast_log(max_abs_x); 816cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi // Subtract Threshold from log-encoded input to get the amount of overshoot 826cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float overshoot = max_abs_x_dB - knee_threshold_; 836cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi // Hard half-wave rectifier 846cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float rect = std::max(overshoot, 0.0f); 856cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi // Multiply rectified overshoot with slope 866cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float cv = rect * slope_; 876cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi const float prev_state = state_; 886cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi if (cv <= state_) { 896cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv; 906cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } else { 916cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv; 926cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } 936cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi compressor_gain_ *= 946cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state); 956cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi x *= compressor_gain_; 966cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi if (x > kFixedPointLimit) { 976cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi return kFixedPointLimit; 986cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } 996cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi if (x < -kFixedPointLimit) { 1006cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi return -kFixedPointLimit; 1016cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi } 1026cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi return x; 1036cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi} 1046cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 105cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivivoid AdaptiveDynamicRangeCompression::Compress(float *x1, float *x2) { 106cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi // Taking the maximum amplitude of both channels 107cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi const float max_abs_x = std::max(std::fabs(*x1), 108cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi std::max(std::fabs(*x2), kMinLogAbsValue)); 109cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi const float max_abs_x_dB = math::fast_log(max_abs_x); 110cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi // Subtract Threshold from log-encoded input to get the amount of overshoot 111cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi const float overshoot = max_abs_x_dB - knee_threshold_; 112cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi // Hard half-wave rectifier 113cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi const float rect = std::max(overshoot, 0.0f); 114cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi // Multiply rectified overshoot with slope 115cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi const float cv = rect * slope_; 116cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi const float prev_state = state_; 117cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi if (cv <= state_) { 118cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv; 119cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi } else { 120cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv; 121cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi } 122cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi compressor_gain_ *= 123cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state); 124cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi *x1 *= compressor_gain_; 125cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi if (*x1 > kFixedPointLimit) { 126cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi *x1 = kFixedPointLimit; 127cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi } 128cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi if (*x1 < -kFixedPointLimit) { 129cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi *x1 = -kFixedPointLimit; 130cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi } 131cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi *x2 *= compressor_gain_; 132cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi if (*x2 > kFixedPointLimit) { 133cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi *x2 = kFixedPointLimit; 134cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi } 135cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi if (*x2 < -kFixedPointLimit) { 136cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi *x2 = -kFixedPointLimit; 137cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi } 138cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi} 139cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi 1406cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi} // namespace le_fx 1416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi 142