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