Dynamics Processing Effect
Effect and command implementation
Bug: 64161702
Bug: 38266419
Test: manual testing and cts tests
Change-Id: Iead2cd5efd22f735fdcdfd17e81180c4b52260c5
diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf
index 14a171b..dd729c5 100644
--- a/media/libeffects/data/audio_effects.conf
+++ b/media/libeffects/data/audio_effects.conf
@@ -38,6 +38,9 @@
loudness_enhancer {
path /vendor/lib/soundfx/libldnhncr.so
}
+ dynamics_processing {
+ path /vendor/lib/soundfx/libdynproc.so
+ }
}
# Default pre-processing library. Add to audio_effect.conf "libraries" section if
@@ -129,6 +132,10 @@
library loudness_enhancer
uuid fa415329-2034-4bea-b5dc-5b381c8d1e2c
}
+ dynamics_processing {
+ library dynamics_processing
+ uuid e0e6539b-1781-7261-676f-6d7573696340
+ }
}
# Default pre-processing effects. Add to audio_effect.conf "effects" section if
diff --git a/media/libeffects/dynamicsproc/Android.mk b/media/libeffects/dynamicsproc/Android.mk
new file mode 100644
index 0000000..a27a2e7
--- /dev/null
+++ b/media/libeffects/dynamicsproc/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# DynamicsProcessing library
+include $(CLEAR_VARS)
+
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES:= \
+ EffectDynamicsProcessing.cpp \
+ dsp/DPBase.cpp
+
+LOCAL_CFLAGS+= -O2 -fvisibility=hidden
+LOCAL_CFLAGS += -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ liblog \
+
+LOCAL_MODULE_RELATIVE_PATH := soundfx
+LOCAL_MODULE:= libdynproc
+
+LOCAL_HEADER_LIBRARIES := \
+ libaudioeffects
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp b/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
new file mode 100644
index 0000000..56cd247
--- /dev/null
+++ b/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
@@ -0,0 +1,1215 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "EffectDP"
+//#define LOG_NDEBUG 0
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <new>
+
+#include <log/log.h>
+
+#include <audio_effects/effect_dynamicsprocessing.h>
+#include <dsp/DPBase.h>
+
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while (false)
+#endif
+
+// union to hold command values
+using value_t = union {
+ int32_t i;
+ float f;
+};
+
+// effect_handle_t interface implementation for DP effect
+extern const struct effect_interface_s gDPInterface;
+
+// AOSP Dynamics Processing UUID: e0e6539b-1781-7261-676f-6d7573696340
+const effect_descriptor_t gDPDescriptor = {
+ {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),
+ 0, // TODO
+ 1,
+ "Dynamics Processing",
+ "The Android Open Source Project",
+};
+
+enum dp_state_e {
+ DYNAMICS_PROCESSING_STATE_UNINITIALIZED,
+ DYNAMICS_PROCESSING_STATE_INITIALIZED,
+ DYNAMICS_PROCESSING_STATE_ACTIVE,
+};
+
+struct DynamicsProcessingContext {
+ const struct effect_interface_s *mItfe;
+ effect_config_t mConfig;
+ uint8_t mState;
+
+ dp_fx::DPBase * mPDynamics; //the effect (or current effect)
+ int32_t mCurrentVariant;
+ float mPreferredFrameDuration;
+};
+
+// The value offset of an effect parameter is computed by rounding up
+// the parameter size to the next 32 bit alignment.
+static inline uint32_t computeParamVOffset(const effect_param_t *p) {
+ return ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
+ sizeof(int32_t);
+}
+
+//--- local function prototypes
+int DP_setParameter(DynamicsProcessingContext *pContext,
+ uint32_t paramSize,
+ void *pParam,
+ uint32_t valueSize,
+ void *pValue);
+int DP_getParameter(DynamicsProcessingContext *pContext,
+ uint32_t paramSize,
+ void *pParam,
+ uint32_t *pValueSize,
+ void *pValue);
+int DP_getParameterCmdSize(uint32_t paramSize,
+ void *pParam);
+void DP_expectedParamValueSizes(uint32_t paramSize,
+ void *pParam,
+ bool isSet,
+ uint32_t *pCmdSize,
+ uint32_t *pValueSize);
+//
+//--- Local functions (not directly used by effect interface)
+//
+
+void DP_reset(DynamicsProcessingContext *pContext)
+{
+ ALOGV("> DP_reset(%p)", pContext);
+ if (pContext->mPDynamics != NULL) {
+ pContext->mPDynamics->reset();
+ } else {
+ ALOGE("DP_reset(%p): null DynamicsProcessing", pContext);
+ }
+}
+
+//----------------------------------------------------------------------------
+// DP_setConfig()
+//----------------------------------------------------------------------------
+// Purpose: Set input and output audio configuration.
+//
+// Inputs:
+// pContext: effect engine context
+// pConfig: pointer to effect_config_t structure holding input and output
+// configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int DP_setConfig(DynamicsProcessingContext *pContext, effect_config_t *pConfig)
+{
+ ALOGV("DP_setConfig(%p)", pContext);
+
+ if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
+ if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
+ if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
+ if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
+ pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
+ if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_FLOAT) return -EINVAL;
+
+ pContext->mConfig = *pConfig;
+
+ DP_reset(pContext);
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+// DP_getConfig()
+//----------------------------------------------------------------------------
+// Purpose: Get input and output audio configuration.
+//
+// Inputs:
+// pContext: effect engine context
+// pConfig: pointer to effect_config_t structure holding input and output
+// configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+void DP_getConfig(DynamicsProcessingContext *pContext, effect_config_t *pConfig)
+{
+ *pConfig = pContext->mConfig;
+}
+
+//----------------------------------------------------------------------------
+// DP_init()
+//----------------------------------------------------------------------------
+// Purpose: Initialize engine with default configuration.
+//
+// Inputs:
+// pContext: effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int DP_init(DynamicsProcessingContext *pContext)
+{
+ ALOGV("DP_init(%p)", pContext);
+
+ pContext->mItfe = &gDPInterface;
+ pContext->mPDynamics = NULL;
+ pContext->mState = DYNAMICS_PROCESSING_STATE_UNINITIALIZED;
+
+ pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+ pContext->mConfig.inputCfg.samplingRate = 44100;
+ pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
+ pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
+ pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
+ pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
+ pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+ pContext->mConfig.outputCfg.samplingRate = 44100;
+ pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
+ pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
+ pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
+ pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ pContext->mCurrentVariant = -1; //none
+ pContext->mPreferredFrameDuration = 0; //none
+
+ DP_setConfig(pContext, &pContext->mConfig);
+ pContext->mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+ return 0;
+}
+
+void DP_changeVariant(DynamicsProcessingContext *pContext, int newVariant) {
+ if (pContext->mPDynamics != NULL) {
+ delete pContext->mPDynamics;
+ pContext->mPDynamics = NULL;
+ }
+ switch(newVariant) {
+ //TODO: actually instantiate one of the variants. For now all instantiate the base;
+ default:
+ pContext->mCurrentVariant = newVariant;
+ pContext->mPDynamics = new dp_fx::DPBase();
+ break;
+ }
+}
+
+//
+//--- Effect Library Interface Implementation
+//
+
+int DPLib_Release(effect_handle_t handle) {
+ DynamicsProcessingContext * pContext = (DynamicsProcessingContext *)handle;
+
+ ALOGV("DPLib_Release %p", handle);
+ if (pContext == NULL) {
+ return -EINVAL;
+ }
+ delete pContext->mPDynamics;
+ delete pContext;
+
+ return 0;
+}
+
+int DPLib_Create(const effect_uuid_t *uuid,
+ int32_t sessionId __unused,
+ int32_t ioId __unused,
+ effect_handle_t *pHandle) {
+ ALOGV("DPLib_Create()");
+
+ if (pHandle == NULL || uuid == NULL) {
+ return -EINVAL;
+ }
+
+ if (memcmp(uuid, &gDPDescriptor.uuid, sizeof(*uuid)) != 0) {
+ return -EINVAL;
+ }
+
+ DynamicsProcessingContext *pContext = new DynamicsProcessingContext;
+ *pHandle = (effect_handle_t)pContext;
+ int ret = DP_init(pContext);
+ if (ret < 0) {
+ ALOGW("DPLib_Create() init failed");
+ DPLib_Release(*pHandle);
+ return ret;
+ }
+
+ ALOGV("DPLib_Create context is %p", pContext);
+ return 0;
+}
+
+int DPLib_GetDescriptor(const effect_uuid_t *uuid,
+ effect_descriptor_t *pDescriptor) {
+
+ if (pDescriptor == NULL || uuid == NULL){
+ ALOGE("DPLib_GetDescriptor() called with NULL pointer");
+ return -EINVAL;
+ }
+
+ if (memcmp(uuid, &gDPDescriptor.uuid, sizeof(*uuid)) == 0) {
+ *pDescriptor = gDPDescriptor;
+ return 0;
+ }
+
+ return -EINVAL;
+} /* end DPLib_GetDescriptor */
+
+//
+//--- Effect Control Interface Implementation
+//
+int DP_process(effect_handle_t self, audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer) {
+ DynamicsProcessingContext * pContext = (DynamicsProcessingContext *)self;
+
+ if (pContext == NULL) {
+ ALOGE("DP_process() called with NULL context");
+ return -EINVAL;
+ }
+
+ if (inBuffer == NULL || inBuffer->raw == NULL ||
+ outBuffer == NULL || outBuffer->raw == NULL ||
+ inBuffer->frameCount != outBuffer->frameCount ||
+ inBuffer->frameCount == 0) {
+ ALOGE("inBuffer or outBuffer are NULL or have problems with frame count");
+ return -EINVAL;
+ }
+ if (pContext->mState != DYNAMICS_PROCESSING_STATE_ACTIVE) {
+ ALOGE("mState is not DYNAMICS_PROCESSING_STATE_ACTIVE. Current mState %d",
+ pContext->mState);
+ return -ENODATA;
+ }
+ //if dynamics exist...
+ if (pContext->mPDynamics != NULL) {
+ int32_t channelCount = (int32_t)audio_channel_count_from_out_mask(
+ pContext->mConfig.inputCfg.channels);
+ pContext->mPDynamics->processSamples(inBuffer->f32, inBuffer->f32,
+ inBuffer->frameCount * channelCount);
+ if (inBuffer->raw != outBuffer->raw) {
+ if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (size_t i = 0; i < outBuffer->frameCount * channelCount; i++) {
+ outBuffer->f32[i] += inBuffer->f32[i];
+ }
+ } else {
+ memcpy(outBuffer->raw, inBuffer->raw,
+ outBuffer->frameCount * channelCount * sizeof(float));
+ }
+ }
+ } else {
+ //do nothing. no effect created yet. warning.
+ ALOGW("Warning: no DynamicsProcessing engine available");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int DP_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
+ void *pCmdData, uint32_t *replySize, void *pReplyData) {
+
+ DynamicsProcessingContext * pContext = (DynamicsProcessingContext *)self;
+
+ if (pContext == NULL || pContext->mState == DYNAMICS_PROCESSING_STATE_UNINITIALIZED) {
+ ALOGE("DP_command() called with NULL context or uninitialized state.");
+ return -EINVAL;
+ }
+
+ ALOGV("DP_command command %d cmdSize %d",cmdCode, cmdSize);
+ switch (cmdCode) {
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ ALOGE("EFFECT_CMD_INIT wrong replyData or repySize");
+ return -EINVAL;
+ }
+ *(int *) pReplyData = DP_init(pContext);
+ break;
+ case EFFECT_CMD_SET_CONFIG:
+ if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+ || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
+ ALOGE("EFFECT_CMD_SET_CONFIG error with pCmdData, cmdSize, pReplyData or replySize");
+ return -EINVAL;
+ }
+ *(int *) pReplyData = DP_setConfig(pContext,
+ (effect_config_t *) pCmdData);
+ break;
+ case EFFECT_CMD_GET_CONFIG:
+ if (pReplyData == NULL ||
+ *replySize != sizeof(effect_config_t)) {
+ ALOGE("EFFECT_CMD_GET_CONFIG wrong replyData or repySize");
+ return -EINVAL;
+ }
+ DP_getConfig(pContext, (effect_config_t *)pReplyData);
+ break;
+ case EFFECT_CMD_RESET:
+ DP_reset(pContext);
+ break;
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
+ ALOGE("EFFECT_CMD_ENABLE wrong replyData or repySize");
+ return -EINVAL;
+ }
+ if (pContext->mState != DYNAMICS_PROCESSING_STATE_INITIALIZED) {
+ ALOGE("EFFECT_CMD_ENABLE state not initialized");
+ *(int *)pReplyData = -ENOSYS;
+ } else {
+ pContext->mState = DYNAMICS_PROCESSING_STATE_ACTIVE;
+ ALOGV("EFFECT_CMD_ENABLE() OK");
+ *(int *)pReplyData = 0;
+ }
+ break;
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
+ ALOGE("EFFECT_CMD_DISABLE wrong replyData or repySize");
+ return -EINVAL;
+ }
+ if (pContext->mState != DYNAMICS_PROCESSING_STATE_ACTIVE) {
+ ALOGE("EFFECT_CMD_DISABLE state not active");
+ *(int *)pReplyData = -ENOSYS;
+ } else {
+ pContext->mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+ ALOGV("EFFECT_CMD_DISABLE() OK");
+ *(int *)pReplyData = 0;
+ }
+ break;
+ case EFFECT_CMD_GET_PARAM: {
+ if (pCmdData == NULL || pReplyData == NULL || replySize == NULL) {
+ ALOGE("null pCmdData or pReplyData or replySize");
+ return -EINVAL;
+ }
+ effect_param_t *pEffectParam = (effect_param_t *) pCmdData;
+ uint32_t expectedCmdSize = DP_getParameterCmdSize(pEffectParam->psize,
+ pEffectParam->data);
+ if (cmdSize != expectedCmdSize || *replySize < expectedCmdSize) {
+ ALOGE("error cmdSize: %d, expetedCmdSize: %d, replySize: %d",
+ cmdSize, expectedCmdSize, *replySize);
+ return -EINVAL;
+ }
+
+ ALOGVV("DP_command expectedCmdSize: %d", expectedCmdSize);
+ memcpy(pReplyData, pCmdData, expectedCmdSize);
+ effect_param_t *p = (effect_param_t *)pReplyData;
+
+ uint32_t voffset = computeParamVOffset(p);
+
+ p->status = DP_getParameter(pContext,
+ p->psize,
+ p->data,
+ &p->vsize,
+ p->data + voffset);
+ *replySize = sizeof(effect_param_t) + voffset + p->vsize;
+
+ ALOGVV("DP_command replysize %u, status %d" , *replySize, p->status);
+ break;
+ }
+ case EFFECT_CMD_SET_PARAM: {
+ if (pCmdData == NULL ||
+ cmdSize < (sizeof(effect_param_t) + sizeof(int32_t) + sizeof(int32_t)) ||
+ pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
+ ALOGE("\tLVM_ERROR : DynamicsProcessing cmdCode Case: "
+ "EFFECT_CMD_SET_PARAM: ERROR");
+ return -EINVAL;
+ }
+
+ effect_param_t * const p = (effect_param_t *) pCmdData;
+ const uint32_t voffset = computeParamVOffset(p);
+
+ *(int *)pReplyData = DP_setParameter(pContext,
+ p->psize,
+ (void *)p->data,
+ p->vsize,
+ p->data + voffset);
+ break;
+ }
+ case EFFECT_CMD_SET_DEVICE:
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
+
+ default:
+ ALOGW("DP_command invalid command %d",cmdCode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+//register expected cmd size
+int DP_getParameterCmdSize(uint32_t paramSize,
+ void *pParam) {
+ if (paramSize < sizeof(int32_t)) {
+ return 0;
+ }
+ int32_t param = *(int32_t*)pParam;
+ switch(param) {
+ case DP_PARAM_GET_CHANNEL_COUNT: //paramcmd
+ case DP_PARAM_ENGINE_ARCHITECTURE:
+ //effect + param
+ return (int)(sizeof(effect_param_t) + sizeof(uint32_t));
+ case DP_PARAM_INPUT_GAIN: //paramcmd + param
+ case DP_PARAM_LIMITER:
+ case DP_PARAM_PRE_EQ:
+ case DP_PARAM_POST_EQ:
+ case DP_PARAM_MBC:
+ //effect + param
+ return (int)(sizeof(effect_param_t) + 2 * sizeof(uint32_t));
+ case DP_PARAM_PRE_EQ_BAND:
+ case DP_PARAM_POST_EQ_BAND:
+ case DP_PARAM_MBC_BAND:
+ return (int)(sizeof(effect_param_t) + 3 * sizeof(uint32_t));
+ }
+ 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() : pChannel->getPostEq();
+ 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,
+ uint32_t *pValueSize,
+ void *pValue) {
+ int status = 0;
+ int32_t *params = (int32_t *)pParam;
+ static_assert(sizeof(float) == sizeof(int32_t) && sizeof(float) == sizeof(value_t) &&
+ alignof(float) == alignof(int32_t) && alignof(float) == alignof(value_t),
+ "Size/alignment mismatch for float/int32_t/value_t");
+ value_t *values = reinterpret_cast<value_t*>(pValue);
+
+ ALOGVV("%s start", __func__);
+#ifdef VERY_VERY_VERBOSE_LOGGING
+ for (size_t i = 0; i < paramSize/sizeof(int32_t); i++) {
+ ALOGVV("Param[%zu] %d", i, params[i]);
+ }
+#endif
+ if (paramSize < sizeof(int32_t)) {
+ ALOGE("%s invalid paramSize: %u", __func__, paramSize);
+ return -EINVAL;
+ }
+ const int32_t command = params[0];
+ switch (command) {
+ case DP_PARAM_GET_CHANNEL_COUNT: {
+ if (!DP_checkSizesInt(paramSize,*pValueSize, 1 /*params*/, 1 /*values*/)) {
+ ALOGE("%s DP_PARAM_GET_CHANNEL_COUNT (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+ *pValueSize = sizeof(uint32_t);
+ *(uint32_t *)pValue = (uint32_t)audio_channel_count_from_out_mask(
+ pContext->mConfig.inputCfg.channels);
+ ALOGVV("%s DP_PARAM_GET_CHANNEL_COUNT channels %d", __func__, *(int32_t *)pValue);
+ break;
+ }
+ case DP_PARAM_ENGINE_ARCHITECTURE: {
+ ALOGVV("engine architecture paramsize: %d valuesize %d",paramSize, *pValueSize);
+ if (!DP_checkSizesInt(paramSize, *pValueSize, 1 /*params*/, 9 /*values*/)) {
+ ALOGE("%s DP_PARAM_ENGINE_ARCHITECTURE (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = { PARAM_ENGINE_ARCHITECTURE };
+// Number[] values = { 0 /*0 variant */,
+// 0.0f /* 1 preferredFrameDuration */,
+// 0 /*2 preEqInUse */,
+// 0 /*3 preEqBandCount */,
+// 0 /*4 mbcInUse */,
+// 0 /*5 mbcBandCount*/,
+// 0 /*6 postEqInUse */,
+// 0 /*7 postEqBandCount */,
+// 0 /*8 limiterInUse */};
+ if (pContext->mPDynamics == NULL) {
+ ALOGE("%s DP_PARAM_ENGINE_ARCHITECTURE error mPDynamics is NULL", __func__);
+ status = -EINVAL;
+ break;
+ }
+ values[0].i = pContext->mCurrentVariant;
+ values[1].f = pContext->mPreferredFrameDuration;
+ values[2].i = pContext->mPDynamics->isPreEQInUse();
+ values[3].i = pContext->mPDynamics->getPreEqBandCount();
+ values[4].i = pContext->mPDynamics->isMbcInUse();
+ values[5].i = pContext->mPDynamics->getMbcBandCount();
+ values[6].i = pContext->mPDynamics->isPostEqInUse();
+ values[7].i = pContext->mPDynamics->getPostEqBandCount();
+ values[8].i = pContext->mPDynamics->isLimiterInUse();
+
+ *pValueSize = sizeof(value_t) * 9;
+
+ ALOGVV(" variant %d, preferredFrameDuration: %f, preEqInuse %d, bands %d, mbcinuse %d,"
+ "mbcbands %d, posteqInUse %d, bands %d, limiterinuse %d",
+ values[0].i, values[1].f, values[2].i, values[3].i, values[4].i, values[5].i,
+ values[6].i, values[7].i, values[8].i);
+ break;
+ }
+ case DP_PARAM_INPUT_GAIN: {
+ ALOGVV("engine get PARAM_INPUT_GAIN paramsize: %d valuesize %d",paramSize, *pValueSize);
+ if (!DP_checkSizesInt(paramSize, *pValueSize, 2 /*params*/, 1 /*values*/)) {
+ ALOGE("%s get PARAM_INPUT_GAIN invalid sizes.", __func__);
+ status = -EINVAL;
+ break;
+ }
+
+ const int32_t channel = params[1];
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ ALOGE("%s get PARAM_INPUT_GAIN invalid channel %d", __func__, channel);
+ status = -EINVAL;
+ break;
+ }
+ values[0].f = pChannel->getInputGain();
+ *pValueSize = sizeof(value_t) * 1;
+
+ ALOGVV(" channel: %d, input gain %f\n", channel, values[0].f);
+ break;
+ }
+ case DP_PARAM_PRE_EQ:
+ case DP_PARAM_POST_EQ: {
+ ALOGVV("engine get PARAM_*_EQ paramsize: %d valuesize %d",paramSize, *pValueSize);
+ if (!DP_checkSizesInt(paramSize, *pValueSize, 2 /*params*/, 3 /*values*/)) {
+ ALOGE("%s get PARAM_*_EQ (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = {paramSet == PARAM_PRE_EQ ? PARAM_PRE_EQ : PARAM_POST_EQ,
+// channelIndex};
+// Number[] values = {0 /*0 in use */,
+// 0 /*1 enabled*/,
+// 0 /*2 band count */};
+ const int32_t channel = params[1];
+
+ dp_fx::DPEq *pEq = DP_getEq(pContext, channel, command);
+ if (pEq == NULL) {
+ ALOGE("%s get PARAM_*_EQ invalid eq", __func__);
+ status = -EINVAL;
+ break;
+ }
+ values[0].i = pEq->isInUse();
+ values[1].i = pEq->isEnabled();
+ values[2].i = pEq->getBandCount();
+ *pValueSize = sizeof(value_t) * 3;
+
+ ALOGVV(" %s channel: %d, inUse::%d, enabled:%d, bandCount:%d\n",
+ (command == DP_PARAM_PRE_EQ ? "preEq" : "postEq"), channel,
+ values[0].i, values[1].i, values[2].i);
+ break;
+ }
+ case DP_PARAM_PRE_EQ_BAND:
+ case DP_PARAM_POST_EQ_BAND: {
+ ALOGVV("engine get PARAM_*_EQ_BAND paramsize: %d valuesize %d",paramSize, *pValueSize);
+ if (!DP_checkSizesInt(paramSize, *pValueSize, 3 /*params*/, 3 /*values*/)) {
+ ALOGE("%s get PARAM_*_EQ_BAND (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = {paramSet,
+// channelIndex,
+// bandIndex};
+// Number[] values = {(eqBand.isEnabled() ? 1 : 0),
+// eqBand.getCutoffFrequency(),
+// eqBand.getGain()};
+ const int32_t channel = params[1];
+ const int32_t band = params[2];
+
+ dp_fx::DPEqBand *pEqBand = DP_getEqBand(pContext, channel, command, band);
+ if (pEqBand == NULL) {
+ ALOGE("%s get PARAM_*_EQ_BAND invalid channel %d or band %d", __func__, channel, band);
+ status = -EINVAL;
+ break;
+ }
+
+ values[0].i = pEqBand->isEnabled();
+ values[1].f = pEqBand->getCutoffFrequency();
+ values[2].f = pEqBand->getGain();
+ *pValueSize = sizeof(value_t) * 3;
+
+ ALOGVV("%s channel: %d, band::%d, enabled:%d, cutoffFrequency:%f, gain%f\n",
+ (command == DP_PARAM_PRE_EQ_BAND ? "preEqBand" : "postEqBand"), channel, band,
+ values[0].i, values[1].f, values[2].f);
+ break;
+ }
+ case DP_PARAM_MBC: {
+ ALOGVV("engine get PDP_PARAM_MBC paramsize: %d valuesize %d",paramSize, *pValueSize);
+ if (!DP_checkSizesInt(paramSize, *pValueSize, 2 /*params*/, 3 /*values*/)) {
+ ALOGE("%s get PDP_PARAM_MBC (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+
+// Number[] params = {PARAM_MBC,
+// channelIndex};
+// Number[] values = {0 /*0 in use */,
+// 0 /*1 enabled*/,
+// 0 /*2 band count */};
+
+ const int32_t channel = params[1];
+
+ dp_fx::DPMbc *pMbc = DP_getMbc(pContext, channel);
+ if (pMbc == NULL) {
+ ALOGE("%s get PDP_PARAM_MBC invalid MBC", __func__);
+ status = -EINVAL;
+ break;
+ }
+
+ values[0].i = pMbc->isInUse();
+ values[1].i = pMbc->isEnabled();
+ values[2].i = pMbc->getBandCount();
+ *pValueSize = sizeof(value_t) * 3;
+
+ ALOGVV("DP_PARAM_MBC channel: %d, inUse::%d, enabled:%d, bandCount:%d\n", channel,
+ values[0].i, values[1].i, values[2].i);
+ break;
+ }
+ case DP_PARAM_MBC_BAND: {
+ ALOGVV("engine get DP_PARAM_MBC_BAND paramsize: %d valuesize %d",paramSize, *pValueSize);
+ if (!DP_checkSizesInt(paramSize, *pValueSize, 3 /*params*/, 11 /*values*/)) {
+ ALOGE("%s get DP_PARAM_MBC_BAND (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = {PARAM_MBC_BAND,
+// channelIndex,
+// bandIndex};
+// Number[] values = {0 /*0 enabled */,
+// 0.0f /*1 cutoffFrequency */,
+// 0.0f /*2 AttackTime */,
+// 0.0f /*3 ReleaseTime */,
+// 0.0f /*4 Ratio */,
+// 0.0f /*5 Threshold */,
+// 0.0f /*6 KneeWidth */,
+// 0.0f /*7 NoiseGateThreshold */,
+// 0.0f /*8 ExpanderRatio */,
+// 0.0f /*9 PreGain */,
+// 0.0f /*10 PostGain*/};
+
+ const int32_t channel = params[1];
+ const int32_t band = params[2];
+
+ dp_fx::DPMbcBand *pMbcBand = DP_getMbcBand(pContext, channel, band);
+ if (pMbcBand == NULL) {
+ ALOGE("%s get PARAM_MBC_BAND invalid channel %d or band %d", __func__, channel, band);
+ status = -EINVAL;
+ break;
+ }
+
+ values[0].i = pMbcBand->isEnabled();
+ values[1].f = pMbcBand->getCutoffFrequency();
+ values[2].f = pMbcBand->getAttackTime();
+ values[3].f = pMbcBand->getReleaseTime();
+ values[4].f = pMbcBand->getRatio();
+ values[5].f = pMbcBand->getThreshold();
+ values[6].f = pMbcBand->getKneeWidth();
+ values[7].f = pMbcBand->getNoiseGateThreshold();
+ values[8].f = pMbcBand->getExpanderRatio();
+ values[9].f = pMbcBand->getPreGain();
+ values[10].f = pMbcBand->getPostGain();
+
+ *pValueSize = sizeof(value_t) * 11;
+ ALOGVV(" mbcBand channel: %d, band::%d, enabled:%d, cutoffFrequency:%f, attackTime:%f,"
+ "releaseTime:%f, ratio:%f, threshold:%f, kneeWidth:%f, noiseGateThreshold:%f,"
+ "expanderRatio:%f, preGain:%f, postGain:%f\n", channel, band, values[0].i,
+ values[1].f, values[2].f, values[3].f, values[4].f, values[5].f, values[6].f,
+ values[7].f, values[8].f, values[9].f, values[10].f);
+ break;
+ }
+ case DP_PARAM_LIMITER: {
+ ALOGVV("engine get DP_PARAM_LIMITER paramsize: %d valuesize %d",paramSize, *pValueSize);
+ if (!DP_checkSizesInt(paramSize, *pValueSize, 2 /*params*/, 8 /*values*/)) {
+ ALOGE("%s DP_PARAM_LIMITER (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+
+ int32_t channel = params[1];
+// Number[] values = {0 /*0 in use (int)*/,
+// 0 /*1 enabled (int)*/,
+// 0 /*2 link group (int)*/,
+// 0.0f /*3 attack time (float)*/,
+// 0.0f /*4 release time (float)*/,
+// 0.0f /*5 ratio (float)*/,
+// 0.0f /*6 threshold (float)*/,
+// 0.0f /*7 post gain(float)*/};
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ ALOGE("%s DP_PARAM_LIMITER invalid channel %d", __func__, channel);
+ status = -EINVAL;
+ break;
+ }
+ dp_fx::DPLimiter *pLimiter = pChannel->getLimiter();
+ if (pLimiter == NULL) {
+ ALOGE("%s DP_PARAM_LIMITER null LIMITER", __func__);
+ status = -EINVAL;
+ break;
+ }
+ values[0].i = pLimiter->isInUse();
+ values[1].i = pLimiter->isEnabled();
+ values[2].i = pLimiter->getLinkGroup();
+ values[3].f = pLimiter->getAttackTime();
+ values[4].f = pLimiter->getReleaseTime();
+ values[5].f = pLimiter->getRatio();
+ values[6].f = pLimiter->getThreshold();
+ values[7].f = pLimiter->getPostGain();
+
+ *pValueSize = sizeof(value_t) * 8;
+
+ ALOGVV(" Limiter channel: %d, inUse::%d, enabled:%d, linkgroup:%d attackTime:%f,"
+ "releaseTime:%f, ratio:%f, threshold:%f, postGain:%f\n",
+ channel, values[0].i/*inUse*/, values[1].i/*enabled*/, values[2].i/*linkGroup*/,
+ values[3].f/*attackTime*/, values[4].f/*releaseTime*/,
+ values[5].f/*ratio*/, values[6].f/*threshold*/,
+ values[7].f/*postGain*/);
+ break;
+ }
+ default:
+ ALOGE("%s invalid param %d", __func__, params[0]);
+ status = -EINVAL;
+ break;
+ }
+
+ ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
+ return status;
+} /* end DP_getParameter */
+
+int DP_setParameter(DynamicsProcessingContext *pContext,
+ uint32_t paramSize,
+ void *pParam,
+ uint32_t valueSize,
+ void *pValue) {
+ int status = 0;
+ int32_t *params = (int32_t *)pParam;
+ static_assert(sizeof(float) == sizeof(int32_t) && sizeof(float) == sizeof(value_t) &&
+ alignof(float) == alignof(int32_t) && alignof(float) == alignof(value_t),
+ "Size/alignment mismatch for float/int32_t/value_t");
+ value_t *values = reinterpret_cast<value_t*>(pValue);
+
+ ALOGVV("%s start", __func__);
+ if (paramSize < sizeof(int32_t)) {
+ ALOGE("%s invalid paramSize: %u", __func__, paramSize);
+ return -EINVAL;
+ }
+ const int32_t command = params[0];
+ switch (command) {
+ case DP_PARAM_ENGINE_ARCHITECTURE: {
+ ALOGVV("engine architecture paramsize: %d valuesize %d",paramSize, valueSize);
+ if (!DP_checkSizesInt(paramSize, valueSize, 1 /*params*/, 9 /*values*/)) {
+ ALOGE("%s DP_PARAM_ENGINE_ARCHITECTURE (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = { PARAM_ENGINE_ARCHITECTURE };
+// Number[] values = { variant /* variant */,
+// preferredFrameDuration,
+// (preEqInUse ? 1 : 0),
+// preEqBandCount,
+// (mbcInUse ? 1 : 0),
+// mbcBandCount,
+// (postEqInUse ? 1 : 0),
+// postEqBandCount,
+// (limiterInUse ? 1 : 0)};
+ const int32_t variant = values[0].i;
+ const float preferredFrameDuration = values[1].f;
+ const int32_t preEqInUse = values[2].i;
+ const int32_t preEqBandCount = values[3].i;
+ const int32_t mbcInUse = values[4].i;
+ const int32_t mbcBandCount = values[5].i;
+ const int32_t postEqInUse = values[6].i;
+ const int32_t postEqBandCount = values[7].i;
+ const int32_t limiterInUse = values[8].i;
+ ALOGVV("variant %d, preEqInuse %d, bands %d, mbcinuse %d, mbcbands %d, posteqInUse %d,"
+ "bands %d, limiterinuse %d", variant, preEqInUse, preEqBandCount, mbcInUse,
+ mbcBandCount, postEqInUse, postEqBandCount, limiterInUse);
+
+ //set variant (instantiate effect)
+ //initArchitecture for effect
+ DP_changeVariant(pContext, variant);
+ if (pContext->mPDynamics == NULL) {
+ ALOGE("%s DP_PARAM_ENGINE_ARCHITECTURE error setting variant %d", __func__, variant);
+ status = -EINVAL;
+ break;
+ }
+ pContext->mPreferredFrameDuration = preferredFrameDuration;
+ pContext->mPDynamics->init((uint32_t)audio_channel_count_from_out_mask(
+ pContext->mConfig.inputCfg.channels),
+ preEqInUse != 0, (uint32_t)preEqBandCount,
+ mbcInUse != 0, (uint32_t)mbcBandCount,
+ postEqInUse != 0, (uint32_t)postEqBandCount,
+ limiterInUse != 0);
+ break;
+ }
+ case DP_PARAM_INPUT_GAIN: {
+ ALOGVV("engine DP_PARAM_INPUT_GAIN paramsize: %d valuesize %d",paramSize, valueSize);
+ if (!DP_checkSizesInt(paramSize, valueSize, 2 /*params*/, 1 /*values*/)) {
+ ALOGE("%s DP_PARAM_INPUT_GAIN invalid sizes.", __func__);
+ status = -EINVAL;
+ break;
+ }
+
+ const int32_t channel = params[1];
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ ALOGE("%s DP_PARAM_INPUT_GAIN invalid channel %d", __func__, channel);
+ status = -EINVAL;
+ break;
+ }
+ const float gain = values[0].f;
+ ALOGVV("%s DP_PARAM_INPUT_GAIN channel %d, level %f", __func__, channel, gain);
+ pChannel->setInputGain(gain);
+ break;
+ }
+ case DP_PARAM_PRE_EQ:
+ case DP_PARAM_POST_EQ: {
+ ALOGVV("engine DP_PARAM_*_EQ paramsize: %d valuesize %d",paramSize, valueSize);
+ if (!DP_checkSizesInt(paramSize, valueSize, 2 /*params*/, 3 /*values*/)) {
+ ALOGE("%s DP_PARAM_*_EQ (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = {paramSet,
+// channelIndex};
+// Number[] values = { (eq.isInUse() ? 1 : 0),
+// (eq.isEnabled() ? 1 : 0),
+// bandCount};
+ const int32_t channel = params[1];
+
+ const int32_t enabled = values[1].i;
+ const int32_t bandCount = values[2].i;
+ ALOGVV(" %s channel: %d, inUse::%d, enabled:%d, bandCount:%d\n",
+ (command == DP_PARAM_PRE_EQ ? "preEq" : "postEq"), channel, values[0].i,
+ values[2].i, bandCount);
+
+ dp_fx::DPEq *pEq = DP_getEq(pContext, channel, command);
+ if (pEq == NULL) {
+ ALOGE("%s set PARAM_*_EQ invalid channel %d or command %d", __func__, channel,
+ command);
+ status = -EINVAL;
+ break;
+ }
+
+ pEq->setEnabled(enabled != 0);
+ //fail if bandcountis different? maybe.
+ if ((int32_t)pEq->getBandCount() != bandCount) {
+ ALOGW("%s warning, trying to set different bandcount from %d to %d", __func__,
+ pEq->getBandCount(), bandCount);
+ }
+ break;
+ }
+ case DP_PARAM_PRE_EQ_BAND:
+ case DP_PARAM_POST_EQ_BAND: {
+ ALOGVV("engine set PARAM_*_EQ_BAND paramsize: %d valuesize %d",paramSize, valueSize);
+ if (!DP_checkSizesInt(paramSize, valueSize, 3 /*params*/, 3 /*values*/)) {
+ ALOGE("%s PARAM_*_EQ_BAND (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] values = { channelIndex,
+// bandIndex,
+// (eqBand.isEnabled() ? 1 : 0),
+// eqBand.getCutoffFrequency(),
+// eqBand.getGain()};
+
+// Number[] params = {paramSet,
+// channelIndex,
+// bandIndex};
+// Number[] values = {(eqBand.isEnabled() ? 1 : 0),
+// eqBand.getCutoffFrequency(),
+// eqBand.getGain()};
+
+ const int32_t channel = params[1];
+ const int32_t band = params[2];
+
+ const int32_t enabled = values[0].i;
+ const float cutoffFrequency = values[1].f;
+ const float gain = values[2].f;
+
+
+ ALOGVV(" %s channel: %d, band::%d, enabled:%d, cutoffFrequency:%f, gain%f\n",
+ (command == DP_PARAM_PRE_EQ_BAND ? "preEqBand" : "postEqBand"), channel, band,
+ enabled, cutoffFrequency, gain);
+
+ dp_fx::DPEq *pEq = DP_getEq(pContext, channel, command);
+ if (pEq == NULL) {
+ ALOGE("%s set PARAM_*_EQ_BAND invalid channel %d or command %d", __func__, channel,
+ command);
+ status = -EINVAL;
+ break;
+ }
+
+ dp_fx::DPEqBand eqBand;
+ eqBand.init(enabled != 0, cutoffFrequency, gain);
+ pEq->setBand(band, eqBand);
+ break;
+ }
+ case DP_PARAM_MBC: {
+ ALOGVV("engine DP_PARAM_MBC paramsize: %d valuesize %d",paramSize, valueSize);
+ if (!DP_checkSizesInt(paramSize, valueSize, 2 /*params*/, 3 /*values*/)) {
+ ALOGE("%s DP_PARAM_MBC (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = { PARAM_MBC,
+// channelIndex};
+// Number[] values = {(mbc.isInUse() ? 1 : 0),
+// (mbc.isEnabled() ? 1 : 0),
+// bandCount};
+ const int32_t channel = params[1];
+
+ const int32_t enabled = values[1].i;
+ const int32_t bandCount = values[2].i;
+ ALOGVV("MBC channel: %d, inUse::%d, enabled:%d, bandCount:%d\n", channel, values[0].i,
+ enabled, bandCount);
+
+ dp_fx::DPMbc *pMbc = DP_getMbc(pContext, channel);
+ if (pMbc == NULL) {
+ ALOGE("%s set DP_PARAM_MBC invalid channel %d ", __func__, channel);
+ status = -EINVAL;
+ break;
+ }
+
+ pMbc->setEnabled(enabled != 0);
+ //fail if bandcountis different? maybe.
+ if ((int32_t)pMbc->getBandCount() != bandCount) {
+ ALOGW("%s warning, trying to set different bandcount from %d to %d", __func__,
+ pMbc->getBandCount(), bandCount);
+ }
+ break;
+ }
+ case DP_PARAM_MBC_BAND: {
+ ALOGVV("engine set DP_PARAM_MBC_BAND paramsize: %d valuesize %d ",paramSize, valueSize);
+ if (!DP_checkSizesInt(paramSize, valueSize, 3 /*params*/, 11 /*values*/)) {
+ ALOGE("%s DP_PARAM_MBC_BAND: (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = { PARAM_MBC_BAND,
+// channelIndex,
+// bandIndex};
+// Number[] values = {(mbcBand.isEnabled() ? 1 : 0),
+// mbcBand.getCutoffFrequency(),
+// mbcBand.getAttackTime(),
+// mbcBand.getReleaseTime(),
+// mbcBand.getRatio(),
+// mbcBand.getThreshold(),
+// mbcBand.getKneeWidth(),
+// mbcBand.getNoiseGateThreshold(),
+// mbcBand.getExpanderRatio(),
+// mbcBand.getPreGain(),
+// mbcBand.getPostGain()};
+
+ const int32_t channel = params[1];
+ const int32_t band = params[2];
+
+ const int32_t enabled = values[0].i;
+ const float cutoffFrequency = values[1].f;
+ const float attackTime = values[2].f;
+ const float releaseTime = values[3].f;
+ const float ratio = values[4].f;
+ const float threshold = values[5].f;
+ const float kneeWidth = values[6].f;
+ const float noiseGateThreshold = values[7].f;
+ const float expanderRatio = values[8].f;
+ const float preGain = values[9].f;
+ const float postGain = values[10].f;
+
+ ALOGVV(" mbcBand channel: %d, band::%d, enabled:%d, cutoffFrequency:%f, attackTime:%f,"
+ "releaseTime:%f, ratio:%f, threshold:%f, kneeWidth:%f, noiseGateThreshold:%f,"
+ "expanderRatio:%f, preGain:%f, postGain:%f\n",
+ channel, band, enabled, cutoffFrequency, attackTime, releaseTime, ratio,
+ threshold, kneeWidth, noiseGateThreshold, expanderRatio, preGain, postGain);
+
+ dp_fx::DPMbc *pMbc = DP_getMbc(pContext, channel);
+ if (pMbc == NULL) {
+ ALOGE("%s set DP_PARAM_MBC_BAND invalid channel %d", __func__, channel);
+ status = -EINVAL;
+ break;
+ }
+
+ dp_fx::DPMbcBand mbcBand;
+ mbcBand.init(enabled != 0, cutoffFrequency, attackTime, releaseTime, ratio, threshold,
+ kneeWidth, noiseGateThreshold, expanderRatio, preGain, postGain);
+ pMbc->setBand(band, mbcBand);
+ break;
+ }
+ case DP_PARAM_LIMITER: {
+ ALOGVV("engine DP_PARAM_LIMITER paramsize: %d valuesize %d",paramSize, valueSize);
+ if (!DP_checkSizesInt(paramSize, valueSize, 2 /*params*/, 8 /*values*/)) {
+ ALOGE("%s DP_PARAM_LIMITER (cmd %d) invalid sizes.", __func__, command);
+ status = -EINVAL;
+ break;
+ }
+// Number[] params = { PARAM_LIMITER,
+// channelIndex};
+// Number[] values = {(limiter.isInUse() ? 1 : 0),
+// (limiter.isEnabled() ? 1 : 0),
+// limiter.getLinkGroup(),
+// limiter.getAttackTime(),
+// limiter.getReleaseTime(),
+// limiter.getRatio(),
+// limiter.getThreshold(),
+// limiter.getPostGain()};
+
+ const int32_t channel = params[1];
+
+ const int32_t inUse = values[0].i;
+ const int32_t enabled = values[1].i;
+ const int32_t linkGroup = values[2].i;
+ const float attackTime = values[3].f;
+ const float releaseTime = values[4].f;
+ const float ratio = values[5].f;
+ const float threshold = values[6].f;
+ const float postGain = values[7].f;
+
+ ALOGVV(" Limiter channel: %d, inUse::%d, enabled:%d, linkgroup:%d attackTime:%f,"
+ "releaseTime:%f, ratio:%f, threshold:%f, postGain:%f\n", channel, inUse,
+ enabled, linkGroup, attackTime, releaseTime, ratio, threshold, postGain);
+
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ ALOGE("%s DP_PARAM_LIMITER invalid channel %d", __func__, channel);
+ status = -EINVAL;
+ break;
+ }
+ dp_fx::DPLimiter limiter;
+ limiter.init(inUse != 0, enabled != 0, linkGroup, attackTime, releaseTime, ratio,
+ threshold, postGain);
+ pChannel->setLimiter(limiter);
+ break;
+ }
+ default:
+ ALOGE("%s invalid param %d", __func__, params[0]);
+ status = -EINVAL;
+ break;
+ }
+
+ ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
+ return status;
+} /* end DP_setParameter */
+
+/* Effect Control Interface Implementation: get_descriptor */
+int DP_getDescriptor(effect_handle_t self,
+ effect_descriptor_t *pDescriptor)
+{
+ DynamicsProcessingContext * pContext = (DynamicsProcessingContext *) self;
+
+ if (pContext == NULL || pDescriptor == NULL) {
+ ALOGE("DP_getDescriptor() invalid param");
+ return -EINVAL;
+ }
+
+ *pDescriptor = gDPDescriptor;
+
+ return 0;
+} /* end DP_getDescriptor */
+
+
+// effect_handle_t interface implementation for Dynamics Processing effect
+const struct effect_interface_s gDPInterface = {
+ DP_process,
+ DP_command,
+ DP_getDescriptor,
+ NULL,
+};
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+ .tag = AUDIO_EFFECT_LIBRARY_TAG,
+ .version = EFFECT_LIBRARY_API_VERSION,
+ .name = "Dynamics Processing Library",
+ .implementor = "The Android Open Source Project",
+ .create_effect = DPLib_Create,
+ .release_effect = DPLib_Release,
+ .get_descriptor = DPLib_GetDescriptor,
+};
+
+}; // extern "C"
+
diff --git a/media/libeffects/dynamicsproc/MODULE_LICENSE_APACHE2 b/media/libeffects/dynamicsproc/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libeffects/dynamicsproc/MODULE_LICENSE_APACHE2
diff --git a/media/libeffects/dynamicsproc/NOTICE b/media/libeffects/dynamicsproc/NOTICE
new file mode 100644
index 0000000..31cc6e9
--- /dev/null
+++ b/media/libeffects/dynamicsproc/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2018, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.cpp b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
new file mode 100644
index 0000000..30c2c36
--- /dev/null
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2018 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 <android/log.h>
+#include "DPBase.h"
+
+namespace dp_fx {
+
+DPStage::DPStage() : mInUse(DP_DEFAULT_STAGE_INUSE),
+ mEnabled(DP_DEFAULT_STAGE_ENABLED) {
+}
+
+void DPStage::init(bool inUse, bool enabled) {
+ mInUse = inUse;
+ mEnabled = enabled;
+}
+
+//----
+DPBandStage::DPBandStage() : mBandCount(0) {
+}
+
+void DPBandStage::init(bool inUse, bool enabled, int bandCount) {
+ DPStage::init(inUse, enabled);
+ mBandCount = inUse ? bandCount : 0;
+}
+
+//---
+DPBandBase::DPBandBase() {
+ init(DP_DEFAULT_BAND_ENABLED,
+ DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ);
+}
+
+void DPBandBase::init(bool enabled, float cutoffFrequency){
+ mEnabled = enabled;
+ mCutoofFrequencyHz = cutoffFrequency;
+}
+
+//-----
+DPEqBand::DPEqBand() {
+ init(DP_DEFAULT_BAND_ENABLED,
+ DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ,
+ DP_DEFAULT_GAIN_DB);
+}
+
+void DPEqBand::init(bool enabled, float cutoffFrequency, float gain) {
+ DPBandBase::init(enabled, cutoffFrequency);
+ setGain(gain);
+}
+
+float DPEqBand::getGain() const{
+ return mGainDb;
+}
+
+void DPEqBand::setGain(float gain) {
+ mGainDb = gain;
+}
+
+//------
+DPMbcBand::DPMbcBand() {
+ init(DP_DEFAULT_BAND_ENABLED,
+ DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ,
+ DP_DEFAULT_ATTACK_TIME_MS,
+ DP_DEFAULT_RELEASE_TIME_MS,
+ DP_DEFAULT_RATIO,
+ DP_DEFAULT_THRESHOLD_DB,
+ DP_DEFAULT_KNEE_WIDTH_DB,
+ DP_DEFAULT_NOISE_GATE_THRESHOLD_DB,
+ DP_DEFAULT_EXPANDER_RATIO,
+ DP_DEFAULT_GAIN_DB,
+ DP_DEFAULT_GAIN_DB);
+}
+
+void DPMbcBand::init(bool enabled, float cutoffFrequency, float attackTime, float releaseTime,
+ float ratio, float threshold, float kneeWidth, float noiseGateThreshold,
+ float expanderRatio, float preGain, float postGain) {
+ DPBandBase::init(enabled, cutoffFrequency);
+ setAttackTime(attackTime);
+ setReleaseTime(releaseTime);
+ setRatio(ratio);
+ setThreshold(threshold);
+ setKneeWidth(kneeWidth);
+ setNoiseGateThreshold(noiseGateThreshold);
+ setExpanderRatio(expanderRatio);
+ setPreGain(preGain);
+ setPostGain(postGain);
+}
+
+//------
+DPEq::DPEq() {
+}
+
+void DPEq::init(bool inUse, bool enabled, uint32_t bandCount) {
+ DPBandStage::init(inUse, enabled, bandCount);
+ mBands.resize(getBandCount());
+}
+
+DPEqBand * DPEq::getBand(uint32_t band) {
+ if (band < getBandCount()) {
+ return &mBands[band];
+ }
+ return NULL;
+}
+
+void DPEq::setBand(uint32_t band, DPEqBand &src) {
+ if (band < getBandCount()) {
+ mBands[band] = src;
+ }
+}
+
+//------
+DPMbc::DPMbc() {
+}
+
+void DPMbc::init(bool inUse, bool enabled, uint32_t bandCount) {
+ DPBandStage::init(inUse, enabled, bandCount);
+ if (isInUse()) {
+ mBands.resize(bandCount);
+ } else {
+ mBands.resize(0);
+ }
+}
+
+DPMbcBand * DPMbc::getBand(uint32_t band) {
+ if (band < getBandCount()) {
+ return &mBands[band];
+ }
+ return NULL;
+}
+
+void DPMbc::setBand(uint32_t band, DPMbcBand &src) {
+ if (band < getBandCount()) {
+ mBands[band] = src;
+ }
+}
+
+//------
+DPLimiter::DPLimiter() {
+ init(DP_DEFAULT_STAGE_INUSE,
+ DP_DEFAULT_STAGE_ENABLED,
+ DP_DEFAULT_LINK_GROUP,
+ DP_DEFAULT_ATTACK_TIME_MS,
+ DP_DEFAULT_RELEASE_TIME_MS,
+ DP_DEFAULT_RATIO,
+ DP_DEFAULT_THRESHOLD_DB,
+ DP_DEFAULT_GAIN_DB);
+}
+
+void DPLimiter::init(bool inUse, bool enabled, uint32_t linkGroup, float attackTime, float releaseTime,
+ float ratio, float threshold, float postGain) {
+ DPStage::init(inUse, enabled);
+ setLinkGroup(linkGroup);
+ setAttackTime(attackTime);
+ setReleaseTime(releaseTime);
+ setRatio(ratio);
+ setThreshold(threshold);
+ setPostGain(postGain);
+}
+
+//----
+DPChannel::DPChannel() : mInitialized(false), mInputGainDb(0), mPreEqInUse(false), mMbcInUse(false),
+ mPostEqInUse(false), mLimiterInUse(false) {
+}
+
+void DPChannel::init(float inputGain, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse) {
+ setInputGain(inputGain);
+ mPreEqInUse = preEqInUse;
+ mMbcInUse = mbcInUse;
+ mPostEqInUse = postEqInUse;
+ mLimiterInUse = limiterInUse;
+
+ mPreEq.init(mPreEqInUse, false, preEqBandCount);
+ mMbc.init(mMbcInUse, false, mbcBandCount);
+ mPostEq.init(mPostEqInUse, false, postEqBandCount);
+ mLimiter.init(mLimiterInUse, false, 0, 50, 120, 2, -30, 0);
+ mInitialized = true;
+}
+
+DPEq* DPChannel::getPreEq() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mPreEq;
+}
+
+DPMbc* DPChannel::getMbc() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mMbc;
+}
+
+DPEq* DPChannel::getPostEq() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mPostEq;
+}
+
+DPLimiter* DPChannel::getLimiter() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mLimiter;
+}
+
+void DPChannel::setLimiter(DPLimiter &limiter) {
+ if (!mInitialized) {
+ return;
+ }
+ mLimiter = limiter;
+}
+
+//----
+DPBase::DPBase() : mInitialized(false), mChannelCount(0), mPreEqInUse(false), mPreEqBandCount(0),
+ mMbcInUse(false), mMbcBandCount(0), mPostEqInUse(false), mPostEqBandCount(0),
+ mLimiterInUse(false) {
+}
+
+void DPBase::init(uint32_t channelCount, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse) {
+ mChannelCount = channelCount;
+ mPreEqInUse = preEqInUse;
+ mPreEqBandCount = preEqBandCount;
+ mMbcInUse = mbcInUse;
+ mMbcBandCount = mbcBandCount;
+ mPostEqInUse = postEqInUse;
+ mPostEqBandCount = postEqBandCount;
+ mLimiterInUse = limiterInUse;
+ mChannel.resize(mChannelCount);
+ for (size_t ch = 0; ch < mChannelCount; ch++) {
+ mChannel[ch].init(0, preEqInUse, preEqBandCount, mbcInUse, mbcBandCount,
+ postEqInUse, postEqBandCount, limiterInUse);
+ }
+ mInitialized = true;
+}
+
+void DPBase::reset() {
+ //perform reset operations with current architecture.
+}
+
+size_t DPBase::processSamples(float *in, float *out, size_t samples) {
+ //actually do something with samples, for now, just apply level.
+ uint32_t channelCount = getChannelCount();
+ std::vector<float> level(channelCount);
+ for (uint32_t ch = 0; ch < channelCount; ch++) {
+ DPChannel *pChannel = getChannel(ch);
+ if (pChannel != NULL) {
+ level[ch] = pow(10, pChannel->getInputGain() / 20.0);
+ }
+ }
+ size_t processedSamples = 0;
+ float *pInput = in;
+ float *pOutput = out;
+ for (size_t k = 0; k < samples; k++) {
+ float value = *pInput++;
+ *pOutput++ = value * level[k % channelCount];
+ processedSamples++;
+ }
+ return processedSamples;
+}
+
+DPChannel* DPBase::getChannel(uint32_t channelIndex) {
+ if (!mInitialized || channelIndex < 0 || channelIndex >= mChannel.size()) {
+ return NULL;
+ }
+ return & mChannel[channelIndex];
+}
+
+} //namespace dp_fx
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.h b/media/libeffects/dynamicsproc/dsp/DPBase.h
new file mode 100644
index 0000000..52593ef
--- /dev/null
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2018 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 <stdint.h>
+#include <cmath>
+#include <vector>
+#include <android/log.h>
+
+namespace dp_fx {
+
+#define DP_DEFAULT_BAND_ENABLED false
+#define DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ 1000
+#define DP_DEFAULT_ATTACK_TIME_MS 50
+#define DP_DEFAULT_RELEASE_TIME_MS 120
+#define DP_DEFAULT_RATIO 2
+#define DP_DEFAULT_THRESHOLD_DB -30
+#define DP_DEFAULT_KNEE_WIDTH_DB 0
+#define DP_DEFAULT_NOISE_GATE_THRESHOLD_DB -90
+#define DP_DEFAULT_EXPANDER_RATIO 1
+#define DP_DEFAULT_GAIN_DB 0
+#define DP_DEFAULT_STAGE_INUSE false
+#define DP_DEFAULT_STAGE_ENABLED false
+#define DP_DEFAULT_LINK_GROUP 0
+
+
+
+class DPStage {
+public:
+ DPStage();
+ ~DPStage() = default;
+ void init(bool inUse, bool enabled);
+ bool isInUse() const {
+ return mInUse;
+ }
+ bool isEnabled() const {
+ return mEnabled;
+ }
+ void setEnabled(bool enabled) {
+ mEnabled = enabled;
+ }
+private:
+ bool mInUse;
+ bool mEnabled;
+};
+
+class DPBandStage : public DPStage {
+public:
+ DPBandStage();
+ ~DPBandStage() = default;
+ void init(bool inUse, bool enabled, int bandCount);
+ uint32_t getBandCount() const {
+ return mBandCount;
+ }
+ void setBandCount(uint32_t bandCount) {
+ mBandCount = bandCount;
+ }
+private:
+ uint32_t mBandCount;
+};
+
+class DPBandBase {
+public:
+ DPBandBase();
+ ~DPBandBase() = default;
+ void init(bool enabled, float cutoffFrequency);
+ bool isEnabled() const {
+ return mEnabled;
+ }
+ void setEnabled(bool enabled) {
+ mEnabled = enabled;
+ }
+ float getCutoffFrequency() const {
+ return mCutoofFrequencyHz;
+ }
+ void setCutoffFrequency(float cutoffFrequency) {
+ mCutoofFrequencyHz = cutoffFrequency;
+ }
+private:
+ bool mEnabled;
+ float mCutoofFrequencyHz;
+};
+
+class DPEqBand : public DPBandBase {
+public:
+ DPEqBand();
+ ~DPEqBand() = default;
+ void init(bool enabled, float cutoffFrequency, float gain);
+ float getGain() const;
+ void setGain(float gain);
+private:
+ float mGainDb;
+};
+
+class DPMbcBand : public DPBandBase {
+public:
+ DPMbcBand();
+ ~DPMbcBand() = default;
+ void init(bool enabled, float cutoffFrequency, float attackTime, float releaseTime,
+ float ratio, float threshold, float kneeWidth, float noiseGateThreshold,
+ float expanderRatio, float preGain, float postGain);
+ float getAttackTime() const {
+ return mAttackTimeMs;
+ }
+ void setAttackTime(float attackTime) {
+ mAttackTimeMs = attackTime;
+ }
+ float getReleaseTime() const {
+ return mReleaseTimeMs;
+ }
+ void setReleaseTime(float releaseTime) {
+ mReleaseTimeMs = releaseTime;
+ }
+ float getRatio() const {
+ return mRatio;
+ }
+ void setRatio(float ratio) {
+ mRatio = ratio;
+ }
+ float getThreshold() const {
+ return mThresholdDb;
+ }
+ void setThreshold(float threshold) {
+ mThresholdDb = threshold;
+ }
+ float getKneeWidth() const {
+ return mKneeWidthDb;
+ }
+ void setKneeWidth(float kneeWidth) {
+ mKneeWidthDb = kneeWidth;
+ }
+ float getNoiseGateThreshold() const {
+ return mNoiseGateThresholdDb;
+ }
+ void setNoiseGateThreshold(float noiseGateThreshold) {
+ mNoiseGateThresholdDb = noiseGateThreshold;
+ }
+ float getExpanderRatio() const {
+ return mExpanderRatio;
+ }
+ void setExpanderRatio(float expanderRatio) {
+ mExpanderRatio = expanderRatio;
+ }
+ float getPreGain() const {
+ return mPreGainDb;
+ }
+ void setPreGain(float preGain) {
+ mPreGainDb = preGain;
+ }
+ float getPostGain() const {
+ return mPostGainDb;
+ }
+ void setPostGain(float postGain) {
+ mPostGainDb = postGain;
+ }
+private:
+ float mAttackTimeMs;
+ float mReleaseTimeMs;
+ float mRatio;
+ float mThresholdDb;
+ float mKneeWidthDb;
+ float mNoiseGateThresholdDb;
+ float mExpanderRatio;
+ float mPreGainDb;
+ float mPostGainDb;
+};
+
+class DPEq : public DPBandStage {
+public:
+ DPEq();
+ ~DPEq() = default;
+ void init(bool inUse, bool enabled, uint32_t bandCount);
+ DPEqBand * getBand(uint32_t band);
+ void setBand(uint32_t band, DPEqBand &src);
+private:
+ std::vector<DPEqBand> mBands;
+};
+
+class DPMbc : public DPBandStage {
+public:
+ DPMbc();
+ ~DPMbc() = default;
+ void init(bool inUse, bool enabled, uint32_t bandCount);
+ DPMbcBand * getBand(uint32_t band);
+ void setBand(uint32_t band, DPMbcBand &src);
+private:
+ std::vector<DPMbcBand> mBands;
+};
+
+class DPLimiter : public DPStage {
+public:
+ DPLimiter();
+ ~DPLimiter() = default;
+ void init(bool inUse, bool enabled, uint32_t linkGroup, float attackTime, float releaseTime,
+ float ratio, float threshold, float postGain);
+ uint32_t getLinkGroup() const {
+ return mLinkGroup;
+ }
+ void setLinkGroup(uint32_t linkGroup) {
+ mLinkGroup = linkGroup;
+ }
+ float getAttackTime() const {
+ return mAttackTimeMs;
+ }
+ void setAttackTime(float attackTime) {
+ mAttackTimeMs = attackTime;
+ }
+ float getReleaseTime() const {
+ return mReleaseTimeMs;
+ }
+ void setReleaseTime(float releaseTime) {
+ mReleaseTimeMs = releaseTime;
+ }
+ float getRatio() const {
+ return mRatio;
+ }
+ void setRatio(float ratio) {
+ mRatio = ratio;
+ }
+ float getThreshold() const {
+ return mThresholdDb;
+ }
+ void setThreshold(float threshold) {
+ mThresholdDb = threshold;
+ }
+ float getPostGain() const {
+ return mPostGainDb;
+ }
+ void setPostGain(float postGain) {
+ mPostGainDb = postGain;
+ }
+private:
+ uint32_t mLinkGroup;
+ float mAttackTimeMs;
+ float mReleaseTimeMs;
+ float mRatio;
+ float mThresholdDb;
+ float mPostGainDb;
+};
+
+class DPChannel {
+public:
+ DPChannel();
+ ~DPChannel() = default;
+ void init(float inputGain, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse);
+
+ float getInputGain() const {
+ if (!mInitialized) {
+ return 0;
+ }
+ return mInputGainDb;
+ }
+ void setInputGain(float gain) {
+ mInputGainDb = gain;
+ }
+
+ DPEq* getPreEq();
+ DPMbc* getMbc();
+ DPEq* getPostEq();
+ DPLimiter *getLimiter();
+ void setLimiter(DPLimiter &limiter);
+
+private:
+ bool mInitialized;
+ float mInputGainDb;
+
+ DPEq mPreEq;
+ DPMbc mMbc;
+ DPEq mPostEq;
+ DPLimiter mLimiter;
+
+ bool mPreEqInUse;
+ bool mMbcInUse;
+ bool mPostEqInUse;
+ bool mLimiterInUse;
+};
+
+class DPBase {
+public:
+ DPBase();
+ virtual ~DPBase() = default;
+
+ void init(uint32_t channelCount, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse);
+ virtual size_t processSamples(float *in, float *out, size_t samples);
+ virtual void reset();
+
+ DPChannel* getChannel(uint32_t channelIndex);
+ uint32_t getChannelCount() const {
+ return mChannelCount;
+ }
+ uint32_t getPreEqBandCount() const {
+ return mPreEqBandCount;
+ }
+ uint32_t getMbcBandCount() const {
+ return mMbcBandCount;
+ }
+ uint32_t getPostEqBandCount() const {
+ return mPostEqBandCount;
+ }
+ bool isPreEQInUse() const {
+ return mPreEqInUse;
+ }
+ bool isMbcInUse() const {
+ return mMbcInUse;
+ }
+ bool isPostEqInUse() const {
+ return mPostEqInUse;
+ }
+ bool isLimiterInUse() const {
+ return mLimiterInUse;
+ }
+
+private:
+ bool mInitialized;
+ //general
+ uint32_t mChannelCount;
+ bool mPreEqInUse;
+ uint32_t mPreEqBandCount;
+ bool mMbcInUse;
+ uint32_t mMbcBandCount;
+ bool mPostEqInUse;
+ uint32_t mPostEqBandCount;
+ bool mLimiterInUse;
+
+ std::vector<DPChannel> mChannel;
+};
+
+} //namespace dp_fx