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//#define LOG_NDEBUG 0 17 18#include <cmath> 19 20#include "common/core/math.h" 21#include "common/core/types.h" 22#include "dsp/core/basic.h" 23#include "dsp/core/interpolation.h" 24#include "dsp/core/dynamic_range_compression.h" 25 26#include <android/log.h> 27 28namespace le_fx { 29 30// Definitions for static const class members declared in 31// dynamic_range_compression.h. 32const float AdaptiveDynamicRangeCompression::kMinAbsValue = 0.000001f; 33const float AdaptiveDynamicRangeCompression::kMinLogAbsValue = 34 0.032766999999999997517097227728299912996590137481689453125f; 35const float AdaptiveDynamicRangeCompression::kFixedPointLimit = 32767.0f; 36const float AdaptiveDynamicRangeCompression::kInverseFixedPointLimit = 37 1.0f / AdaptiveDynamicRangeCompression::kFixedPointLimit; 38const float AdaptiveDynamicRangeCompression::kDefaultKneeThresholdInDecibel = 39 -8.0f; 40const float AdaptiveDynamicRangeCompression::kCompressionRatio = 7.0f; 41const float AdaptiveDynamicRangeCompression::kTauAttack = 0.001f; 42const float AdaptiveDynamicRangeCompression::kTauRelease = 0.015f; 43 44AdaptiveDynamicRangeCompression::AdaptiveDynamicRangeCompression() { 45 static const float kTargetGain[] = { 46 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; 47 static const float kKneeThreshold[] = { 48 -8.0f, -8.0f, -8.5f, -9.0f, -10.0f }; 49 target_gain_to_knee_threshold_.Initialize( 50 &kTargetGain[0], &kKneeThreshold[0], 51 sizeof(kTargetGain) / sizeof(kTargetGain[0])); 52} 53 54bool AdaptiveDynamicRangeCompression::Initialize( 55 float target_gain, float sampling_rate) { 56 set_knee_threshold_via_target_gain(target_gain); 57 sampling_rate_ = sampling_rate; 58 state_ = 0.0f; 59 compressor_gain_ = 1.0f; 60 if (kTauAttack > 0.0f) { 61 const float taufs = kTauAttack * sampling_rate_; 62 alpha_attack_ = std::exp(-1.0f / taufs); 63 } else { 64 alpha_attack_ = 0.0f; 65 } 66 if (kTauRelease > 0.0f) { 67 const float taufs = kTauRelease * sampling_rate_; 68 alpha_release_ = std::exp(-1.0f / taufs); 69 } else { 70 alpha_release_ = 0.0f; 71 } 72 // Feed-forward topology 73 slope_ = 1.0f / kCompressionRatio - 1.0f; 74 return true; 75} 76 77float AdaptiveDynamicRangeCompression::Compress(float x) { 78 const float max_abs_x = std::max(std::fabs(x), kMinLogAbsValue); 79 const float max_abs_x_dB = math::fast_log(max_abs_x); 80 // Subtract Threshold from log-encoded input to get the amount of overshoot 81 const float overshoot = max_abs_x_dB - knee_threshold_; 82 // Hard half-wave rectifier 83 const float rect = std::max(overshoot, 0.0f); 84 // Multiply rectified overshoot with slope 85 const float cv = rect * slope_; 86 const float prev_state = state_; 87 if (cv <= state_) { 88 state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv; 89 } else { 90 state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv; 91 } 92 compressor_gain_ *= 93 math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state); 94 x *= compressor_gain_; 95 if (x > kFixedPointLimit) { 96 return kFixedPointLimit; 97 } 98 if (x < -kFixedPointLimit) { 99 return -kFixedPointLimit; 100 } 101 return x; 102} 103 104void AdaptiveDynamicRangeCompression::Compress(float *x1, float *x2) { 105 // Taking the maximum amplitude of both channels 106 const float max_abs_x = std::max(std::fabs(*x1), 107 std::max(std::fabs(*x2), kMinLogAbsValue)); 108 const float max_abs_x_dB = math::fast_log(max_abs_x); 109 // Subtract Threshold from log-encoded input to get the amount of overshoot 110 const float overshoot = max_abs_x_dB - knee_threshold_; 111 // Hard half-wave rectifier 112 const float rect = std::max(overshoot, 0.0f); 113 // Multiply rectified overshoot with slope 114 const float cv = rect * slope_; 115 const float prev_state = state_; 116 if (cv <= state_) { 117 state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv; 118 } else { 119 state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv; 120 } 121 compressor_gain_ *= 122 math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state); 123 *x1 *= compressor_gain_; 124 if (*x1 > kFixedPointLimit) { 125 *x1 = kFixedPointLimit; 126 } 127 if (*x1 < -kFixedPointLimit) { 128 *x1 = -kFixedPointLimit; 129 } 130 *x2 *= compressor_gain_; 131 if (*x2 > kFixedPointLimit) { 132 *x2 = kFixedPointLimit; 133 } 134 if (*x2 < -kFixedPointLimit) { 135 *x2 = -kFixedPointLimit; 136 } 137} 138 139} // namespace le_fx 140 141