summaryrefslogtreecommitdiffstats
path: root/media/libeffects
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2013-09-25 18:43:55 -0700
committerJean-Michel Trivi <jmtrivi@google.com>2013-09-26 12:55:10 -0700
commitcd0c4683947231a7d3dc7811bedb75c5a965103c (patch)
tree3554110faa75566c437e0d4f5bf26cf7b2759f97 /media/libeffects
parentfed6292af65a0b97b583ecbd3c232b3811a3f37b (diff)
downloadframeworks_av-cd0c4683947231a7d3dc7811bedb75c5a965103c.zip
frameworks_av-cd0c4683947231a7d3dc7811bedb75c5a965103c.tar.gz
frameworks_av-cd0c4683947231a7d3dc7811bedb75c5a965103c.tar.bz2
LoudnessEnhancer compatible with stereo imaging
Use a single compressor for both channels. Envelope of signal is determined by looking at both channels. Bug 8413913 Change-Id: Ia9b6f34923d2977c60a3352500b858dfa1fab33c
Diffstat (limited to 'media/libeffects')
-rw-r--r--media/libeffects/loudness/EffectLoudnessEnhancer.cpp42
-rw-r--r--media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h2
-rw-r--r--media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp35
-rw-r--r--media/libeffects/loudness/dsp/core/dynamic_range_compression.h3
4 files changed, 56 insertions, 26 deletions
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
index dfc25db..91ed677 100644
--- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -56,8 +56,7 @@ struct LoudnessEnhancerContext {
int32_t mTargetGainmB;// target gain in mB
// in this implementation, there is no coupling between the compression on the left and right
// channels
- le_fx::AdaptiveDynamicRangeCompression* mCompressorL;
- le_fx::AdaptiveDynamicRangeCompression* mCompressorR;
+ le_fx::AdaptiveDynamicRangeCompression* mCompressor;
};
//
@@ -68,11 +67,10 @@ void LE_reset(LoudnessEnhancerContext *pContext)
{
ALOGV(" > LE_reset(%p)", pContext);
- if ((pContext->mCompressorL != NULL) && (pContext->mCompressorR != NULL)) {
+ if (pContext->mCompressor != NULL) {
float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
- pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
- pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+ pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
} else {
ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext);
}
@@ -176,13 +174,9 @@ int LE_init(LoudnessEnhancerContext *pContext)
float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
- if (pContext->mCompressorL == NULL) {
- pContext->mCompressorL = new le_fx::AdaptiveDynamicRangeCompression();
- pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
- }
- if (pContext->mCompressorR == NULL) {
- pContext->mCompressorR = new le_fx::AdaptiveDynamicRangeCompression();
- pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+ if (pContext->mCompressor == NULL) {
+ pContext->mCompressor = new le_fx::AdaptiveDynamicRangeCompression();
+ pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
}
LE_setConfig(pContext, &pContext->mConfig);
@@ -215,8 +209,7 @@ int LELib_Create(const effect_uuid_t *uuid,
pContext->mItfe = &gLEInterface;
pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
- pContext->mCompressorL = NULL;
- pContext->mCompressorR = NULL;
+ pContext->mCompressor = NULL;
ret = LE_init(pContext);
if (ret < 0) {
ALOGW("LELib_Create() init failed");
@@ -242,13 +235,9 @@ int LELib_Release(effect_handle_t handle) {
return -EINVAL;
}
pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
- if (pContext->mCompressorL != NULL) {
- delete pContext->mCompressorL;
- pContext->mCompressorL = NULL;
- }
- if (pContext->mCompressorR != NULL) {
- delete pContext->mCompressorR;
- pContext->mCompressorR = NULL;
+ if (pContext->mCompressor != NULL) {
+ delete pContext->mCompressor;
+ pContext->mCompressor = NULL;
}
delete pContext;
@@ -293,11 +282,14 @@ int LE_process(
//ALOGV("LE about to process %d samples", inBuffer->frameCount);
uint16_t inIdx;
float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
+ float leftSample, rightSample;
for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
- inBuffer->s16[2*inIdx] = pContext->mCompressorL->Compress(
- inputAmp * (float)inBuffer->s16[2*inIdx]);
- inBuffer->s16[2*inIdx +1] = pContext->mCompressorR->Compress(
- inputAmp * (float)inBuffer->s16[2*inIdx +1]);
+ // makeup gain is applied on the input of the compressor
+ leftSample = inputAmp * (float)inBuffer->s16[2*inIdx];
+ rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
+ pContext->mCompressor->Compress(&leftSample, &rightSample);
+ inBuffer->s16[2*inIdx] = (int16_t) leftSample;
+ inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
}
if (inBuffer->raw != outBuffer->raw) {
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
index fed8c2a..da75ceb 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
@@ -35,7 +35,7 @@ inline void AdaptiveDynamicRangeCompression::set_knee_threshold_via_target_gain(
float target_gain) {
const float decibel = target_gain_to_knee_threshold_.Interpolate(
target_gain);
- ALOGE("set_knee_threshold_via_target_gain: decibel =%.3f", decibel);
+ ALOGV("set_knee_threshold_via_target_gain: decibel =%.3fdB", decibel);
set_knee_threshold(decibel);
}
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
index 2bbd043..7bd068e 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
@@ -102,5 +102,40 @@ float AdaptiveDynamicRangeCompression::Compress(float x) {
return x;
}
+void AdaptiveDynamicRangeCompression::Compress(float *x1, float *x2) {
+ // Taking the maximum amplitude of both channels
+ const float max_abs_x = std::max(std::fabs(*x1),
+ std::max(std::fabs(*x2), 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);
+ *x1 *= compressor_gain_;
+ if (*x1 > kFixedPointLimit) {
+ *x1 = kFixedPointLimit;
+ }
+ if (*x1 < -kFixedPointLimit) {
+ *x1 = -kFixedPointLimit;
+ }
+ *x2 *= compressor_gain_;
+ if (*x2 > kFixedPointLimit) {
+ *x2 = kFixedPointLimit;
+ }
+ if (*x2 < -kFixedPointLimit) {
+ *x2 = -kFixedPointLimit;
+ }
+}
+
} // namespace le_fx
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
index 4c015df..2821a78 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
@@ -55,6 +55,9 @@ class AdaptiveDynamicRangeCompression {
// log(.) and exp(.).
float Compress(float x);
+ // Stereo channel version of the compressor
+ void Compress(float *x1, float *x2);
+
// This version is slower than Compress(.) but faster than CompressSlow(.)
float CompressNormalSpeed(float x);