Setting EFFECT_FLAG_VOLUME_CTRL for DynamicsProcessing effect
Fixing level handling in DynamicsProcessing effect.
Bug: 79712497
Test: manual testing and sound amplifier test
Change-Id: Ie263ab570ad55e10e1ee80795357977a24a920fd
diff --git a/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp b/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
index 55383eb..0b883f1 100644
--- a/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
@@ -51,7 +51,7 @@
{0x7261676f, 0x6d75, 0x7369, 0x6364, {0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}}, // type
{0xe0e6539b, 0x1781, 0x7261, 0x676f, {0x6d, 0x75, 0x73, 0x69, 0x63, 0x40}}, // uuid
EFFECT_CONTROL_API_VERSION,
- (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | EFFECT_FLAG_VOLUME_CTRL),
0, // TODO
1,
"Dynamics Processing",
@@ -367,6 +367,76 @@
return 0;
}
+//helper function
+bool DP_checkSizesInt(uint32_t paramSize, uint32_t valueSize, uint32_t expectedParams,
+ uint32_t expectedValues) {
+ if (paramSize < expectedParams * sizeof(int32_t)) {
+ ALOGE("Invalid paramSize: %u expected %u", paramSize,
+ (uint32_t)(expectedParams * sizeof(int32_t)));
+ return false;
+ }
+ if (valueSize < expectedValues * sizeof(int32_t)) {
+ ALOGE("Invalid valueSize %u expected %u", valueSize,
+ (uint32_t)(expectedValues * sizeof(int32_t)));
+ return false;
+ }
+ return true;
+}
+
+static dp_fx::DPChannel* DP_getChannel(DynamicsProcessingContext *pContext,
+ int32_t channel) {
+ if (pContext->mPDynamics == NULL) {
+ return NULL;
+ }
+ dp_fx::DPChannel *pChannel = pContext->mPDynamics->getChannel(channel);
+ ALOGE_IF(pChannel == NULL, "DPChannel NULL. invalid channel %d", channel);
+ return pChannel;
+}
+
+static dp_fx::DPEq* DP_getEq(DynamicsProcessingContext *pContext, int32_t channel,
+ int32_t eqType) {
+ dp_fx::DPChannel *pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ return NULL;
+ }
+ dp_fx::DPEq *pEq = (eqType == DP_PARAM_PRE_EQ ? pChannel->getPreEq() :
+ (eqType == DP_PARAM_POST_EQ ? pChannel->getPostEq() : NULL));
+ ALOGE_IF(pEq == NULL,"DPEq NULL invalid eq");
+ return pEq;
+}
+
+static dp_fx::DPEqBand* DP_getEqBand(DynamicsProcessingContext *pContext, int32_t channel,
+ int32_t eqType, int32_t band) {
+ dp_fx::DPEq *pEq = DP_getEq(pContext, channel, eqType);
+ if (pEq == NULL) {
+ return NULL;
+ }
+ dp_fx::DPEqBand *pEqBand = pEq->getBand(band);
+ ALOGE_IF(pEqBand == NULL, "DPEqBand NULL. invalid band %d", band);
+ return pEqBand;
+}
+
+static dp_fx::DPMbc* DP_getMbc(DynamicsProcessingContext *pContext, int32_t channel) {
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ return NULL;
+ }
+ dp_fx::DPMbc *pMbc = pChannel->getMbc();
+ ALOGE_IF(pMbc == NULL, "DPMbc NULL invalid MBC");
+ return pMbc;
+}
+
+static dp_fx::DPMbcBand* DP_getMbcBand(DynamicsProcessingContext *pContext, int32_t channel,
+ int32_t band) {
+ dp_fx::DPMbc *pMbc = DP_getMbc(pContext, channel);
+ if (pMbc == NULL) {
+ return NULL;
+ }
+ dp_fx::DPMbcBand *pMbcBand = pMbc->getBand(band);
+ ALOGE_IF(pMbcBand == NULL, "pMbcBand NULL. invalid band %d", band);
+ return pMbcBand;
+}
+
int DP_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
void *pCmdData, uint32_t *replySize, void *pReplyData) {
@@ -483,8 +553,49 @@
p->data + voffset);
break;
}
+ case EFFECT_CMD_SET_VOLUME: {
+ ALOGV("EFFECT_CMD_SET_VOLUME");
+ // if pReplyData is NULL, VOL_CTRL is delegated to another effect
+ if (pReplyData == NULL || replySize == NULL || *replySize < ((int)sizeof(int32_t) * 2)) {
+ ALOGV("no VOLUME data to return");
+ break;
+ }
+ if (pCmdData == NULL || cmdSize < ((int)sizeof(uint32_t) * 2)) {
+ ALOGE("\tLVM_ERROR : DynamicsProcessing EFFECT_CMD_SET_VOLUME ERROR");
+ return -EINVAL;
+ }
+
+ const int32_t unityGain = 1 << 24;
+ //channel count
+ int32_t channelCount = (int32_t)audio_channel_count_from_out_mask(
+ pContext->mConfig.inputCfg.channels);
+ for (int32_t ch = 0; ch < channelCount; ch++) {
+
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, ch);
+ if (pChannel == NULL) {
+ ALOGE("%s EFFECT_CMD_SET_VOLUME invalid channel %d", __func__, ch);
+ return -EINVAL;
+ break;
+ }
+
+ int32_t offset = ch;
+ if (ch > 1) {
+ // FIXME: limited to 2 unique channels. If more channels present, use value for
+ // first channel
+ offset = 0;
+ }
+ const float gain = (float)*((uint32_t *)pCmdData + offset) / unityGain;
+ const float gainDb = linearToDb(gain);
+ ALOGVV("%s EFFECT_CMD_SET_VOLUME channel %d, engine outputlevel %f (%0.2f dB)",
+ __func__, ch, gain, gainDb);
+ pChannel->setOutputGain(gainDb);
+ }
+
+ const int32_t volRet[2] = {unityGain, unityGain}; // Apply no volume before effect.
+ memcpy(pReplyData, volRet, sizeof(volRet));
+ break;
+ }
case EFFECT_CMD_SET_DEVICE:
- case EFFECT_CMD_SET_VOLUME:
case EFFECT_CMD_SET_AUDIO_MODE:
break;
@@ -523,76 +634,6 @@
return 0;
}
-//helper function
-bool DP_checkSizesInt(uint32_t paramSize, uint32_t valueSize, uint32_t expectedParams,
- uint32_t expectedValues) {
- if (paramSize < expectedParams * sizeof(int32_t)) {
- ALOGE("Invalid paramSize: %u expected %u", paramSize,
- (uint32_t) (expectedParams * sizeof(int32_t)));
- return false;
- }
- if (valueSize < expectedValues * sizeof(int32_t)) {
- ALOGE("Invalid valueSize %u expected %u", valueSize,
- (uint32_t)(expectedValues * sizeof(int32_t)));
- return false;
- }
- return true;
-}
-
-static dp_fx::DPChannel* DP_getChannel(DynamicsProcessingContext *pContext,
- int32_t channel) {
- if (pContext->mPDynamics == NULL) {
- return NULL;
- }
- dp_fx::DPChannel *pChannel = pContext->mPDynamics->getChannel(channel);
- ALOGE_IF(pChannel == NULL, "DPChannel NULL. invalid channel %d", channel);
- return pChannel;
-}
-
-static dp_fx::DPEq* DP_getEq(DynamicsProcessingContext *pContext, int32_t channel,
- int32_t eqType) {
- dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
- if (pChannel == NULL) {
- return NULL;
- }
- dp_fx::DPEq *pEq = (eqType == DP_PARAM_PRE_EQ ? pChannel->getPreEq() :
- (eqType == DP_PARAM_POST_EQ ? pChannel->getPostEq() : NULL));
- ALOGE_IF(pEq == NULL,"DPEq NULL invalid eq");
- return pEq;
-}
-
-static dp_fx::DPEqBand* DP_getEqBand(DynamicsProcessingContext *pContext, int32_t channel,
- int32_t eqType, int32_t band) {
- dp_fx::DPEq *pEq = DP_getEq(pContext, channel, eqType);
- if (pEq == NULL) {
- return NULL;
- }
- dp_fx::DPEqBand *pEqBand = pEq->getBand(band);
- ALOGE_IF(pEqBand == NULL, "DPEqBand NULL. invalid band %d", band);
- return pEqBand;
-}
-
-static dp_fx::DPMbc* DP_getMbc(DynamicsProcessingContext *pContext, int32_t channel) {
- dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
- if (pChannel == NULL) {
- return NULL;
- }
- dp_fx::DPMbc *pMbc = pChannel->getMbc();
- ALOGE_IF(pMbc == NULL, "DPMbc NULL invalid MBC");
- return pMbc;
-}
-
-static dp_fx::DPMbcBand* DP_getMbcBand(DynamicsProcessingContext *pContext, int32_t channel,
- int32_t band) {
- dp_fx::DPMbc *pMbc = DP_getMbc(pContext, channel);
- if (pMbc == NULL) {
- return NULL;
- }
- dp_fx::DPMbcBand *pMbcBand = pMbc->getBand(band);
- ALOGE_IF(pMbcBand == NULL, "pMbcBand NULL. invalid band %d", band);
- return pMbcBand;
-}
-
int DP_getParameter(DynamicsProcessingContext *pContext,
uint32_t paramSize,
void *pParam,
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.cpp b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
index 8b79991..ac758e0 100644
--- a/media/libeffects/dynamicsproc/dsp/DPBase.cpp
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
@@ -174,8 +174,8 @@
}
//----
-DPChannel::DPChannel() : mInitialized(false), mInputGainDb(0), mPreEqInUse(false), mMbcInUse(false),
- mPostEqInUse(false), mLimiterInUse(false) {
+DPChannel::DPChannel() : mInitialized(false), mInputGainDb(0), mOutputGainDb(0),
+ mPreEqInUse(false), mMbcInUse(false), mPostEqInUse(false), mLimiterInUse(false) {
}
void DPChannel::init(float inputGain, bool preEqInUse, uint32_t preEqBandCount,
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.h b/media/libeffects/dynamicsproc/dsp/DPBase.h
index 355f64b..e74f91d 100644
--- a/media/libeffects/dynamicsproc/dsp/DPBase.h
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.h
@@ -272,6 +272,16 @@
mInputGainDb = gain;
}
+ float getOutputGain() const {
+ if (!mInitialized) {
+ return 0;
+ }
+ return mOutputGainDb;
+ }
+ void setOutputGain(float gain) {
+ mOutputGainDb = gain;
+ }
+
DPEq* getPreEq();
DPMbc* getMbc();
DPEq* getPostEq();
@@ -281,6 +291,7 @@
private:
bool mInitialized;
float mInputGainDb;
+ float mOutputGainDb;
DPEq mPreEq;
DPMbc mMbc;
diff --git a/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp b/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
index db20c41..e96a3ef 100644
--- a/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
+++ b/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
@@ -53,14 +53,6 @@
#define IS_CHANGED(c, a, b) { c |= !compareEquality(a,b); \
(a) = (b); }
-float dBtoLinear(float valueDb) {
- return pow (10, valueDb / 20.0);
-}
-
-float linearToDb(float value) {
- return 20 * log10(value);
-}
-
//ChannelBuffers helper
void ChannelBuffer::initBuffers(unsigned int blockSize, unsigned int overlapSize,
unsigned int halfFftSize, unsigned int samplingRate, DPBase &dpBase) {
@@ -376,6 +368,9 @@
mLinkedLimiters.update(cb.mLimiterParams.linkGroup, channelIndex);
}
}
+
+ //=== Output Gain
+ cb.outputGainDb = pChannel->getOutputGain();
}
size_t DPFrequency::processSamples(const float *in, float *out, size_t samples) {
@@ -651,16 +646,21 @@
}
size_t DPFrequency::processLastStages(ChannelBuffer &cb) {
+
+ float outputGainFactor = dBtoLinear(cb.outputGainDb);
//== Limiter. last Pass
if (cb.mLimiterInUse && cb.mLimiterEnabled) {
- const size_t cSize = cb.complexTemp.size();
- const size_t maxBin = std::min(cSize/2, mHalfFFTSize);
//compute factor, with post-gain
float factor = cb.mLimiterParams.linkFactor * dBtoLinear(cb.mLimiterParams.postGainDb);
+ outputGainFactor *= factor;
+ }
- //apply to all
+ //apply to all if != 1.0
+ if (!compareEquality(outputGainFactor, 1.0f)) {
+ size_t cSize = cb.complexTemp.size();
+ size_t maxBin = std::min(cSize/2, mHalfFFTSize);
for (size_t k = 0; k < maxBin; k++) {
- cb.complexTemp[k] *= factor;
+ cb.complexTemp[k] *= outputGainFactor;
}
}
diff --git a/media/libeffects/dynamicsproc/dsp/DPFrequency.h b/media/libeffects/dynamicsproc/dsp/DPFrequency.h
index c502eb8..be8771d 100644
--- a/media/libeffects/dynamicsproc/dsp/DPFrequency.h
+++ b/media/libeffects/dynamicsproc/dsp/DPFrequency.h
@@ -43,6 +43,7 @@
//Current parameters
float inputGainDb;
+ float outputGainDb;
struct BandParams {
bool enabled;
float freqCutoffHz;
diff --git a/media/libeffects/dynamicsproc/dsp/RDsp.h b/media/libeffects/dynamicsproc/dsp/RDsp.h
index cc568ba..cfa1305 100644
--- a/media/libeffects/dynamicsproc/dsp/RDsp.h
+++ b/media/libeffects/dynamicsproc/dsp/RDsp.h
@@ -26,6 +26,19 @@
using ComplexVec = std::vector<std::complex<float>>;
// =======
+// Helper Functions
+// =======
+template <class T>
+static T dBtoLinear(T valueDb) {
+ return pow (10, valueDb / 20.0);
+}
+
+template <class T>
+static T linearToDb(T value) {
+ return 20 * log10(value);
+}
+
+// =======
// DSP window creation
// =======