libeffects: Added multichannel support for volume balance
Test: local native test (lvmtest)
Bug: 120941390
Change-Id: If982e03a57fb3a1e03d67f531c615bc016e7f3a5
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index 7a32d3f..d150f18 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -132,6 +132,9 @@
shared_libs: [
"liblog",
],
+ header_libs: [
+ "libhardware_headers"
+ ],
cflags: [
"-fvisibility=hidden",
"-DBUILD_FLOAT",
diff --git a/media/libeffects/lvm/lib/Bundle/lib/LVM.h b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
index 83ecae1..5082a53 100644
--- a/media/libeffects/lvm/lib/Bundle/lib/LVM.h
+++ b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
@@ -298,6 +298,7 @@
LVM_PSA_DecaySpeed_en PSA_PeakDecayRate; /* Peak value decay rate*/
#ifdef SUPPORT_MC
LVM_INT32 NrChannels;
+ LVM_INT32 ChMask;
#endif
} LVM_ControlParams_t;
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
index 62b4c73..1d95342 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
@@ -93,6 +93,7 @@
#ifdef SUPPORT_MC
pInstance->Params.NrChannels = pParams->NrChannels;
+ pInstance->Params.ChMask = pParams->ChMask;
#endif
/*
* Cinema Sound parameters
@@ -584,6 +585,7 @@
#ifdef SUPPORT_MC
pInstance->NrChannels = LocalParams.NrChannels;
+ pInstance->ChMask = LocalParams.ChMask;
#endif
/* Clear all internal data if format change*/
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
index 19d1532..cdd3134 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
@@ -291,6 +291,7 @@
#ifdef SUPPORT_MC
LVM_INT16 NrChannels;
+ LVM_INT32 ChMask;
#endif
} LVM_Instance_t;
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
index 94ba278..8d30a61 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
@@ -21,6 +21,7 @@
/* Includes */
/* */
/****************************************************************************************/
+#include <system/audio.h>
#include "LVM_Private.h"
#include "VectorArithmetic.h"
@@ -67,6 +68,7 @@
LVM_ReturnStatus_en Status;
#ifdef SUPPORT_MC
LVM_INT32 NrChannels = pInstance->NrChannels;
+ LVM_INT32 ChMask = pInstance->ChMask;
#define NrFrames SampleCount // alias for clarity
#endif
@@ -119,6 +121,7 @@
#ifdef SUPPORT_MC
/* Update the local variable NrChannels from pInstance->NrChannels value */
NrChannels = pInstance->NrChannels;
+ ChMask = pInstance->ChMask;
#endif
if(Status != LVM_SUCCESS)
@@ -140,6 +143,7 @@
pToProcess = pOutData;
#ifdef SUPPORT_MC
NrChannels = 2;
+ ChMask = AUDIO_CHANNEL_OUT_STEREO;
#endif
}
@@ -254,18 +258,24 @@
}
#ifdef SUPPORT_MC
- /* TODO - Multichannel support to be added */
- if (NrChannels == 2)
+ /*
+ * Volume balance
+ */
+ LVC_MixSoft_1St_MC_float_SAT(&pInstance->VC_BalanceMix,
+ pProcessed,
+ pProcessed,
+ NrFrames,
+ NrChannels,
+ ChMask);
+#else
+ /*
+ * Volume balance
+ */
+ LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
+ pProcessed,
+ pProcessed,
+ SampleCount);
#endif
- {
- /*
- * Volume balance
- */
- LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
- pProcessed,
- pProcessed,
- SampleCount);
- }
/*
* Perform Parametric Spectum Analysis
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
index eb5755e..db76cd1 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c
@@ -59,6 +59,31 @@
}
+#ifdef SUPPORT_MC
+void LVC_Core_MixHard_1St_MC_float_SAT (Mix_Private_FLOAT_st **ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ LVM_FLOAT Temp;
+ LVM_INT16 ii, jj;
+ for (ii = NrFrames; ii != 0; ii--)
+ {
+ for (jj = 0; jj < NrChannels; jj++)
+ {
+ Mix_Private_FLOAT_st *pInstance1 = (Mix_Private_FLOAT_st *)(ptrInstance[jj]);
+ Temp = ((LVM_FLOAT)*(src++) * (LVM_FLOAT)pInstance1->Current);
+ if (Temp > 1.0f)
+ *dst++ = 1.0f;
+ else if (Temp < -1.0f)
+ *dst++ = -1.0f;
+ else
+ *dst++ = (LVM_FLOAT)Temp;
+ }
+ }
+}
+#endif
#else
void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_st *ptrInstance1,
LVMixer3_st *ptrInstance2,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
index 656a117..56b5dae 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c
@@ -146,6 +146,51 @@
pInstanceR->Current = CurrentR;
}
+#ifdef SUPPORT_MC
+void LVC_Core_MixSoft_1St_MC_float_WRA (Mix_Private_FLOAT_st **ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels)
+{
+ LVM_INT32 ii, ch;
+ LVM_FLOAT Temp =0.0f;
+ LVM_FLOAT tempCurrent[NrChannels];
+ for (ch = 0; ch < NrChannels; ch++)
+ {
+ tempCurrent[ch] = ptrInstance[ch]->Current;
+ }
+ for (ii = NrFrames; ii > 0; ii--)
+ {
+ for (ch = 0; ch < NrChannels; ch++)
+ {
+ Mix_Private_FLOAT_st *pInstance = ptrInstance[ch];
+ const LVM_FLOAT Delta = pInstance->Delta;
+ LVM_FLOAT Current = tempCurrent[ch];
+ const LVM_FLOAT Target = pInstance->Target;
+ if (Current < Target)
+ {
+ ADD2_SAT_FLOAT(Current, Delta, Temp);
+ Current = Temp;
+ if (Current > Target)
+ Current = Target;
+ }
+ else
+ {
+ Current -= Delta;
+ if (Current < Target)
+ Current = Target;
+ }
+ *dst++ = *src++ * Current;
+ tempCurrent[ch] = Current;
+ }
+ }
+ for (ch = 0; ch < NrChannels; ch++)
+ {
+ ptrInstance[ch]->Current = tempCurrent[ch];
+ }
+}
+#endif
#else
void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_st *ptrInstance1,
LVMixer3_st *ptrInstance2,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
index bd5a925..a4682d3 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c
@@ -19,6 +19,8 @@
INCLUDE FILES
***********************************************************************************/
+#include <system/audio.h>
+
#include "LVC_Mixer_Private.h"
#include "VectorArithmetic.h"
#include "ScalarArithmetic.h"
@@ -30,10 +32,207 @@
#define TRUE 1
#define FALSE 0
+#define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(*(a))))
+
/**********************************************************************************
FUNCTION LVC_MixSoft_1St_2i_D16C31_SAT
***********************************************************************************/
#ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+/* This threshold is used to decide on the processing to be applied on
+ * front center and back center channels
+ */
+#define LVM_VOL_BAL_THR (0.000016f)
+void LVC_MixSoft_1St_MC_float_SAT (LVMixer3_2St_FLOAT_st *ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT32 NrChannels,
+ LVM_INT32 ChMask)
+{
+ char HardMixing = TRUE;
+ LVM_FLOAT TargetGain;
+ Mix_Private_FLOAT_st Target_lfe = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
+ Mix_Private_FLOAT_st Target_ctr = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
+ Mix_Private_FLOAT_st *pInstance1 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+ Mix_Private_FLOAT_st *pInstance2 = \
+ (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
+ Mix_Private_FLOAT_st *pMixPrivInst[4] = {pInstance1, pInstance2, &Target_ctr, &Target_lfe};
+ Mix_Private_FLOAT_st *pInstance[NrChannels];
+
+ if (audio_channel_mask_get_representation(ChMask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ pInstance[i] = pMixPrivInst[i];
+ }
+ for (int i = 2; i < NrChannels; i++)
+ {
+ pInstance[i] = pMixPrivInst[2];
+ }
+ }
+ else
+ {
+ // TODO: Combine with system/media/audio_utils/Balance.cpp
+ // Constants in system/media/audio/include/system/audio-base.h
+ // 'mixInstIdx' is used to map the appropriate mixer instance for each channel.
+ const int mixInstIdx[] = {
+ 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u,
+ 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u,
+ 2, // AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u,
+ 3, // AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u,
+ 0, // AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u,
+ 1, // AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u,
+ 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u,
+ 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
+ 2, // AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u,
+ 0, // AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u,
+ 1, // AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u,
+ 2, // AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u,
+ 0, // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u,
+ 2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u,
+ 1, // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u,
+ 0, // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u,
+ 2, // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u,
+ 1, // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u,
+ 0, // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u,
+ 1, // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u
+ };
+ if (pInstance1->Target <= LVM_VOL_BAL_THR ||
+ pInstance2->Target <= LVM_VOL_BAL_THR)
+ {
+ Target_ctr.Target = 0.0f;
+ Target_ctr.Current = 0.0f;
+ Target_ctr.Delta = 0.0f;
+ }
+ const unsigned int idxArrSize = ARRAY_SIZE(mixInstIdx);
+ for (unsigned int i = 0, channel = ChMask; channel !=0 ; ++i)
+ {
+ const unsigned int idx = __builtin_ctz(channel);
+ if (idx < idxArrSize)
+ {
+ pInstance[i] = pMixPrivInst[mixInstIdx[idx]];
+ }
+ else
+ {
+ pInstance[i] = pMixPrivInst[2];
+ }
+ channel &= ~(1 << idx);
+ }
+ }
+
+ if (NrFrames <= 0) return;
+
+ /******************************************************************************
+ SOFT MIXING
+ *******************************************************************************/
+
+ if ((pInstance1->Current != pInstance1->Target) ||
+ (pInstance2->Current != pInstance2->Target))
+ {
+ // TODO: combine similar checks below.
+ if (pInstance1->Delta == LVM_MAXFLOAT
+ || Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ /* Difference is not significant anymore. Make them equal. */
+ pInstance1->Current = pInstance1->Target;
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+
+ if (HardMixing == TRUE)
+ {
+ if (pInstance2->Delta == LVM_MAXFLOAT
+ || Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ /* Difference is not significant anymore. Make them equal. */
+ pInstance2->Current = pInstance2->Target;
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
+ }
+ else
+ {
+ /* Soft mixing has to be applied */
+ HardMixing = FALSE;
+ }
+ }
+
+ if (HardMixing == FALSE)
+ {
+ LVC_Core_MixSoft_1St_MC_float_WRA (&pInstance[0],
+ src, dst, NrFrames, NrChannels);
+ }
+ }
+
+ /******************************************************************************
+ HARD MIXING
+ *******************************************************************************/
+
+ if (HardMixing == TRUE)
+ {
+ if ((pInstance1->Target == LVM_MAXFLOAT) && (pInstance2->Target == LVM_MAXFLOAT))
+ {
+ if (src != dst)
+ {
+ Copy_Float(src, dst, NrFrames*NrChannels);
+ }
+ }
+ else
+ {
+ LVC_Core_MixHard_1St_MC_float_SAT(&(pInstance[0]),
+ src, dst, NrFrames, NrChannels);
+ }
+ }
+
+ /******************************************************************************
+ CALL BACK
+ *******************************************************************************/
+
+ if (ptrInstance->MixerStream[0].CallbackSet)
+ {
+ if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
+ {
+ pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
+ Make them equal. */
+ TargetGain = pInstance1->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
+ ptrInstance->MixerStream[0].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[0].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[0].pCallBack) (\
+ ptrInstance->MixerStream[0].pCallbackHandle,
+ ptrInstance->MixerStream[0].pGeneralPurpose,
+ ptrInstance->MixerStream[0].CallbackParam);
+ }
+ }
+ }
+ if (ptrInstance->MixerStream[1].CallbackSet)
+ {
+ if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
+ {
+ pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
+ Make them equal. */
+ TargetGain = pInstance2->Target;
+ LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
+ ptrInstance->MixerStream[1].CallbackSet = FALSE;
+ if (ptrInstance->MixerStream[1].pCallBack != 0)
+ {
+ (*ptrInstance->MixerStream[1].pCallBack) (\
+ ptrInstance->MixerStream[1].pCallbackHandle,
+ ptrInstance->MixerStream[1].pGeneralPurpose,
+ ptrInstance->MixerStream[1].CallbackParam);
+ }
+ }
+ }
+}
+#endif
void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
const LVM_FLOAT *src,
LVM_FLOAT *dst,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
index 7f18747..199d529 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
@@ -224,6 +224,14 @@
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
#ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+void LVC_MixSoft_1St_MC_float_SAT(LVMixer3_2St_FLOAT_st *pInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst, /* dst can be equal to src */
+ LVM_INT16 NrFrames,
+ LVM_INT32 NrChannels,
+ LVM_INT32 ChMask);
+#endif
void LVC_MixSoft_1St_2i_D16C31_SAT(LVMixer3_2St_FLOAT_st *pInstance,
const LVM_FLOAT *src,
LVM_FLOAT *dst, /* dst can be equal to src */
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
index f10094b..453a6a5 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
@@ -116,6 +116,13 @@
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
#ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+void LVC_Core_MixSoft_1St_MC_float_WRA(Mix_Private_FLOAT_st **ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels);
+#endif
void LVC_Core_MixSoft_1St_2i_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance1,
LVMixer3_FLOAT_st *ptrInstance2,
const LVM_FLOAT *src,
@@ -136,6 +143,13 @@
/* Gain values should not be more that 1.0 */
/**********************************************************************************/
#ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+void LVC_Core_MixHard_1St_MC_float_SAT(Mix_Private_FLOAT_st **ptrInstance,
+ const LVM_FLOAT *src,
+ LVM_FLOAT *dst,
+ LVM_INT16 NrFrames,
+ LVM_INT16 NrChannels);
+#endif
void LVC_Core_MixHard_1St_2i_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance1,
LVMixer3_FLOAT_st *ptrInstance2,
const LVM_FLOAT *src,