diff options
Diffstat (limited to 'media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp')
-rw-r--r-- | media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp new file mode 100644 index 0000000..2bbd043 --- /dev/null +++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cmath> + +#include "common/core/math.h" +#include "common/core/types.h" +#include "dsp/core/basic.h" +#include "dsp/core/interpolation.h" +#include "dsp/core/dynamic_range_compression.h" + +//#define LOG_NDEBUG 0 +#include <cutils/log.h> + + +namespace le_fx { + +// Definitions for static const class members declared in +// dynamic_range_compression.h. +const float AdaptiveDynamicRangeCompression::kMinAbsValue = 0.000001f; +const float AdaptiveDynamicRangeCompression::kMinLogAbsValue = + 0.032766999999999997517097227728299912996590137481689453125f; +const float AdaptiveDynamicRangeCompression::kFixedPointLimit = 32767.0f; +const float AdaptiveDynamicRangeCompression::kInverseFixedPointLimit = + 1.0f / AdaptiveDynamicRangeCompression::kFixedPointLimit; +const float AdaptiveDynamicRangeCompression::kDefaultKneeThresholdInDecibel = + -8.0f; +const float AdaptiveDynamicRangeCompression::kCompressionRatio = 7.0f; +const float AdaptiveDynamicRangeCompression::kTauAttack = 0.001f; +const float AdaptiveDynamicRangeCompression::kTauRelease = 0.015f; + +AdaptiveDynamicRangeCompression::AdaptiveDynamicRangeCompression() { + static const float kTargetGain[] = { + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + static const float kKneeThreshold[] = { + -8.0f, -8.0f, -8.5f, -9.0f, -10.0f }; + target_gain_to_knee_threshold_.Initialize( + &kTargetGain[0], &kKneeThreshold[0], + sizeof(kTargetGain) / sizeof(kTargetGain[0])); +} + +bool AdaptiveDynamicRangeCompression::Initialize( + float target_gain, float sampling_rate) { + set_knee_threshold_via_target_gain(target_gain); + sampling_rate_ = sampling_rate; + state_ = 0.0f; + compressor_gain_ = 1.0f; + if (kTauAttack > 0.0f) { + const float taufs = kTauAttack * sampling_rate_; + alpha_attack_ = std::exp(-1.0f / taufs); + } else { + alpha_attack_ = 0.0f; + } + if (kTauRelease > 0.0f) { + const float taufs = kTauRelease * sampling_rate_; + alpha_release_ = std::exp(-1.0f / taufs); + } else { + alpha_release_ = 0.0f; + } + // Feed-forward topology + slope_ = 1.0f / kCompressionRatio - 1.0f; + return true; +} + +float AdaptiveDynamicRangeCompression::Compress(float x) { + const float max_abs_x = std::max(std::fabs(x), kMinLogAbsValue); + const float max_abs_x_dB = math::fast_log(max_abs_x); + // Subtract Threshold from log-encoded input to get the amount of overshoot + const float overshoot = max_abs_x_dB - knee_threshold_; + // Hard half-wave rectifier + const float rect = std::max(overshoot, 0.0f); + // Multiply rectified overshoot with slope + const float cv = rect * slope_; + const float prev_state = state_; + if (cv <= state_) { + state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv; + } else { + state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv; + } + compressor_gain_ *= + math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state); + x *= compressor_gain_; + if (x > kFixedPointLimit) { + return kFixedPointLimit; + } + if (x < -kFixedPointLimit) { + return -kFixedPointLimit; + } + return x; +} + +} // namespace le_fx + |