libeffects: Add multichannel processing support

Multichannel processing support added for Bundled effects including

Bass Enhancement (DBE)
N Band Equalizer (EQNB)
Concert Surround / Stereo Widening (CS)
Parametric Spectrum Analysis (PSA)
DC removal
Treble Boost

Test: Solo Tester, CTS Effects Test, Local Native Test
Bug: 72223862
Change-Id: Ide86b529a7574c26306098fedd7b276b3688998f
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index 5c57c43..7a32d3f 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -129,11 +129,14 @@
         "Common/lib",
         "Bundle/lib",
     ],
-
+    shared_libs: [
+        "liblog",
+    ],
     cflags: [
         "-fvisibility=hidden",
         "-DBUILD_FLOAT",
         "-DHIGHER_FS",
+        "-DSUPPORT_MC",
 
         "-Wall",
         "-Werror",
diff --git a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
index 4c2b954..a1fa79a 100644
--- a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
+++ b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
@@ -256,6 +256,9 @@
     LVDBE_Volume_en         VolumeControl;
     LVM_INT16               VolumedB;
     LVM_INT16               HeadroomdB;
+#ifdef SUPPORT_MC
+    LVM_INT16               NrChannels;
+#endif
 
 } LVDBE_Params_t;
 
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
index fd4016b..0ba2c86 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.c
@@ -118,7 +118,7 @@
      * Calculate the table offsets
      */
     LVM_UINT16 Offset = (LVM_UINT16)((LVM_UINT16)pParams->SampleRate + \
-                                    (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_48000)));    
+                                    (LVM_UINT16)(pParams->CentreFrequency * (1+LVDBE_FS_48000)));
 #endif
 
     /*
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
index 3fff2a2..2946734 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.c
@@ -95,7 +95,7 @@
 #ifdef BUILD_FLOAT
         pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size   = sizeof(LVDBE_Coef_FLOAT_t);
 #else
-        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size         = sizeof(LVDBE_Coef_t);   
+        pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size         = sizeof(LVDBE_Coef_t);
 #endif
         pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Alignment    = LVDBE_PERSISTENT_COEF_ALIGN;
         pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Type         = LVDBE_PERSISTENT_COEF;
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
index 4e5207f..4225a30 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
@@ -64,7 +64,12 @@
 #define LVDBE_PERSISTENT_COEF_ALIGN      4       /* 32-bit alignment for coef */
 #define LVDBE_SCRATCH_ALIGN              4       /* 32-bit alignment for long data */
 
+#ifdef SUPPORT_MC
+/* Number of buffers required for inplace processing */
+#define LVDBE_SCRATCHBUFFERS_INPLACE     (LVM_MAX_CHANNELS * 3)
+#else
 #define LVDBE_SCRATCHBUFFERS_INPLACE     6       /* Number of buffers required for inplace processing */
+#endif
 
 #define LVDBE_MIXER_TC                   5       /* Mixer time  */
 #define LVDBE_BYPASS_MIXER_TC            100     /* Bypass mixer time */
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
index 10ea700..c4d3403 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.c
@@ -21,11 +21,13 @@
 /*                                                                                      */
 /****************************************************************************************/
 
+#include <string.h> // memset
 #include "LVDBE.h"
 #include "LVDBE_Private.h"
 #include "VectorArithmetic.h"
 #include "AGC.h"
 #include "LVDBE_Coeffs.h"               /* Filter coefficients */
+#include <log/log.h>
 
 /********************************************************************************************/
 /*                                                                                          */
@@ -187,42 +189,49 @@
 LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
     const LVM_FLOAT *pInData,
     LVM_FLOAT *pOutData,
-    LVM_UINT16 NumSamples)
+    const LVM_UINT16 NrFrames) // updated to use samples = frames * channels.
 {
-
   LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
-  LVM_FLOAT *pScratch_in = (LVM_FLOAT *)pInstance->MemoryTable.Region
-  [LVDBE_MEMREGION_SCRATCH].pBaseAddress;
-  LVM_FLOAT *pScratch = pScratch_in + 2 * NumSamples;
-  LVM_FLOAT *pMono;
-  LVM_INT32 ii = 0;
 
-  /* Scratch for Volume Control starts at offset of 4*NumSamples float values from pScratch */
-  LVM_FLOAT           *pScratchVol = (LVM_FLOAT *)(&pScratch_in[4 * NumSamples]);
-//  LVM_INT16 *pScratchVol_int = (LVM_INT16 *)(pScratchVol);
+  /*Extract number of Channels info*/
+#ifdef SUPPORT_MC
+  // Mono passed in as stereo
+  const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
+      ? 2 : pInstance->Params.NrChannels;
+#else
+  const LVM_INT32 NrChannels = 2; // FCC_2
+#endif
+  const LVM_INT32 NrSamples = NrChannels * NrFrames;
 
-  /* Scratch for Mono path starts at offset of 6*NumSamples 32-bit values from pScratch */
-  pMono = &pScratch_in[4 * NumSamples];
+  /* Space to store DBE path computation */
+  LVM_FLOAT * const pScratch =
+          (LVM_FLOAT *)pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
 
   /*
-   * Check the number of samples is not too large
+   * Scratch for Mono path starts at offset of
+   * NrSamples float values from pScratch.
    */
-  if (NumSamples > pInstance->Capabilities.MaxBlockSize)
+  LVM_FLOAT * const pMono = pScratch + NrSamples;
+
+  /*
+   * TRICKY: pMono is used and discarded by the DBE path.
+   *         so it is available for use for the pScratchVol
+   *         path which is computed afterwards.
+   *
+   * Space to store Volume Control path computation.
+   * This is identical to pMono (see TRICKY comment).
+   */
+  LVM_FLOAT * const pScratchVol = pMono;
+
+  /*
+   * Check the number of frames is not too large
+   */
+  if (NrFrames > pInstance->Capabilities.MaxBlockSize)
   {
-    return(LVDBE_TOOMANYSAMPLES);
+    return LVDBE_TOOMANYSAMPLES;
   }
 
   /*
-   * Convert 16-bit samples to Float
-   */
-  Copy_Float(pInData, /* Source 16-bit data    */
-      pScratch_in, /* Dest. 32-bit data     */
-      (LVM_INT16)(2 * NumSamples)); /* Left and right        */
-
-  for (ii = 0; ii < 2 * NumSamples; ii++) {
-    pScratch[ii] = pScratch_in[ii];
-  }
-  /*
    * Check if the algorithm is enabled
    */
   /* DBE path is processed when DBE is ON or during On/Off transitions */
@@ -230,50 +239,81 @@
       (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[0])
           !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[0])))
   {
+    // make copy of input data
+    Copy_Float(pInData,
+        pScratch,
+        (LVM_INT16)NrSamples);
 
     /*
      * Apply the high pass filter if selected
      */
     if (pInstance->Params.HPFSelect == LVDBE_HPF_ON)
     {
+#ifdef SUPPORT_MC
+      BQ_MC_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance, /* Filter instance      */
+          pScratch, /* Source               */
+          pScratch, /* Destination          */
+          (LVM_INT16)NrFrames,
+          (LVM_INT16)NrChannels);
+#else
       BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance      */
-          (LVM_FLOAT *)pScratch, /* Source               */
-          (LVM_FLOAT *)pScratch, /* Destination          */
-          (LVM_INT16)NumSamples); /* Number of samples    */
+          pScratch, /* Source               */
+          pScratch, /* Destination          */
+          (LVM_INT16)NrFrames);
+#endif
     }
 
     /*
      * Create the mono stream
      */
-    From2iToMono_Float((LVM_FLOAT *)pScratch, /* Stereo source         */
+#ifdef SUPPORT_MC
+    FromMcToMono_Float(pScratch, /* Source */
+        pMono, /* Mono destination */
+        (LVM_INT16)NrFrames,  /* Number of frames */
+        (LVM_INT16)NrChannels);
+#else
+    From2iToMono_Float(pScratch, /* Stereo source         */
         pMono, /* Mono destination      */
-        (LVM_INT16)NumSamples); /* Number of samples     */
+        (LVM_INT16)NrFrames);
+#endif
 
     /*
      * Apply the band pass filter
      */
     BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance       */
-        (LVM_FLOAT *)pMono, /* Source                */
-        (LVM_FLOAT *)pMono, /* Destination           */
-        (LVM_INT16)NumSamples); /* Number of samples     */
+        pMono, /* Source                */
+        pMono, /* Destination           */
+        (LVM_INT16)NrFrames);
 
     /*
      * Apply the AGC and mix
      */
+#ifdef SUPPORT_MC
+    AGC_MIX_VOL_Mc1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer      */
+        pScratch, /* Source         */
+        pMono, /* Mono band pass source */
+        pScratch, /* Destination    */
+        NrFrames, /* Number of frames     */
+        NrChannels); /* Number of channels     */
+#else
     AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer      */
         pScratch, /* Stereo source         */
         pMono, /* Mono band pass source */
         pScratch, /* Stereo destination    */
-        NumSamples); /* Number of samples     */
+        NrFrames);
+#endif
 
-    for (ii = 0; ii < 2 * NumSamples; ii++) {
+    for (LVM_INT32 ii = 0; ii < NrSamples; ++ii) {
       //TODO: replace with existing clamping function
-      if(pScratch[ii] < -1.0) {
+      if (pScratch[ii] < -1.0) {
         pScratch[ii] = -1.0;
-      } else if(pScratch[ii] > 1.0) {
+      } else if (pScratch[ii] > 1.0) {
         pScratch[ii] = 1.0;
       }
     }
+  } else {
+    // clear DBE processed path
+    memset(pScratch, 0, sizeof(*pScratch) * NrSamples);
   }
 
   /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
@@ -286,21 +326,40 @@
      * The algorithm is disabled but volume management is required to compensate for
      * headroom and volume (if enabled)
      */
-    LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume,
-        pScratch_in,
+#ifdef SUPPORT_MC
+    LVC_MixSoft_Mc_D16C31_SAT(&pInstance->pData->BypassVolume,
+        pInData,
         pScratchVol,
-        (LVM_INT16)(2 * NumSamples)); /* Left and right */
+        (LVM_INT16)NrFrames,
+        (LVM_INT16)NrChannels);
+#else
+    LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume,
+        pInData,
+        pScratchVol,
+        (LVM_INT16)NrSamples); /* Left and right, really # samples */
+#endif
+  } else {
+    // clear bypass volume path
+    memset(pScratchVol, 0, sizeof(*pScratchVol) * NrSamples);
   }
 
   /*
    * Mix DBE processed path and bypass volume path
    */
+#ifdef SUPPORT_MC
+  LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->pData->BypassMixer,
+      pScratch,
+      pScratchVol,
+      pOutData,
+      (LVM_INT16)NrFrames,
+      (LVM_INT16)NrChannels);
+#else
   LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
       pScratch,
       pScratchVol,
       pOutData,
-      (LVM_INT16)(2 * NumSamples));
-
-  return(LVDBE_SUCCESS);
+      (LVM_INT16)NrSamples);
+#endif
+  return LVDBE_SUCCESS;
 }
 #endif
diff --git a/media/libeffects/lvm/lib/Bundle/lib/LVM.h b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
index 9b6da31..83ecae1 100644
--- a/media/libeffects/lvm/lib/Bundle/lib/LVM.h
+++ b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
@@ -296,6 +296,9 @@
     /* Spectrum Analyzer parameters Control */
     LVM_PSA_Mode_en             PSA_Enable;
     LVM_PSA_DecaySpeed_en       PSA_PeakDecayRate;      /* Peak value decay rate*/
+#ifdef SUPPORT_MC
+    LVM_INT32                   NrChannels;
+#endif
 
 } LVM_ControlParams_t;
 
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
index 0a3c30e..37272e3 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.c
@@ -25,6 +25,8 @@
 #include "LVM_Private.h"
 #include "VectorArithmetic.h"
 
+#include <log/log.h>
+
 /****************************************************************************************/
 /*                                                                                      */
 /* FUNCTION:                 LVM_BufferManagedIn                                        */
@@ -62,8 +64,11 @@
     LVM_Instance_t   *pInstance = (LVM_Instance_t  *)hInstance;
     LVM_Buffer_t     *pBuffer;
     LVM_FLOAT        *pDest;
+#ifdef SUPPORT_MC
+    LVM_INT16        NumChannels = pInstance->NrChannels;
+#else
     LVM_INT16        NumChannels = 2;
-
+#endif
 
     /*
      * Set the processing address pointers
@@ -207,8 +212,7 @@
     LVM_Instance_t   *pInstance = (LVM_Instance_t  *)hInstance;
     LVM_Buffer_t     *pBuffer;
     LVM_INT16        *pDest;
-    LVM_INT16        NumChannels =2;
-
+    LVM_INT16        NumChannels = 2;
 
     /*
      * Set the processing address pointers
@@ -499,7 +503,7 @@
         if (pBuffer->OutDelaySamples != 0)
         {
             Copy_16(&pBuffer->OutDelayBuffer[0],                    /* Source */
-                    pDest,                                          /* Detsination */
+                    pDest,                                          /* Destination */
                     (LVM_INT16)(2*pBuffer->OutDelaySamples));       /* Number of delay samples */
             pDest += 2 * pBuffer->OutDelaySamples;                  /* Update the output pointer */
             pBuffer->SamplesToOutput = (LVM_INT16)(pBuffer->SamplesToOutput - pBuffer->OutDelaySamples); /* Update the numbr of samples to output */
@@ -750,7 +754,11 @@
     LVM_INT16       NumSamples;
     LVM_FLOAT       *pStart;
     LVM_FLOAT       *pDest;
-
+#ifdef SUPPORT_MC
+    LVM_INT32       NrChannels = pInstance->NrChannels;
+#define NrFrames NumSamples  // alias for clarity
+#define FrameCount SampleCount
+#endif
 
     /*
      * Set the pointers
@@ -758,7 +766,6 @@
     NumSamples = pBuffer->SamplesToOutput;
     pStart     = pBuffer->pScratch;
 
-
     /*
      * check if it is the first call of a block
       */
@@ -786,14 +793,25 @@
             /*
              * Copy all output delay samples to the output
              */
+#ifdef SUPPORT_MC
             Copy_Float(&pBuffer->OutDelayBuffer[0],                /* Source */
-                       pDest,                                      /* Detsination */
+                       pDest,                                      /* Destination */
+                       /* Number of delay samples */
+                       (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
+#else
+            Copy_Float(&pBuffer->OutDelayBuffer[0],                /* Source */
+                       pDest,                                      /* Destination */
                        (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of delay samples */
+#endif
 
             /*
              * Update the pointer and sample counts
              */
+#ifdef SUPPORT_MC
+            pDest += NrChannels * pBuffer->OutDelaySamples; /* Output sample pointer */
+#else
             pDest += 2 * pBuffer->OutDelaySamples; /* Output sample pointer */
+#endif
             NumSamples = (LVM_INT16)(NumSamples - pBuffer->OutDelaySamples); /* Samples left \
                                                                                 to send */
             pBuffer->OutDelaySamples = 0; /* No samples left in the buffer */
@@ -803,23 +821,40 @@
             /*
              * Copy only some of the ouput delay samples to the output
              */
+#ifdef SUPPORT_MC
             Copy_Float(&pBuffer->OutDelayBuffer[0],                    /* Source */
-                       pDest,                                          /* Detsination */
+                       pDest,                                          /* Destination */
+                       (LVM_INT16)(NrChannels * NrFrames));       /* Number of delay samples */
+#else
+            Copy_Float(&pBuffer->OutDelayBuffer[0],                    /* Source */
+                       pDest,                                          /* Destination */
                        (LVM_INT16)(2 * NumSamples));       /* Number of delay samples */
+#endif
 
             /*
              * Update the pointer and sample counts
              */
+#ifdef SUPPORT_MC
+            pDest += NrChannels * NrFrames; /* Output sample pointer */
+#else
             pDest += 2 * NumSamples; /* Output sample pointer */
+#endif
             /* No samples left in the buffer */
             pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples - NumSamples);
 
             /*
              * Realign the delay buffer data to avoid using circular buffer management
              */
+#ifdef SUPPORT_MC
+            Copy_Float(&pBuffer->OutDelayBuffer[NrChannels * NrFrames],         /* Source */
+                       &pBuffer->OutDelayBuffer[0],                    /* Destination */
+                       /* Number of samples to move */
+                       (LVM_INT16)(NrChannels * pBuffer->OutDelaySamples));
+#else
             Copy_Float(&pBuffer->OutDelayBuffer[2 * NumSamples],         /* Source */
                        &pBuffer->OutDelayBuffer[0],                    /* Destination */
                        (LVM_INT16)(2 * pBuffer->OutDelaySamples)); /* Number of samples to move */
+#endif
             NumSamples = 0;                                /* Samples left to send */
         }
     }
@@ -836,13 +871,23 @@
             /*
              * Copy all processed samples to the output
              */
+#ifdef SUPPORT_MC
             Copy_Float(pStart,                                      /* Source */
-                       pDest,                                       /* Detsination */
+                       pDest,                                       /* Destination */
+                       (LVM_INT16)(NrChannels * FrameCount)); /* Number of processed samples */
+#else
+            Copy_Float(pStart,                                      /* Source */
+                       pDest,                                       /* Destination */
                        (LVM_INT16)(2 * SampleCount)); /* Number of processed samples */
+#endif
             /*
              * Update the pointer and sample counts
              */
+#ifdef SUPPORT_MC
+            pDest      += NrChannels * FrameCount;                 /* Output sample pointer */
+#else
             pDest      += 2 * SampleCount;                          /* Output sample pointer */
+#endif
             NumSamples  = (LVM_INT16)(NumSamples - SampleCount);    /* Samples left to send */
             SampleCount = 0; /* No samples left in the buffer */
         }
@@ -851,14 +896,25 @@
             /*
              * Copy only some processed samples to the output
              */
+#ifdef SUPPORT_MC
+            Copy_Float(pStart,                                         /* Source */
+                       pDest,                                          /* Destination */
+                       (LVM_INT16)(NrChannels * NrFrames));  /* Number of processed samples */
+#else
             Copy_Float(pStart,                                         /* Source */
                        pDest,                                          /* Destination */
                        (LVM_INT16)(2 * NumSamples));     /* Number of processed samples */
+#endif
             /*
              * Update the pointers and sample counts
                */
+#ifdef SUPPORT_MC
+            pStart      += NrChannels * NrFrames;               /* Processed sample pointer */
+            pDest       += NrChannels * NrFrames;               /* Output sample pointer */
+#else
             pStart      += 2 * NumSamples;                        /* Processed sample pointer */
             pDest       += 2 * NumSamples;                        /* Output sample pointer */
+#endif
             SampleCount  = (LVM_INT16)(SampleCount - NumSamples); /* Processed samples left */
             NumSamples   = 0;                                     /* Clear the sample count */
         }
@@ -870,9 +926,16 @@
      */
     if (SampleCount != 0)
     {
+#ifdef SUPPORT_MC
+        Copy_Float(pStart,                                                 /* Source */
+                   /* Destination */
+                   &pBuffer->OutDelayBuffer[NrChannels * pBuffer->OutDelaySamples],
+                   (LVM_INT16)(NrChannels * FrameCount));      /* Number of processed samples */
+#else
         Copy_Float(pStart,                                                 /* Source */
                    &pBuffer->OutDelayBuffer[2 * pBuffer->OutDelaySamples], /* Destination */
                    (LVM_INT16)(2 * SampleCount));               /* Number of processed samples */
+#endif
         /* Update the buffer count */
         pBuffer->OutDelaySamples = (LVM_INT16)(pBuffer->OutDelaySamples + SampleCount);
     }
@@ -1063,14 +1126,24 @@
 {
 
     LVM_Instance_t      *pInstance  = (LVM_Instance_t  *)hInstance;
-    LVM_INT16           NumChannels =2;
+#ifdef SUPPORT_MC
+    LVM_INT16           NumChannels = pInstance->NrChannels;
+#undef NrFrames
+#define NrFrames (*pNumSamples) // alias for clarity
+#else
+    LVM_INT16           NumChannels = 2;
+#endif
 
 
     /*
      * Update sample counts
      */
     pInstance->pInputSamples    += (LVM_INT16)(*pNumSamples * NumChannels); /* Update the I/O pointers */
+#ifdef SUPPORT_MC
+    pInstance->pOutputSamples   += (LVM_INT16)(NrFrames * NumChannels);
+#else
     pInstance->pOutputSamples   += (LVM_INT16)(*pNumSamples * 2);
+#endif
     pInstance->SamplesToProcess  = (LVM_INT16)(pInstance->SamplesToProcess - *pNumSamples); /* Update the sample count */
 
     /*
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
index cfe53b8..7b85f23 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Control.c
@@ -28,6 +28,8 @@
 #include "LVM_Tables.h"
 #include "LVM_Private.h"
 
+#include <log/log.h>
+
 /****************************************************************************************/
 /*                                                                                      */
 /* FUNCTION:           LVM_SetControlParameters                                         */
@@ -75,12 +77,22 @@
         (pParams->SampleRate != LVM_FS_16000) && (pParams->SampleRate != LVM_FS_22050) && (pParams->SampleRate != LVM_FS_24000)       &&
         (pParams->SampleRate != LVM_FS_32000) && (pParams->SampleRate != LVM_FS_44100) && (pParams->SampleRate != LVM_FS_48000))      ||
 #endif
+#ifdef SUPPORT_MC
+        ((pParams->SourceFormat != LVM_STEREO) &&
+         (pParams->SourceFormat != LVM_MONOINSTEREO) &&
+         (pParams->SourceFormat != LVM_MONO) &&
+         (pParams->SourceFormat != LVM_MULTICHANNEL)) ||
+#else
         ((pParams->SourceFormat != LVM_STEREO) && (pParams->SourceFormat != LVM_MONOINSTEREO) && (pParams->SourceFormat != LVM_MONO)) ||
+#endif
         (pParams->SpeakerType > LVM_EX_HEADPHONES))
     {
         return (LVM_OUTOFRANGE);
     }
 
+#ifdef SUPPORT_MC
+    pInstance->Params.NrChannels = pParams->NrChannels;
+#endif
     /*
      * Cinema Sound parameters
      */
@@ -569,6 +581,10 @@
     } while ((pInstance->ControlPending != LVM_FALSE) &&
              (Count > 0));
 
+#ifdef SUPPORT_MC
+    pInstance->NrChannels = LocalParams.NrChannels;
+#endif
+
     /* Clear all internal data if format change*/
     if(LocalParams.SourceFormat != pInstance->Params.SourceFormat)
     {
@@ -719,6 +735,9 @@
         DBE_Params.HeadroomdB       = 0;
         DBE_Params.VolumeControl    = LVDBE_VOLUME_OFF;
         DBE_Params.VolumedB         = 0;
+#ifdef SUPPORT_MC
+        DBE_Params.NrChannels         = LocalParams.NrChannels;
+#endif
 
         /*
          * Make the changes
@@ -775,7 +794,9 @@
         {
             EQNB_Params.SourceFormat = LVEQNB_MONOINSTEREO;     /* Force to Mono-in-Stereo mode */
         }
-
+#ifdef SUPPORT_MC
+        EQNB_Params.NrChannels         = LocalParams.NrChannels;
+#endif
 
         /*
          * Set the control flag
@@ -849,7 +870,9 @@
         CS_Params.SampleRate  = LocalParams.SampleRate;
         CS_Params.ReverbLevel = LocalParams.VirtualizerReverbLevel;
         CS_Params.EffectLevel = LocalParams.CS_EffectLevel;
-
+#ifdef SUPPORT_MC
+        CS_Params.NrChannels  = LocalParams.NrChannels;
+#endif
 
         /*
          * Set the control flag
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
index 26c1c4f..ade329b 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.c
@@ -584,8 +584,11 @@
     /*
      * DC removal filter
      */
+#ifdef SUPPORT_MC
+    DC_Mc_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
+#else
     DC_2I_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
-
+#endif
 
     /*
      * Treble Enhancement
@@ -1039,7 +1042,11 @@
     LVM_SetHeadroomParams(hInstance, &HeadroomParams);
 
     /* DC removal filter */
+#ifdef SUPPORT_MC
+    DC_Mc_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
+#else
     DC_2I_D16_TRC_WRA_01_Init(&pInstance->DC_RemovalInstance);
+#endif
 
     return LVM_SUCCESS;
 }
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
index b453222..19d1532 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
@@ -144,12 +144,19 @@
     LVM_FLOAT               *pScratch;          /* Bundle scratch buffer */
 
     LVM_INT16               BufferState;        /* Buffer status */
+#ifdef SUPPORT_MC
+    LVM_FLOAT               InDelayBuffer[3 * LVM_MAX_CHANNELS * MIN_INTERNAL_BLOCKSIZE];
+#else
     LVM_FLOAT               InDelayBuffer[6 * MIN_INTERNAL_BLOCKSIZE]; /* Input buffer delay line, \
                                                                            left and right */
+#endif
     LVM_INT16               InDelaySamples;     /* Number of samples in the input delay buffer */
-
+#ifdef SUPPORT_MC
+    LVM_FLOAT               OutDelayBuffer[LVM_MAX_CHANNELS * MIN_INTERNAL_BLOCKSIZE];
+#else
     LVM_FLOAT               OutDelayBuffer[2 * MIN_INTERNAL_BLOCKSIZE]; /* Output buffer delay \
                                                                                       line */
+#endif
     LVM_INT16               OutDelaySamples;    /* Number of samples in the output delay buffer, \
                                                                              left and right */
     LVM_INT16               SamplesToOutput;    /* Samples to write to the output */
@@ -282,6 +289,10 @@
 
     LVM_INT16              NoSmoothVolume;      /* Enable or disable smooth volume changes*/
 
+#ifdef SUPPORT_MC
+    LVM_INT16              NrChannels;
+#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 4a19a13..94ba278 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.c
@@ -65,6 +65,10 @@
     LVM_FLOAT           *pToProcess = (LVM_FLOAT *)pInData;
     LVM_FLOAT           *pProcessed = pOutData;
     LVM_ReturnStatus_en  Status;
+#ifdef SUPPORT_MC
+    LVM_INT32           NrChannels  = pInstance->NrChannels;
+#define NrFrames SampleCount  // alias for clarity
+#endif
 
     /*
      * Check if the number of samples is zero
@@ -112,6 +116,10 @@
     if (pInstance->ControlPending == LVM_TRUE)
     {
         Status = LVM_ApplyNewSettings(hInstance);
+#ifdef SUPPORT_MC
+        /* Update the local variable NrChannels from pInstance->NrChannels value */
+        NrChannels = pInstance->NrChannels;
+#endif
 
         if(Status != LVM_SUCCESS)
         {
@@ -130,6 +138,9 @@
                        (LVM_INT16)NumSamples);                 /* Number of input samples */
         pInput     = pOutData;
         pToProcess = pOutData;
+#ifdef SUPPORT_MC
+        NrChannels = 2;
+#endif
     }
 
 
@@ -153,7 +164,6 @@
          */
         if (SampleCount != 0)
         {
-
             /*
              * Apply ConcertSound if required
              */
@@ -171,10 +181,18 @@
              */
             if (pInstance->VC_Active!=0)
             {
+#ifdef SUPPORT_MC
+                LVC_MixSoft_Mc_D16C31_SAT(&pInstance->VC_Volume,
+                                       pToProcess,
+                                       pProcessed,
+                                       (LVM_INT16)(NrFrames),
+                                       NrChannels);
+#else
                 LVC_MixSoft_1St_D16C31_SAT(&pInstance->VC_Volume,
                                        pToProcess,
                                        pProcessed,
                                        (LVM_INT16)(2 * SampleCount));     /* Left and right*/
+#endif
                 pToProcess = pProcessed;
             }
 
@@ -221,20 +239,33 @@
                 /*
                  * Apply the filter
                  */
+#ifdef SUPPORT_MC
+                FO_Mc_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
+                                           pProcessed,
+                                           pProcessed,
+                                           (LVM_INT16)NrFrames,
+                                           (LVM_INT16)NrChannels);
+#else
                 FO_2I_D16F32C15_LShx_TRC_WRA_01(&pInstance->pTE_State->TrebleBoost_State,
                                            pProcessed,
                                            pProcessed,
                                            (LVM_INT16)SampleCount);
+#endif
 
             }
-
-            /*
-             * Volume balance
-             */
-            LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
-                                            pProcessed,
-                                            pProcessed,
-                                            SampleCount);
+#ifdef SUPPORT_MC
+            /* TODO - Multichannel support to be added */
+            if (NrChannels == 2)
+#endif
+            {
+                /*
+                 * Volume balance
+                 */
+                LVC_MixSoft_1St_2i_D16C31_SAT(&pInstance->VC_BalanceMix,
+                                              pProcessed,
+                                              pProcessed,
+                                              SampleCount);
+            }
 
             /*
              * Perform Parametric Spectum Analysis
@@ -242,28 +273,39 @@
             if ((pInstance->Params.PSA_Enable == LVM_PSA_ON) &&
                                             (pInstance->InstParams.PSA_Included == LVM_PSA_ON))
             {
-                    From2iToMono_Float(pProcessed,
-                                       pInstance->pPSAInput,
-                                       (LVM_INT16)(SampleCount));
+#ifdef SUPPORT_MC
+                FromMcToMono_Float(pProcessed,
+                                   pInstance->pPSAInput,
+                                   (LVM_INT16)(NrFrames),
+                                   NrChannels);
+#else
+                From2iToMono_Float(pProcessed,
+                                   pInstance->pPSAInput,
+                                   (LVM_INT16)(SampleCount));
+#endif
 
-                    LVPSA_Process(pInstance->hPSAInstance,
-                            pInstance->pPSAInput,
-                            (LVM_UINT16)(SampleCount),
-                            AudioTime);
+                LVPSA_Process(pInstance->hPSAInstance,
+                        pInstance->pPSAInput,
+                        (LVM_UINT16)(SampleCount),
+                        AudioTime);
             }
 
-
             /*
              * DC removal
              */
+#ifdef SUPPORT_MC
+            DC_Mc_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
+                                 pProcessed,
+                                 pProcessed,
+                                 (LVM_INT16)NrFrames,
+                                 NrChannels);
+#else
             DC_2I_D16_TRC_WRA_01(&pInstance->DC_RemovalInstance,
                                  pProcessed,
                                  pProcessed,
                                  (LVM_INT16)SampleCount);
-
-
+#endif
         }
-
         /*
          * Manage the output buffer
          */
@@ -497,4 +539,4 @@
 
     return(LVM_SUCCESS);
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libeffects/lvm/lib/Common/lib/AGC.h b/media/libeffects/lvm/lib/Common/lib/AGC.h
index 9a3d35d..06e742e 100644
--- a/media/libeffects/lvm/lib/Common/lib/AGC.h
+++ b/media/libeffects/lvm/lib/Common/lib/AGC.h
@@ -78,6 +78,15 @@
                                  const LVM_FLOAT            *pMonoSrc,      /* Mono source */
                                  LVM_FLOAT                  *pDst,          /* Stereo destination */
                                  LVM_UINT16                 n);             /* Number of samples */
+#ifdef SUPPORT_MC
+void AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t  *pInstance,  /* Instance pointer */
+                                 const LVM_FLOAT            *pStSrc,      /* Source */
+                                 const LVM_FLOAT            *pMonoSrc,    /* Mono source */
+                                 LVM_FLOAT                  *pDst,        /* Destination */
+                                 LVM_UINT16                 NrFrames,     /* Number of frames */
+                                 LVM_UINT16                 NrChannels);  /* Number of channels */
+#endif
+
 #else
 void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t  *pInstance,     /* Instance pointer */
                                  const LVM_INT32            *pStSrc,        /* Stereo source */
diff --git a/media/libeffects/lvm/lib/Common/lib/BIQUAD.h b/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
index 3ee7f63..01539b2 100644
--- a/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
+++ b/media/libeffects/lvm/lib/Common/lib/BIQUAD.h
@@ -30,8 +30,17 @@
 #ifdef BUILD_FLOAT
 typedef struct
 {
+#ifdef SUPPORT_MC
+    /* The memory region created by this structure instance is typecast
+     * into another structure containing a pointer and an array of filter
+     * coefficients. In one case this memory region is used for storing
+     * DC component of channels
+     */
+    LVM_FLOAT *pStorage;
+    LVM_FLOAT Storage[LVM_MAX_CHANNELS];
+#else
     LVM_FLOAT Storage[6];
-
+#endif
 } Biquad_FLOAT_Instance_t;
 #else
 typedef struct
@@ -179,7 +188,12 @@
 
 typedef struct
 {
-    LVM_FLOAT Storage[ (2 * 2) ];  /* Two channels, two taps of size LVM_INT32 */
+#ifdef SUPPORT_MC
+    /* LVM_MAX_CHANNELS channels, two taps of size LVM_FLOAT */
+    LVM_FLOAT Storage[ (LVM_MAX_CHANNELS * 2) ];
+#else
+    LVM_FLOAT Storage[ (2 * 2) ];  /* Two channels, two taps of size LVM_FLOAT */
+#endif
 } Biquad_2I_Order1_FLOAT_Taps_t;
 #else
 typedef struct
@@ -197,12 +211,17 @@
 #ifdef BUILD_FLOAT
 typedef struct
 {
-    LVM_FLOAT Storage[ (1 * 4) ];  /* One channel, four taps of size LVM_INT32 */
+    LVM_FLOAT Storage[ (1 * 4) ];  /* One channel, four taps of size LVM_FLOAT */
 } Biquad_1I_Order2_FLOAT_Taps_t;
 
 typedef struct
 {
-    LVM_FLOAT Storage[ (2 * 4) ];  /* Two channels, four taps of size LVM_INT32 */
+#ifdef SUPPORT_MC
+    /* LVM_MAX_CHANNELS, four taps of size LVM_FLOAT */
+    LVM_FLOAT Storage[ (LVM_MAX_CHANNELS * 4) ];
+#else
+    LVM_FLOAT Storage[ (2 * 4) ];  /* Two channels, four taps of size LVM_FLOAT */
+#endif
 } Biquad_2I_Order2_FLOAT_Taps_t;
 #else
 typedef struct
@@ -366,6 +385,13 @@
                                             LVM_FLOAT                    *pDataIn,
                                             LVM_FLOAT                    *pDataOut,
                                             LVM_INT16                 NrSamples);
+#ifdef SUPPORT_MC
+void BQ_MC_D32F32C30_TRC_WRA_01 (           Biquad_FLOAT_Instance_t      *pInstance,
+                                            LVM_FLOAT                    *pDataIn,
+                                            LVM_FLOAT                    *pDataOut,
+                                            LVM_INT16                    NrFrames,
+                                            LVM_INT16                    NrChannels);
+#endif
 #else
 void BQ_2I_D32F32Cll_TRC_WRA_01_Init (      Biquad_Instance_t       *pInstance,
                                             Biquad_2I_Order2_Taps_t *pTaps,
@@ -434,6 +460,13 @@
                                  LVM_FLOAT                     *pDataIn,
                                  LVM_FLOAT                     *pDataOut,
                                  LVM_INT16                     NrSamples);
+#ifdef SUPPORT_MC
+void FO_Mc_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t  *pInstance,
+                                     LVM_FLOAT                *pDataIn,
+                                     LVM_FLOAT                *pDataOut,
+                                     LVM_INT16                NrFrames,
+                                     LVM_INT16                NrChannels);
+#endif
 #else
 void FO_1I_D32F32Cll_TRC_WRA_01_Init(       Biquad_Instance_t       *pInstance,
                                             Biquad_1I_Order1_Taps_t *pTaps,
@@ -527,6 +560,13 @@
                                     LVM_FLOAT               *pDataIn,
                                     LVM_FLOAT               *pDataOut,
                                     LVM_INT16               NrSamples);
+#ifdef SUPPORT_MC
+void PK_Mc_D32F32C14G11_TRC_WRA_01(Biquad_FLOAT_Instance_t       *pInstance,
+                                   LVM_FLOAT               *pDataIn,
+                                   LVM_FLOAT               *pDataOut,
+                                   LVM_INT16               NrFrames,
+                                   LVM_INT16               NrChannels);
+#endif
 #else
 void PK_2I_D32F32C14G11_TRC_WRA_01 (        Biquad_Instance_t       *pInstance,
                                             LVM_INT32                    *pDataIn,
@@ -540,12 +580,22 @@
 
 /*** 16 bit data path STEREO ******************************************************/
 #ifdef BUILD_FLOAT
+#ifdef SUPPORT_MC
+void DC_Mc_D16_TRC_WRA_01_Init     (        Biquad_FLOAT_Instance_t       *pInstance);
+
+void DC_Mc_D16_TRC_WRA_01          (        Biquad_FLOAT_Instance_t       *pInstance,
+                                            LVM_FLOAT               *pDataIn,
+                                            LVM_FLOAT               *pDataOut,
+                                            LVM_INT16               NrFrames,
+                                            LVM_INT16               NrChannels);
+#else
 void DC_2I_D16_TRC_WRA_01_Init     (        Biquad_FLOAT_Instance_t       *pInstance);
 
 void DC_2I_D16_TRC_WRA_01          (        Biquad_FLOAT_Instance_t       *pInstance,
                                             LVM_FLOAT               *pDataIn,
                                             LVM_FLOAT               *pDataOut,
                                             LVM_INT16               NrSamples);
+#endif
 #else
 void DC_2I_D16_TRC_WRA_01_Init     (        Biquad_Instance_t       *pInstance);
 
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h b/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h
index 81e288c..a76354d 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Timer.h
@@ -44,7 +44,15 @@
 
 typedef struct
 {
-    LVM_INT32 Storage[6];
+    /*
+     * The memory area created using this structure is internally
+     * typecast to LVM_Timer_Instance_Private_t and used.
+     * The LVM_Timer_Instance_Private_t structure has 3 pointer type elements
+     * 2 elements of type LVM_INT32 and one element of type LVM_INT16.
+     * Inorder to cater both 32 and 64 bit builds, Storage array should
+     * have a minimum of 9 elements of type LVM_INT32.
+     */
+    LVM_INT32 Storage[9];
 
 } LVM_Timer_Instance_t;
 
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index ea16072..303b62d 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -122,6 +122,12 @@
 
 #endif // NATIVE_FLOAT_BUFFER
 
+#ifdef SUPPORT_MC
+#define LVM_MAX_CHANNELS 8 // FCC_8
+#else
+#define LVM_MAX_CHANNELS 2 // FCC_2
+#endif
+
 /****************************************************************************************/
 /*                                                                                      */
 /*  Standard Enumerated types                                                           */
@@ -143,6 +149,9 @@
     LVM_STEREO          = 0,
     LVM_MONOINSTEREO    = 1,
     LVM_MONO            = 2,
+#ifdef SUPPORT_MC
+    LVM_MULTICHANNEL    = 3,
+#endif
     LVM_SOURCE_DUMMY    = LVM_MAXENUM
 } LVM_Format_en;
 
diff --git a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
index 0ba20a3..7468a90 100644
--- a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
+++ b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
@@ -47,6 +47,16 @@
 void Copy_Float(                 const LVM_FLOAT *src,
                                  LVM_FLOAT *dst,
                                  LVM_INT16 n );
+#ifdef SUPPORT_MC
+void Copy_Float_Mc_Stereo(       const LVM_FLOAT *src,
+                                 LVM_FLOAT *dst,
+                                 LVM_INT16 NrFrames,
+                                 LVM_INT32 NrChannels);
+void Copy_Float_Stereo_Mc(       const LVM_FLOAT *src,
+                                 LVM_FLOAT *dst,
+                                 LVM_INT16 NrFrames,
+                                 LVM_INT32 NrChannels);
+#endif
 #else
 void Copy_16(                 const LVM_INT16 *src,
                                     LVM_INT16 *dst,
@@ -181,6 +191,12 @@
 void From2iToMono_Float(         const LVM_FLOAT  *src,
                                  LVM_FLOAT  *dst,
                                  LVM_INT16 n);
+#ifdef SUPPORT_MC
+void FromMcToMono_Float(const LVM_FLOAT *src,
+                        LVM_FLOAT *dst,
+                        LVM_INT16 NrFrames,
+                        LVM_INT16 NrChannels);
+#endif
 #else
 void From2iToMono_32(         const LVM_INT32  *src,
                                     LVM_INT32  *dst,
diff --git a/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c b/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
index fa9f01f..5c8655f 100644
--- a/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c
@@ -305,4 +305,150 @@
 
     return;
 }
+#ifdef SUPPORT_MC
+/****************************************************************************************/
+/*                                                                                      */
+/* FUNCTION:                  AGC_MIX_VOL_Mc1Mon_D32_WRA                                */
+/*                                                                                      */
+/* DESCRIPTION:                                                                         */
+/*    Apply AGC and mix signals                                                         */
+/*                                                                                      */
+/*                                                                                      */
+/*  McSrc   ------------------|                                                         */
+/*                            |                                                         */
+/*              ______       _|_        ________                                        */
+/*             |      |     |   |      |        |                                       */
+/*  MonoSrc -->| AGC  |---->| + |----->| Volume |------------------------------+--->    */
+/*             | Gain |     |___|      | Gain   |                              |        */
+/*             |______|                |________|                              |        */
+/*                /|\                               __________     ________    |        */
+/*                 |                               |          |   |        |   |        */
+/*                 |-------------------------------| AGC Gain |<--| Peak   |<--|        */
+/*                                                 | Update   |   | Detect |            */
+/*                                                 |__________|   |________|            */
+/*                                                                                      */
+/*                                                                                      */
+/* PARAMETERS:                                                                          */
+/*  pInstance               Instance pointer                                            */
+/*  pMcSrc                  Multichannel source                                         */
+/*  pMonoSrc                Mono band pass source                                       */
+/*  pDst                    Multichannel destination                                    */
+/*  NrFrames                Number of frames                                            */
+/*  NrChannels              Number of channels                                          */
+/*                                                                                      */
+/* RETURNS:                                                                             */
+/*  Void                                                                                */
+/*                                                                                      */
+/* NOTES:                                                                               */
+/*                                                                                      */
+/****************************************************************************************/
+void AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t  *pInstance,
+                                 const LVM_FLOAT            *pMcSrc,
+                                 const LVM_FLOAT            *pMonoSrc,
+                                 LVM_FLOAT                  *pDst,
+                                 LVM_UINT16                 NrFrames,
+                                 LVM_UINT16                 NrChannels)
+{
+
+    /*
+     * General variables
+     */
+    LVM_UINT16      i, jj;                                      /* Sample index */
+    LVM_FLOAT       SampleVal;                                  /* Sample value */
+    LVM_FLOAT       Mono;                                       /* Mono sample */
+    LVM_FLOAT       AbsPeak;                                    /* Absolute peak signal */
+    LVM_FLOAT       AGC_Mult;                                   /* Short AGC gain */
+    LVM_FLOAT       Vol_Mult;                                   /* Short volume */
+
+
+    /*
+     * Instance control variables
+     */
+    LVM_FLOAT      AGC_Gain      = pInstance->AGC_Gain;         /* Get the current AGC gain */
+    LVM_FLOAT      AGC_MaxGain   = pInstance->AGC_MaxGain;      /* Get maximum AGC gain */
+    LVM_FLOAT      AGC_Attack    = pInstance->AGC_Attack;       /* Attack scaler */
+    /* Decay scaler */
+    LVM_FLOAT      AGC_Decay     = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));
+    LVM_FLOAT      AGC_Target    = pInstance->AGC_Target;       /* Get the target level */
+    LVM_FLOAT      Vol_Current   = pInstance->Volume;           /* Actual volume setting */
+    LVM_FLOAT      Vol_Target    = pInstance->Target;           /* Target volume setting */
+    LVM_FLOAT      Vol_TC        = pInstance->VolumeTC;         /* Time constant */
+
+
+    /*
+     * Process on a sample by sample basis
+     */
+    for (i = 0; i < NrFrames; i++)                                  /* For each frame */
+    {
+
+        /*
+         * Get the scalers
+         */
+        AGC_Mult    = (LVM_FLOAT)(AGC_Gain);              /* Get the AGC gain */
+        Vol_Mult    = (LVM_FLOAT)(Vol_Current);           /* Get the volume gain */
+
+        AbsPeak = 0.0f;
+        /*
+         * Get the input samples
+         */
+        for (jj = 0; jj < NrChannels; jj++)
+        {
+            SampleVal  = *pMcSrc++;                       /* Get the sample value of jj Channel*/
+            Mono       = *pMonoSrc;                       /* Get the mono sample */
+
+            /*
+             * Apply the AGC gain to the mono input and mix with the input signal
+             */
+            SampleVal  += (Mono * AGC_Mult);                        /* Mix in the mono signal */
+
+            /*
+             * Apply the volume and write to the output stream
+             */
+            SampleVal  = SampleVal  * Vol_Mult;
+
+            *pDst++ = SampleVal;                                         /* Save the results */
+
+            /*
+             * Update the AGC gain
+             */
+            AbsPeak = Abs_Float(SampleVal) > AbsPeak ? Abs_Float(SampleVal) : AbsPeak;
+        }
+        if (AbsPeak > AGC_Target)
+        {
+            /*
+             * The signal is too large so decrease the gain
+             */
+            AGC_Gain = AGC_Gain * AGC_Attack;
+        }
+        else
+        {
+            /*
+             * The signal is too small so increase the gain
+             */
+            if (AGC_Gain > AGC_MaxGain)
+            {
+                AGC_Gain -= (AGC_Decay);
+            }
+            else
+            {
+                AGC_Gain += (AGC_Decay);
+            }
+        }
+        pMonoSrc++;
+        /*
+         * Update the gain
+         */
+        Vol_Current +=  (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
+    }
+
+
+    /*
+     * Update the parameters
+     */
+    pInstance->Volume = Vol_Current;                            /* Actual volume setting */
+    pInstance->AGC_Gain = AGC_Gain;
+
+    return;
+}
+#endif /*SUPPORT_MC*/
 #endif /*BUILD_FLOAT*/
diff --git a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
index 960de79..d63365c 100644
--- a/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c
@@ -123,6 +123,87 @@
         }
 
     }
+
+#ifdef SUPPORT_MC
+/**************************************************************************
+ ASSUMPTIONS:
+ COEFS-
+ pBiquadState->coefs[0] is A2, pBiquadState->coefs[1] is A1
+ pBiquadState->coefs[2] is A0, pBiquadState->coefs[3] is -B2
+ pBiquadState->coefs[4] is -B1
+
+ DELAYS-
+ pBiquadState->pDelays[0] to
+ pBiquadState->pDelays[NrChannels - 1] is x(n-1) for all NrChannels
+
+ pBiquadState->pDelays[NrChannels] to
+ pBiquadState->pDelays[2*NrChannels - 1] is x(n-2) for all NrChannels
+
+ pBiquadState->pDelays[2*NrChannels] to
+ pBiquadState->pDelays[3*NrChannels - 1] is y(n-1) for all NrChannels
+
+ pBiquadState->pDelays[3*NrChannels] to
+ pBiquadState->pDelays[4*NrChannels - 1] is y(n-2) for all NrChannels
+***************************************************************************/
+void BQ_MC_D32F32C30_TRC_WRA_01 (           Biquad_FLOAT_Instance_t      *pInstance,
+                                            LVM_FLOAT                    *pDataIn,
+                                            LVM_FLOAT                    *pDataOut,
+                                            LVM_INT16                    NrFrames,
+                                            LVM_INT16                    NrChannels)
+
+
+    {
+        LVM_FLOAT yn, temp;
+        LVM_INT16 ii, jj;
+        PFilter_State_FLOAT pBiquadState = (PFilter_State_FLOAT) pInstance;
+
+         for (ii = NrFrames; ii != 0; ii--)
+         {
+            /**************************************************************************
+                            PROCESSING CHANNEL-WISE
+            ***************************************************************************/
+            for (jj = 0; jj < NrChannels; jj++)
+            {
+                /* yn= (A2  * x(n-2)) */
+                yn = pBiquadState->coefs[0] * pBiquadState->pDelays[NrChannels + jj];
+
+                /* yn+= (A1  * x(n-1)) */
+                temp = pBiquadState->coefs[1] * pBiquadState->pDelays[jj];
+                yn += temp;
+
+                /* yn+= (A0  * x(n)) */
+                temp = pBiquadState->coefs[2] * (*pDataIn);
+                yn += temp;
+
+                 /* yn+= (-B2  * y(n-2)) */
+                temp = pBiquadState->coefs[3] * pBiquadState->pDelays[NrChannels*3 + jj];
+                yn += temp;
+
+                /* yn+= (-B1  * y(n-1)) */
+                temp = pBiquadState->coefs[4] * pBiquadState->pDelays[NrChannels*2 + jj];
+                yn += temp;
+
+                /**************************************************************************
+                                UPDATING THE DELAYS
+                ***************************************************************************/
+                pBiquadState->pDelays[NrChannels * 3 + jj] =
+                    pBiquadState->pDelays[NrChannels * 2 + jj]; /* y(n-2)=y(n-1)*/
+                pBiquadState->pDelays[NrChannels * 1 + jj] =
+                    pBiquadState->pDelays[jj]; /* x(n-2)=x(n-1)*/
+                pBiquadState->pDelays[NrChannels * 2 + jj] = (LVM_FLOAT)yn; /* Update y(n-1)*/
+                pBiquadState->pDelays[jj] = (*pDataIn); /* Update x(n-1)*/
+                pDataIn++;
+                /**************************************************************************
+                                WRITING THE OUTPUT
+                ***************************************************************************/
+                *pDataOut = (LVM_FLOAT)yn; /* Write jj Channel output */
+                pDataOut++;
+            }
+        }
+
+    }
+#endif /*SUPPORT_MC*/
+
 #else
 void BQ_2I_D32F32C30_TRC_WRA_01 (           Biquad_Instance_t       *pInstance,
                                             LVM_INT32                    *pDataIn,
diff --git a/media/libeffects/lvm/lib/Common/src/Copy_16.c b/media/libeffects/lvm/lib/Common/src/Copy_16.c
index e489031..1f9f659 100644
--- a/media/libeffects/lvm/lib/Common/src/Copy_16.c
+++ b/media/libeffects/lvm/lib/Common/src/Copy_16.c
@@ -84,5 +84,65 @@
 
     return;
 }
+#ifdef SUPPORT_MC
+// Extract out the stereo channel pair from multichannel source.
+void Copy_Float_Mc_Stereo(const LVM_FLOAT *src,
+                 LVM_FLOAT *dst,
+                 LVM_INT16 NrFrames, /* Number of frames */
+                 LVM_INT32 NrChannels)
+{
+    LVM_INT16 ii;
+
+    if (NrChannels >= 2)
+    {
+        for (ii = NrFrames; ii != 0; ii--)
+        {
+            dst[0] = src[0];
+            dst[1] = src[1];
+            dst += 2;
+            src += NrChannels;
+        }
+    }
+    else if (NrChannels == 1)
+    {   // not expected to occur, provided for completeness.
+        src += (NrFrames - 1);
+        dst += 2 * (NrFrames - 1);
+        for (ii = NrFrames; ii != 0; ii--)
+        {
+            dst[0] = src[0];
+            dst[1] = src[0];
+            dst -= 2;
+            src --;
+        }
+    }
+}
+
+// Merge a multichannel source with stereo contained in dst, to dst.
+void Copy_Float_Stereo_Mc(const LVM_FLOAT *src,
+                 LVM_FLOAT *dst,
+                 LVM_INT16 NrFrames, /* Number of frames*/
+                 LVM_INT32 NrChannels)
+{
+    LVM_INT16 ii, jj;
+    LVM_FLOAT *src_st = dst + 2 * (NrFrames - 1);
+
+    // repack dst which carries stereo information
+    // together with the upper channels of src.
+    dst += NrChannels * (NrFrames - 1);
+    src += NrChannels * (NrFrames - 1);
+    for (ii = NrFrames; ii != 0; ii--)
+    {
+        dst[0] = src_st[0];
+        dst[1] = src_st[1];
+        for (jj = 2; jj < NrChannels; jj++)
+        {
+            dst[jj] = src[jj];
+        }
+        dst    -= NrChannels;
+        src    -= NrChannels;
+        src_st -= 2;
+    }
+}
+#endif
 #endif
 /**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
index d261c9e..13fac5e 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01.c
@@ -33,7 +33,7 @@
         RightDC = pBiquadState->RightDC;
         for(j = NrSamples-1; j >= 0; j--)
         {
-            /* Subtract DC an saturate */
+            /* Subtract DC and saturate */
             Diff =* (pDataIn++) - (LeftDC);
             if (Diff > 1.0f) {
                 Diff = 1.0f; }
@@ -64,6 +64,58 @@
 
 
     }
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION:       DC_Mc_D16_TRC_WRA_01
+ *
+ * DESCRIPTION:
+ *  DC removal from all channels of a multichannel input
+ *
+ * PARAMETERS:
+ *  pInstance      Instance pointer
+ *  pDataIn        Input/Source
+ *  pDataOut       Output/Destination
+ *  NrFrames       Number of frames
+ *  NrChannels     Number of channels
+ *
+ * RETURNS:
+ *  void
+ *
+ */
+void DC_Mc_D16_TRC_WRA_01(Biquad_FLOAT_Instance_t       *pInstance,
+                          LVM_FLOAT               *pDataIn,
+                          LVM_FLOAT               *pDataOut,
+                          LVM_INT16               NrFrames,
+                          LVM_INT16               NrChannels)
+    {
+        LVM_FLOAT *ChDC;
+        LVM_FLOAT Diff;
+        LVM_INT32 j;
+        LVM_INT32 i;
+        PFilter_FLOAT_State_Mc pBiquadState = (PFilter_FLOAT_State_Mc) pInstance;
+
+        ChDC = &pBiquadState->ChDC[0];
+        for (j = NrFrames - 1; j >= 0; j--)
+        {
+            /* Subtract DC and saturate */
+            for (i = NrChannels - 1; i >= 0; i--)
+            {
+                Diff = *(pDataIn++) - (ChDC[i]);
+                if (Diff > 1.0f) {
+                    Diff = 1.0f;
+                } else if (Diff < -1.0f) {
+                    Diff = -1.0f; }
+                *(pDataOut++) = (LVM_FLOAT)Diff;
+                if (Diff < 0) {
+                    ChDC[i] -= DC_FLOAT_STEP;
+                } else {
+                    ChDC[i] += DC_FLOAT_STEP; }
+            }
+
+        }
+
+    }
+#endif
 #else
 void DC_2I_D16_TRC_WRA_01( Biquad_Instance_t       *pInstance,
                            LVM_INT16               *pDataIn,
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
index 4f4fcd8..0f941a0 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Init.c
@@ -24,6 +24,17 @@
     pBiquadState->LeftDC        = 0.0f;
     pBiquadState->RightDC       = 0.0f;
 }
+#ifdef SUPPORT_MC
+void  DC_Mc_D16_TRC_WRA_01_Init(Biquad_FLOAT_Instance_t   *pInstance)
+{
+    PFilter_FLOAT_State_Mc pBiquadState  = (PFilter_FLOAT_State_Mc) pInstance;
+    LVM_INT32 i;
+    for (i = 0; i < LVM_MAX_CHANNELS; i++)
+    {
+        pBiquadState->ChDC[i] = 0.0f;
+    }
+}
+#endif
 #else
 void  DC_2I_D16_TRC_WRA_01_Init(Biquad_Instance_t   *pInstance)
 {
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
index fa6b729..db3a6d3 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
@@ -34,6 +34,13 @@
     LVM_FLOAT  RightDC;    /* RightDC  */
 }Filter_FLOAT_State;
 typedef Filter_FLOAT_State * PFilter_FLOAT_State ;
+#ifdef SUPPORT_MC
+typedef struct _Filter_FLOAT_State_Mc_
+{
+    LVM_FLOAT  ChDC[LVM_MAX_CHANNELS];     /* ChannelDC  */
+} Filter_FLOAT_State_Mc;
+typedef Filter_FLOAT_State_Mc * PFilter_FLOAT_State_Mc ;
+#endif
 #else
 typedef struct _Filter_State_
 {
diff --git a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
index 192927c..2a50f18 100644
--- a/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c
@@ -117,6 +117,93 @@
         }
 
     }
+#ifdef SUPPORT_MC
+/**************************************************************************
+ASSUMPTIONS:
+COEFS-
+pBiquadState->coefs[0] is A1,
+pBiquadState->coefs[1] is A0,
+pBiquadState->coefs[2] is -B1,
+DELAYS-
+pBiquadState->pDelays[2*ch + 0] is x(n-1) of the 'ch' - channel
+pBiquadState->pDelays[2*ch + 1] is y(n-1) of the 'ch' - channel
+The index 'ch' runs from 0 to (NrChannels - 1)
+
+PARAMETERS:
+ pInstance        Pointer Instance
+ pDataIn          Input/Source
+ pDataOut         Output/Destination
+ NrFrames         Number of frames
+ NrChannels       Number of channels
+
+RETURNS:
+ void
+***************************************************************************/
+void FO_Mc_D16F32C15_LShx_TRC_WRA_01(Biquad_FLOAT_Instance_t *pInstance,
+                                     LVM_FLOAT               *pDataIn,
+                                     LVM_FLOAT               *pDataOut,
+                                     LVM_INT16               NrFrames,
+                                     LVM_INT16               NrChannels)
+    {
+        LVM_FLOAT   yn;
+        LVM_FLOAT   Temp;
+        LVM_INT16   ii;
+        LVM_INT16   ch;
+        PFilter_Float_State pBiquadState = (PFilter_Float_State) pInstance;
+
+        LVM_FLOAT   *pDelays = pBiquadState->pDelays;
+        LVM_FLOAT   *pCoefs  = &pBiquadState->coefs[0];
+        LVM_FLOAT   A0 = pCoefs[1];
+        LVM_FLOAT   A1 = pCoefs[0];
+        LVM_FLOAT   B1 = pCoefs[2];
+
+
+
+
+        for (ii = NrFrames; ii != 0; ii--)
+        {
+
+            /**************************************************************************
+                            PROCESSING OF THE CHANNELS
+            ***************************************************************************/
+            for (ch = 0; ch < NrChannels; ch++)
+            {
+                // yn =A1  * x(n-1)
+                yn = (LVM_FLOAT)A1 * pDelays[0];
+
+                // yn+=A0  * x(n)
+                yn += (LVM_FLOAT)A0 * (*pDataIn);
+
+                // yn +=  (-B1  * y(n-1))
+                Temp = B1 * pDelays[1];
+                yn += Temp;
+
+
+                /**************************************************************************
+                                UPDATING THE DELAYS
+                ***************************************************************************/
+                pDelays[1] = yn; // Update y(n-1)
+                pDelays[0] = (*pDataIn++); // Update x(n-1)
+
+                /**************************************************************************
+                                WRITING THE OUTPUT
+                ***************************************************************************/
+
+                /*Saturate results*/
+                if (yn > 1.0f)
+                {
+                    yn = 1.0f;
+                } else if (yn < -1.0f) {
+                    yn = -1.0f;
+                }
+
+                *pDataOut++ = (LVM_FLOAT)yn;
+                pDelays += 2;
+            }
+            pDelays -= NrChannels * 2;
+        }
+    }
+#endif
 #else
 void FO_2I_D16F32C15_LShx_TRC_WRA_01(Biquad_Instance_t       *pInstance,
                                      LVM_INT16               *pDataIn,
diff --git a/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c b/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
index ac1eea8..d02af88 100644
--- a/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
+++ b/media/libeffects/lvm/lib/Common/src/From2iToMono_32.c
@@ -68,5 +68,47 @@
 
     return;
 }
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION:       FromMcToMono_Float
+ *
+ * DESCRIPTION:
+ *  Creates a mono stream from a multichannel input taking the avergae of
+ *  sample values of all channels
+ *
+ * PARAMETERS:
+ *  src            Source
+ *  dst            Destination
+ *  NrFrames       Number of frames
+ *  NrChannels     Number of channels
+ *
+ * RETURNS:
+ *  void
+ *
+ */
+void FromMcToMono_Float(const LVM_FLOAT *src,
+                        LVM_FLOAT *dst,
+                        LVM_INT16 NrFrames,
+                        LVM_INT16 NrChannels)
+{
+    LVM_INT16 ii, jj;
+    LVM_FLOAT Temp;
+
+    for (ii = NrFrames; ii != 0; ii--)
+    {
+        Temp = 0.0f;
+        for (jj = NrChannels; jj !=0; jj--)
+        {
+            Temp += (*src);
+            src++;
+        }
+        *dst = Temp / NrChannels;
+        dst++;
+    }
+
+    return;
+}
+#endif
+
 #endif
 /**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
index d2694cc..419c7c5 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixInSoft_D16C31_SAT.c
@@ -26,10 +26,10 @@
    FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
 ***********************************************************************************/
 #ifdef BUILD_FLOAT
-void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_FLOAT_st *ptrInstance,
-                                    const LVM_FLOAT     *src,
-                                          LVM_FLOAT     *dst,
-                                          LVM_INT16     n)
+void LVC_Core_MixInSoft_D16C31_SAT(LVMixer3_FLOAT_st *ptrInstance,
+                                   const LVM_FLOAT   *src,
+                                         LVM_FLOAT   *dst,
+                                         LVM_INT16   n)
 {
 
     LVM_INT16   OutLoop;
@@ -114,6 +114,139 @@
     }
     pInstance->Current = Current;
 }
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION:       LVC_Core_MixInSoft_Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ *  Mixer function with support for processing multichannel input.
+ *
+ * PARAMETERS:
+ *  ptrInstance    Instance pointer
+ *  src            Source
+ *  dst            Destination
+ *  NrFrames       Number of frames
+ *  NrChannels     Number of channels
+ *
+ * RETURNS:
+ *  void
+ *
+ */
+void LVC_Core_MixInSoft_Mc_D16C31_SAT(LVMixer3_FLOAT_st *ptrInstance,
+                                      const LVM_FLOAT   *src,
+                                            LVM_FLOAT   *dst,
+                                            LVM_INT16   NrFrames,
+                                            LVM_INT16   NrChannels)
+{
+
+    LVM_INT16   OutLoop;
+    LVM_INT16   InLoop;
+    LVM_INT32   ii, jj;
+    Mix_Private_FLOAT_st  *pInstance = (Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+    LVM_FLOAT   Delta = pInstance->Delta;
+    LVM_FLOAT   Current = pInstance->Current;
+    LVM_FLOAT   Target = pInstance->Target;
+    LVM_FLOAT   Temp;
+
+    /*
+     * Same operation is performed on consecutive frames.
+     * So two frames are processed in one iteration and
+     * the loop will run only for half the NrFrames value times.
+     */
+    InLoop = (LVM_INT16)(NrFrames >> 1);
+    /* OutLoop is calculated to handle cases where NrFrames value can be odd.*/
+    OutLoop = (LVM_INT16)(NrFrames - (InLoop << 1));
+
+    if (Current < Target) {
+        if (OutLoop) {
+            Temp = Current + Delta;
+            Current = Temp;
+            if (Current > Target)
+                Current = Target;
+
+           for (ii = OutLoop*NrChannels; ii != 0; ii--) {
+                Temp = (*dst) + (*(src++) * Current);
+                if (Temp > 1.0f)
+                    *dst++ = 1.0f;
+                else if (Temp < -1.0f)
+                    *dst++ = -1.0f;
+                else
+                    *dst++ = Temp;
+            }
+        }
+
+        for (ii = InLoop; ii != 0; ii--) {
+            Temp = Current + Delta;
+            Current = Temp;
+            if (Current > Target)
+                Current = Target;
+
+            for (jj = NrChannels; jj != 0 ; jj--) {
+                Temp = (*dst) + (*(src++) * Current);
+                if (Temp > 1.0f)
+                    *dst++ = 1.0f;
+                else if (Temp < -1.0f)
+                    *dst++ = -1.0f;
+                else
+                    *dst++ = Temp;
+
+                Temp = (*dst) + (*(src++) * Current);
+                if (Temp > 1.0f)
+                    *dst++ = 1.0f;
+                else if (Temp < -1.0f)
+                    *dst++ = -1.0f;
+                else
+                    *dst++ = Temp;
+
+            }
+        }
+    }
+    else{
+        if (OutLoop) {
+            Current -= Delta;
+            if (Current < Target)
+                Current = Target;
+
+            for (ii = OutLoop*NrChannels; ii != 0; ii--) {
+                Temp = (*dst) + (*(src++) * Current);
+                if (Temp > 1.0f)
+                    *dst++ = 1.0f;
+                else if (Temp < -1.0f)
+                    *dst++ = -1.0f;
+                else
+                    *dst++ = Temp;
+            }
+        }
+
+        for (ii = InLoop; ii != 0; ii--) {
+            Current -= Delta;
+            if (Current < Target)
+                Current = Target;
+
+            for (jj = NrChannels; jj != 0 ; jj--) {
+                Temp = (*dst) + (*(src++) * Current);
+                if (Temp > 1.0f)
+                    *dst++ = 1.0f;
+                else if (Temp < -1.0f)
+                    *dst++ = -1.0f;
+                else
+                    *dst++ = Temp;
+
+                Temp = (*dst) + (*(src++) * Current);
+                if (Temp > 1.0f)
+                    *dst++ = 1.0f;
+                else if (Temp < -1.0f)
+                    *dst++ = -1.0f;
+                else
+                    *dst++ = Temp;
+
+            }
+        }
+    }
+    pInstance->Current = Current;
+}
+
+#endif
 #else
 void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_st *ptrInstance,
                                     const LVM_INT16     *src,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
index b5e7f5c..5bfdad8 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c
@@ -27,10 +27,10 @@
    FUNCTION LVCore_MIXSOFT_1ST_D16C31_WRA
 ***********************************************************************************/
 #ifdef BUILD_FLOAT
-void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_FLOAT_st *ptrInstance,
-                                    const LVM_FLOAT     *src,
-                                          LVM_FLOAT     *dst,
-                                          LVM_INT16     n)
+void LVC_Core_MixSoft_1St_D16C31_WRA(LVMixer3_FLOAT_st *ptrInstance,
+                                     const LVM_FLOAT   *src,
+                                           LVM_FLOAT   *dst,
+                                           LVM_INT16   n)
 {
     LVM_INT16   OutLoop;
     LVM_INT16   InLoop;
@@ -105,6 +105,119 @@
     }
     pInstance->Current=Current;
 }
+
+
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION:       LVC_Core_MixSoft_Mc_D16C31_WRA
+ *
+ * DESCRIPTION:
+ *  Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ *  ptrInstance    Instance pointer
+ *  src            Source
+ *  dst            Destination
+ *  NrFrames       Number of frames
+ *  NrChannels     Number of channels
+ *
+ * RETURNS:
+ *  void
+ *
+ */
+void LVC_Core_MixSoft_Mc_D16C31_WRA(LVMixer3_FLOAT_st *ptrInstance,
+                                    const LVM_FLOAT   *src,
+                                          LVM_FLOAT   *dst,
+                                          LVM_INT16   NrFrames,
+                                          LVM_INT16   NrChannels)
+{
+    LVM_INT16   OutLoop;
+    LVM_INT16   InLoop;
+    LVM_INT32   ii, jj;
+    Mix_Private_FLOAT_st  *pInstance=(Mix_Private_FLOAT_st *)(ptrInstance->PrivateParams);
+    LVM_FLOAT   Delta= (LVM_FLOAT)pInstance->Delta;
+    LVM_FLOAT   Current = (LVM_FLOAT)pInstance->Current;
+    LVM_FLOAT   Target= (LVM_FLOAT)pInstance->Target;
+    LVM_FLOAT   Temp;
+
+    /*
+     * Same operation is performed on consecutive frames.
+     * So two frames are processed in one iteration and
+     * the loop will run only for half the NrFrames value times.
+     */
+    InLoop = (LVM_INT16)(NrFrames >> 1);
+    /* OutLoop is calculated to handle cases where NrFrames value can be odd.*/
+    OutLoop = (LVM_INT16)(NrFrames - (InLoop << 1));
+
+    if (Current<Target) {
+        if (OutLoop) {
+
+            Temp = Current + Delta;
+            if (Temp > 1.0f)
+                Temp = 1.0f;
+            else if (Temp < -1.0f)
+                Temp = -1.0f;
+
+            Current=Temp;
+            if (Current > Target)
+                Current = Target;
+
+            for (ii = OutLoop; ii != 0; ii--) {
+                for (jj = NrChannels; jj !=0; jj--) {
+                    *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
+                }
+            }
+        }
+
+        for (ii = InLoop; ii != 0; ii--) {
+
+            Temp = Current + Delta;
+
+            if (Temp > 1.0f)
+                Temp = 1.0f;
+            else if (Temp < -1.0f)
+                Temp = -1.0f;
+
+            Current=Temp;
+            if (Current > Target)
+                Current = Target;
+
+            for (jj = NrChannels; jj != 0 ; jj--)
+            {
+                *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+                *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+            }
+        }
+    }
+    else{
+        if (OutLoop) {
+            Current -= Delta;
+            if (Current < Target)
+                Current = Target;
+
+            for (ii = OutLoop; ii != 0; ii--) {
+                for (jj = NrChannels; jj !=0; jj--) {
+                    *(dst++) = (((LVM_FLOAT)*(src++) * (LVM_FLOAT)Current));
+                }
+            }
+        }
+
+        for (ii = InLoop; ii != 0; ii--) {
+            Current -= Delta;
+            if (Current < Target)
+                Current = Target;
+
+            for (jj = NrChannels; jj != 0 ; jj--)
+            {
+                *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+                *(dst++) = (((LVM_FLOAT)*(src++) * Current));
+            }
+        }
+    }
+    pInstance->Current=Current;
+}
+#endif
+
 #else
 void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_st *ptrInstance,
                                     const LVM_INT16     *src,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
index 192f126..65956f7 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixInSoft_D16C31_SAT.c
@@ -34,10 +34,10 @@
    FUNCTION MIXINSOFT_D16C31_SAT
 ***********************************************************************************/
 #ifdef BUILD_FLOAT
-void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_FLOAT_st *ptrInstance,
-                               LVM_FLOAT             *src,
-                               LVM_FLOAT             *dst,
-                               LVM_INT16             n)
+void LVC_MixInSoft_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
+                              const LVM_FLOAT       *src,
+                                    LVM_FLOAT       *dst,
+                                    LVM_INT16       n)
 {
     char        HardMixing = TRUE;
     LVM_FLOAT   TargetGain;
@@ -106,6 +106,110 @@
     }
 
 }
+
+
+
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION:       LVC_MixInSoft_Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ *  Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ *  ptrInstance    Instance pointer
+ *  src            Source
+ *  dst            Destination
+ *  NrFrames       Number of frames
+ *  NrChannels     Number of channels
+ *
+ * RETURNS:
+ *  void
+ *
+ */
+void LVC_MixInSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
+                                 const LVM_FLOAT       *src,
+                                       LVM_FLOAT       *dst,
+                                       LVM_INT16       NrFrames,
+                                       LVM_INT16       NrChannels)
+{
+    char        HardMixing = TRUE;
+    LVM_FLOAT   TargetGain;
+    Mix_Private_FLOAT_st  *pInstance = \
+                             (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+
+    if (NrFrames <= 0)    return;
+
+    /******************************************************************************
+       SOFT MIXING
+    *******************************************************************************/
+    if (pInstance->Current != pInstance->Target)
+    {
+        if (pInstance->Delta == 1.0f) {
+            pInstance->Current = pInstance->Target;
+            TargetGain = pInstance->Target;
+            LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+        }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+            pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+                                                       Make them equal. */
+            TargetGain = pInstance->Target;
+            LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+        }else{
+            /* Soft mixing has to be applied */
+            HardMixing = FALSE;
+            LVC_Core_MixInSoft_Mc_D16C31_SAT(&(ptrInstance->MixerStream[0]),
+                                             src,
+                                             dst,
+                                             NrFrames,
+                                             NrChannels);
+        }
+    }
+
+    /******************************************************************************
+       HARD MIXING
+    *******************************************************************************/
+
+    if (HardMixing) {
+        if (pInstance->Target != 0) { /* Nothing to do in case Target = 0 */
+            if ((pInstance->Target) == 1.0f) {
+                Add2_Sat_Float(src, dst, NrFrames*NrChannels);
+            }
+            else{
+                Mac3s_Sat_Float(src,
+                                (pInstance->Target),
+                                dst,
+                                NrFrames * NrChannels);
+                /* In case the LVCore function would have changed the Current value */
+                pInstance->Current = pInstance->Target;
+            }
+        }
+    }
+
+
+    /******************************************************************************
+       CALL BACK
+    *******************************************************************************/
+
+    if (ptrInstance->MixerStream[0].CallbackSet) {
+        if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+            pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+                                                       Make them equal. */
+            TargetGain = pInstance->Target;
+            LVC_Mixer_SetTarget(ptrInstance->MixerStream, 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);
+            }
+        }
+    }
+
+}
+#endif
+
+
 #else
 void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_st *ptrInstance,
                                     LVM_INT16             *src,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
index 1017de3..0678ae0 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_D16C31_SAT.c
@@ -103,6 +103,101 @@
         }
     }
 }
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION:       LVC_MixSoft_Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ *  Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ *  ptrInstance    Instance pointer
+ *  src            Source
+ *  dst            Destination
+ *  NrFrames       Number of Frames
+ *  NrChannels     Number of channels
+ *
+ * RETURNS:
+ *  void
+ *
+ */
+void LVC_MixSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *ptrInstance,
+                                  const LVM_FLOAT      *src,
+                                        LVM_FLOAT      *dst,
+                                        LVM_INT16      NrFrames,
+                                        LVM_INT16      NrChannels)
+{
+    char        HardMixing = TRUE;
+    LVM_FLOAT   TargetGain;
+    Mix_Private_FLOAT_st  *pInstance = \
+                          (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
+
+    if (NrFrames <= 0)    return;
+
+    /******************************************************************************
+       SOFT MIXING
+    *******************************************************************************/
+    if (pInstance->Current != pInstance->Target)
+    {
+        if (pInstance->Delta == 1.0f) {
+            pInstance->Current = pInstance->Target;
+            TargetGain = pInstance->Target;
+            LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+        }else if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+            pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+                                                       Make them equal. */
+            TargetGain = pInstance->Target;
+            LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
+        }else{
+            /* Soft mixing has to be applied */
+            HardMixing = FALSE;
+            LVC_Core_MixSoft_Mc_D16C31_WRA(&(ptrInstance->MixerStream[0]),
+                                           src,
+                                           dst,
+                                           NrFrames,
+                                           NrChannels);
+        }
+    }
+
+    /******************************************************************************
+       HARD MIXING
+    *******************************************************************************/
+
+    if (HardMixing) {
+        if (pInstance->Target == 0)
+            LoadConst_Float(0.0, dst, NrFrames * NrChannels);
+        else {
+            if ((pInstance->Target) != 1.0f)
+                Mult3s_Float(src, (pInstance->Target), dst, NrFrames * NrChannels);
+            else if (src != dst)
+                Copy_Float(src, dst, NrFrames * NrChannels);
+        }
+
+    }
+
+    /******************************************************************************
+       CALL BACK
+    *******************************************************************************/
+
+    if (ptrInstance->MixerStream[0].CallbackSet) {
+        if (Abs_Float(pInstance->Current - pInstance->Target) < pInstance->Delta) {
+            pInstance->Current = pInstance->Target; /* Difference is not significant anymore. \
+                                                       Make them equal. */
+            TargetGain = pInstance->Target;
+            LVC_Mixer_SetTarget(ptrInstance->MixerStream, 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);
+            }
+        }
+    }
+}
+
+#endif
+
 #else
 void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_st *ptrInstance,
                                   const LVM_INT16             *src,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
index 3c90071..8a89de1 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_2St_D16C31_SAT.c
@@ -26,11 +26,11 @@
    FUNCTION LVC_MixSoft_2St_D16C31_SAT.c
 ***********************************************************************************/
 #ifdef BUILD_FLOAT
-void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
-                                 const   LVM_FLOAT       *src1,
-                                 LVM_FLOAT       *src2,
-                                 LVM_FLOAT       *dst,
-                                 LVM_INT16       n)
+void LVC_MixSoft_2St_D16C31_SAT(LVMixer3_2St_FLOAT_st *ptrInstance,
+                                const LVM_FLOAT       *src1,
+                                const LVM_FLOAT       *src2,
+                                      LVM_FLOAT       *dst,
+                                      LVM_INT16       n)
 {
     Mix_Private_FLOAT_st  *pInstance1 = \
                              (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
@@ -67,6 +67,70 @@
                                          src1, src2, dst, n);
     }
 }
+
+#ifdef SUPPORT_MC
+/*
+ * FUNCTION:       LVC_MixSoft_2Mc_D16C31_SAT
+ *
+ * DESCRIPTION:
+ *  2 stream Mixer function with support for processing multichannel input
+ *
+ * PARAMETERS:
+ *  ptrInstance    Instance pointer
+ *  src1           First multichannel source
+ *  src2           Second multichannel source
+ *  dst            Destination
+ *  NrFrames       Number of frames
+ *  NrChannels     Number of channels
+ *
+ * RETURNS:
+ *  void
+ *
+ */
+void LVC_MixSoft_2Mc_D16C31_SAT(LVMixer3_2St_FLOAT_st *ptrInstance,
+                                const LVM_FLOAT       *src1,
+                                const LVM_FLOAT       *src2,
+                                      LVM_FLOAT       *dst,
+                                      LVM_INT16       NrFrames,
+                                      LVM_INT16       NrChannels)
+{
+    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);
+
+    if (NrFrames <= 0)    return;
+
+    /******************************************************************************
+       SOFT MIXING
+    *******************************************************************************/
+    if ((pInstance1->Current == pInstance1->Target) && (pInstance1->Current == 0)) {
+        LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+                                    src2, dst, NrFrames, NrChannels);
+    }
+    else if ((pInstance2->Current == pInstance2->Target) && (pInstance2->Current == 0)) {
+        LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+                                    src1, dst, NrFrames, NrChannels);
+    }
+    else if ((pInstance1->Current != pInstance1->Target) || \
+                                    (pInstance2->Current != pInstance2->Target))
+    {
+        LVC_MixSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[0]),
+                                   src1, dst, NrFrames, NrChannels);
+        LVC_MixInSoft_Mc_D16C31_SAT((LVMixer3_1St_FLOAT_st *)(&ptrInstance->MixerStream[1]),
+                                   src2, dst, NrFrames, NrChannels);
+    }
+    else{
+        /******************************************************************************
+           HARD MIXING
+        *******************************************************************************/
+        LVC_Core_MixHard_2St_D16C31_SAT(&ptrInstance->MixerStream[0],
+                                        &ptrInstance->MixerStream[1],
+                                        src1, src2, dst, NrFrames * NrChannels);
+    }
+}
+#endif
+
 #else
 void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_st *ptrInstance,
                                     const   LVM_INT16       *src1,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
index f904915..7f18747 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer.h
@@ -157,10 +157,18 @@
 /*** 16 bit functions *************************************************************/
 
 #ifdef BUILD_FLOAT
-void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_FLOAT_st *pInstance,
-                                 const LVM_FLOAT           *src,
-                                 LVM_FLOAT           *dst,
-                                 LVM_INT16           n);
+void LVC_MixSoft_1St_D16C31_SAT(LVMixer3_1St_FLOAT_st *pInstance,
+                                const LVM_FLOAT       *src,
+                                      LVM_FLOAT       *dst,
+                                      LVM_INT16       n);
+#ifdef SUPPORT_MC
+void LVC_MixSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *pInstance,
+                               const LVM_FLOAT       *src,
+                                     LVM_FLOAT       *dst,
+                                     LVM_INT16       NrFrames,
+                                     LVM_INT16       NrChannels);
+#endif
+
 #else
 void LVC_MixSoft_1St_D16C31_SAT( LVMixer3_1St_st *pInstance,
                                   const LVM_INT16           *src,
@@ -169,10 +177,18 @@
 #endif
 
 #ifdef BUILD_FLOAT
-void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_FLOAT_st *pInstance,
-                               LVM_FLOAT           *src,
-                               LVM_FLOAT           *dst,
-                               LVM_INT16           n);
+void LVC_MixInSoft_D16C31_SAT(LVMixer3_1St_FLOAT_st *pInstance,
+                              const LVM_FLOAT       *src,
+                                    LVM_FLOAT       *dst,
+                                    LVM_INT16       n);
+#ifdef SUPPORT_MC
+void LVC_MixInSoft_Mc_D16C31_SAT(LVMixer3_1St_FLOAT_st *pInstance,
+                                 const LVM_FLOAT       *src,
+                                       LVM_FLOAT       *dst,
+                                       LVM_INT16       NrFrames,
+                                       LVM_INT16       NrChannels);
+#endif
+
 #else
 void LVC_MixInSoft_D16C31_SAT( LVMixer3_1St_st *pInstance,
                                         LVM_INT16           *src,
@@ -181,11 +197,19 @@
 #endif
 
 #ifdef BUILD_FLOAT
-void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_FLOAT_st *pInstance,
-                                 const LVM_FLOAT             *src1,
-                                 LVM_FLOAT             *src2,
-                                 LVM_FLOAT             *dst,  /* dst cannot be equal to src2 */
-                                 LVM_INT16             n);
+void LVC_MixSoft_2St_D16C31_SAT(LVMixer3_2St_FLOAT_st *pInstance,
+                                const LVM_FLOAT       *src1,
+                                const LVM_FLOAT       *src2,
+                                LVM_FLOAT             *dst,  /* dst cannot be equal to src2 */
+                                LVM_INT16             n);
+#ifdef SUPPORT_MC
+void LVC_MixSoft_2Mc_D16C31_SAT(LVMixer3_2St_FLOAT_st *pInstance,
+                                const LVM_FLOAT       *src1,
+                                const LVM_FLOAT       *src2,
+                                LVM_FLOAT             *dst,  /* dst cannot be equal to src2 */
+                                LVM_INT16             NrFrames,
+                                LVM_INT16             NrChannels);
+#endif
 #else
 void LVC_MixSoft_2St_D16C31_SAT( LVMixer3_2St_st *pInstance,
                                 const LVM_INT16             *src1,
@@ -200,10 +224,10 @@
 /* Gain values should not be more that 1.0                                        */
 /**********************************************************************************/
 #ifdef BUILD_FLOAT
-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 */
-                                    LVM_INT16           n);     /* Number of stereo samples */
+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 */
+                                   LVM_INT16             n);     /* Number of stereo samples */
 #else
 void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_st         *pInstance,
                                 const   LVM_INT16           *src,
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
index c67455a..507eefa 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_GetTarget.c
@@ -35,7 +35,7 @@
 {
     LVM_FLOAT       TargetGain;
     Mix_Private_FLOAT_st  *pInstance = (Mix_Private_FLOAT_st *)pStream->PrivateParams;
-    
+
     TargetGain = pInstance->Target;  // TargetGain
     return TargetGain;
 }
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 d0d0e1f..f10094b 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/LVC_Mixer_Private.h
@@ -62,6 +62,13 @@
                                     const LVM_FLOAT     *src,
                                     LVM_FLOAT     *dst,
                                     LVM_INT16     n);
+#ifdef SUPPORT_MC
+void LVC_Core_MixInSoft_Mc_D16C31_SAT(LVMixer3_FLOAT_st *ptrInstance,
+                                    const LVM_FLOAT     *src,
+                                          LVM_FLOAT     *dst,
+                                          LVM_INT16     NrFrames,
+                                          LVM_INT16     NrChannels);
+#endif
 #else
 void LVC_Core_MixInSoft_D16C31_SAT( LVMixer3_st *pInstance,
                                     const LVM_INT16     *src,
@@ -73,6 +80,13 @@
                                       const LVM_FLOAT     *src,
                                       LVM_FLOAT     *dst,
                                       LVM_INT16     n);
+#ifdef SUPPORT_MC
+void LVC_Core_MixSoft_Mc_D16C31_WRA(LVMixer3_FLOAT_st *ptrInstance,
+                                    const LVM_FLOAT     *src,
+                                          LVM_FLOAT     *dst,
+                                          LVM_INT16     NrFrames,
+                                          LVM_INT16     NrChannels);
+#endif
 #else
 void LVC_Core_MixSoft_1St_D16C31_WRA( LVMixer3_st *pInstance,
                                     const LVM_INT16     *src,
diff --git a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
index 9c17a05..6c8b2db 100644
--- a/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
+++ b/media/libeffects/lvm/lib/Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c
@@ -119,6 +119,80 @@
         }
 
     }
+
+#ifdef SUPPORT_MC
+/**************************************************************************
+DELAYS-
+pBiquadState->pDelays[0] to
+pBiquadState->pDelays[NrChannels - 1] is x(n-1) for all NrChannels
+
+pBiquadState->pDelays[NrChannels] to
+pBiquadState->pDelays[2*NrChannels - 1] is x(n-2) for all NrChannels
+
+pBiquadState->pDelays[2*NrChannels] to
+pBiquadState->pDelays[3*NrChannels - 1] is y(n-1) for all NrChannels
+
+pBiquadState->pDelays[3*NrChannels] to
+pBiquadState->pDelays[4*NrChannels - 1] is y(n-2) for all NrChannels
+***************************************************************************/
+
+void PK_Mc_D32F32C14G11_TRC_WRA_01 (Biquad_FLOAT_Instance_t       *pInstance,
+                                    LVM_FLOAT               *pDataIn,
+                                    LVM_FLOAT               *pDataOut,
+                                    LVM_INT16               NrFrames,
+                                    LVM_INT16               NrChannels)
+    {
+        LVM_FLOAT yn, ynO, temp;
+        LVM_INT16 ii, jj;
+        PFilter_State_Float pBiquadState = (PFilter_State_Float) pInstance;
+
+         for (ii = NrFrames; ii != 0; ii--)
+         {
+
+            for (jj = 0; jj < NrChannels; jj++)
+            {
+                /**************************************************************************
+                                PROCESSING OF THE jj CHANNEL
+                ***************************************************************************/
+                /* yn= (A0  * (x(n) - x(n-2)))*/
+                temp = (*pDataIn) - pBiquadState->pDelays[NrChannels + jj];
+                yn = temp * pBiquadState->coefs[0];
+
+                /* yn+= ((-B2  * y(n-2))) */
+                temp = pBiquadState->pDelays[NrChannels*3 + jj] * pBiquadState->coefs[1];
+                yn += temp;
+
+                /* yn+= ((-B1 * y(n-1))) */
+                temp = pBiquadState->pDelays[NrChannels*2 + jj] * pBiquadState->coefs[2];
+                yn += temp;
+
+                /* ynO= ((Gain * yn)) */
+                ynO = yn * pBiquadState->coefs[3];
+
+                /* ynO=(ynO + x(n))*/
+                ynO += (*pDataIn);
+
+                /**************************************************************************
+                                UPDATING THE DELAYS
+                ***************************************************************************/
+                pBiquadState->pDelays[NrChannels * 3 + jj] =
+                    pBiquadState->pDelays[NrChannels * 2 + jj]; /* y(n-2)=y(n-1)*/
+                pBiquadState->pDelays[NrChannels * 1 + jj] =
+                    pBiquadState->pDelays[jj]; /* x(n-2)=x(n-1)*/
+                pBiquadState->pDelays[NrChannels * 2 + jj] = yn; /* Update y(n-1) */
+                pBiquadState->pDelays[jj] = (*pDataIn); /* Update x(n-1)*/
+                pDataIn++;
+
+                /**************************************************************************
+                                WRITING THE OUTPUT
+                ***************************************************************************/
+                *pDataOut = ynO; /* Write output*/
+                pDataOut++;
+            }
+        }
+
+    }
+#endif
 #else
 void PK_2I_D32F32C14G11_TRC_WRA_01 ( Biquad_Instance_t       *pInstance,
                                      LVM_INT32               *pDataIn,
diff --git a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
index 8e0b738..e7fdbf6 100644
--- a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
+++ b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
@@ -267,7 +267,9 @@
     /* Equaliser parameters */
     LVM_UINT16                  NBands;                 /* Number of bands */
     LVEQNB_BandDef_t            *pBandDefinition;       /* Pointer to equaliser definitions */
-
+#ifdef SUPPORT_MC
+    LVM_INT16                   NrChannels;
+#endif
 } LVEQNB_Params_t;
 
 
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
index 56b02e0..a9cd5fd 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
@@ -46,7 +46,12 @@
 #define LVEQNB_INSTANCE_ALIGN       4                   /* 32-bit alignment for instance structures */
 #define LVEQNB_DATA_ALIGN           4                   /* 32-bit alignment for structures */
 #define LVEQNB_COEF_ALIGN           4                   /* 32-bit alignment for long words */
+#ifdef SUPPORT_MC
+/* Number of buffers required for inplace processing */
+#define LVEQNB_SCRATCHBUFFERS       (LVM_MAX_CHANNELS * 2)
+#else
 #define LVEQNB_SCRATCHBUFFERS       4                   /* Number of buffers required for inplace processing */
+#endif
 #define LVEQNB_SCRATCH_ALIGN        4                   /* 32-bit alignment for long data */
 
 #define LVEQNB_BYPASS_MIXER_TC      100                 /* Bypass Mixer TC */
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
index 6328181..d188c0e 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.c
@@ -26,6 +26,7 @@
 #include "VectorArithmetic.h"
 #include "BIQUAD.h"
 
+#include <log/log.h>
 
 /****************************************************************************************/
 /*                                                                                      */
@@ -61,14 +62,18 @@
 LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t       hInstance,
                                       const LVM_FLOAT       *pInData,
                                       LVM_FLOAT             *pOutData,
-                                      LVM_UINT16            NumSamples)
-{
-
-    LVM_UINT16          i;
-    Biquad_FLOAT_Instance_t   *pBiquad;
+                                      const LVM_UINT16      NrFrames)
+{                                     // updated to use samples = frames * channels.
     LVEQNB_Instance_t   *pInstance = (LVEQNB_Instance_t  *)hInstance;
-    LVM_FLOAT           *pScratch;
 
+#ifdef SUPPORT_MC
+    // Mono passed in as stereo
+    const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
+        ? 2 : pInstance->Params.NrChannels;
+#else
+    const LVM_INT32 NrChannels = 2; // FCC_2
+#endif
+    const LVM_INT32 NrSamples = NrChannels * NrFrames;
 
      /* Check for NULL pointers */
     if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
@@ -82,14 +87,14 @@
         return LVEQNB_ALIGNMENTERROR;
     }
 
-    pScratch  = (LVM_FLOAT *)pInstance->pFastTemporary;
+    LVM_FLOAT * const pScratch = (LVM_FLOAT *)pInstance->pFastTemporary;
 
     /*
-    * Check the number of samples is not too large
+    * Check the number of frames is not too large
     */
-    if (NumSamples > pInstance->Capabilities.MaxBlockSize)
+    if (NrFrames > pInstance->Capabilities.MaxBlockSize)
     {
-        return(LVEQNB_TOOMANYSAMPLES);
+        return LVEQNB_TOOMANYSAMPLES;
     }
 
     if (pInstance->Params.OperatingMode == LVEQNB_ON)
@@ -97,16 +102,16 @@
         /*
          * Copy input data in to scratch buffer
          */
+        Copy_Float(pInData,     /* Source */
+                   pScratch,    /* Destination */
+                   (LVM_INT16)NrSamples);
 
-        Copy_Float((LVM_FLOAT *)pInData,      /* Source */
-                   pScratch,                  /* Destination */
-                   (LVM_INT16)(2 * NumSamples)); /* Left and Right */
         /*
          * For each section execte the filter unless the gain is 0dB
          */
         if (pInstance->NBands != 0)
         {
-            for (i = 0; i < pInstance->NBands; i++)
+            for (LVM_UINT16 i = 0; i < pInstance->NBands; i++)
             {
                 /*
                  * Check if band is non-zero dB gain
@@ -116,7 +121,7 @@
                     /*
                      * Get the address of the biquad instance
                      */
-                    pBiquad = &pInstance->pEQNB_FilterState_Float[i];
+                    Biquad_FLOAT_Instance_t *pBiquad = &pInstance->pEQNB_FilterState_Float[i];
 
 
                     /*
@@ -126,10 +131,18 @@
                     {
                         case LVEQNB_SinglePrecision_Float:
                         {
+#ifdef SUPPORT_MC
+                            PK_Mc_D32F32C14G11_TRC_WRA_01(pBiquad,
+                                                          pScratch,
+                                                          pScratch,
+                                                          (LVM_INT16)NrFrames,
+                                                          (LVM_INT16)NrChannels);
+#else
                             PK_2I_D32F32C14G11_TRC_WRA_01(pBiquad,
-                                                          (LVM_FLOAT *)pScratch,
-                                                          (LVM_FLOAT *)pScratch,
-                                                          (LVM_INT16)NumSamples);
+                                                          pScratch,
+                                                          pScratch,
+                                                          (LVM_INT16)NrFrames);
+#endif
                             break;
                         }
                         default:
@@ -141,19 +154,29 @@
 
 
         if(pInstance->bInOperatingModeTransition == LVM_TRUE){
+#ifdef SUPPORT_MC
+            LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->BypassMixer,
+                                       pScratch,
+                                       pInData,
+                                       pScratch,
+                                       (LVM_INT16)NrFrames,
+                                       (LVM_INT16)NrChannels);
+#else
             LVC_MixSoft_2St_D16C31_SAT(&pInstance->BypassMixer,
-                                       (LVM_FLOAT *)pScratch,
-                                       (LVM_FLOAT *)pInData,
-                                       (LVM_FLOAT *)pScratch,
-                                       (LVM_INT16)(2 * NumSamples));
-            Copy_Float((LVM_FLOAT*)pScratch,                           /* Source */
-                       pOutData,                                       /* Destination */
-                       (LVM_INT16)(2 * NumSamples));                     /* Left and Right samples */
+                                       pScratch,
+                                       pInData,
+                                       pScratch,
+                                       (LVM_INT16)NrSamples);
+#endif
+            // duplicate with else clause(s)
+            Copy_Float(pScratch,                         /* Source */
+                       pOutData,                         /* Destination */
+                       (LVM_INT16)NrSamples);            /* All channel samples */
         }
         else{
             Copy_Float(pScratch,              /* Source */
                        pOutData,              /* Destination */
-                       (LVM_INT16 )(2 * NumSamples)); /* Left and Right */
+                       (LVM_INT16)NrSamples); /* All channel samples */
         }
     }
     else
@@ -163,12 +186,12 @@
          */
         if (pInData != pOutData)
         {
-            Copy_Float(pInData,                                    /* Source */
-                       pOutData,                                   /* Destination */
-                       (LVM_INT16)(2 * NumSamples));                 /* Left and Right samples */
+            Copy_Float(pInData,                          /* Source */
+                       pOutData,                         /* Destination */
+                       (LVM_INT16)NrSamples);            /* All channel samples */
         }
     }
-    return(LVEQNB_SUCCESS);
+    return LVEQNB_SUCCESS;
 
 }
 #else
@@ -312,4 +335,4 @@
     return(LVEQNB_SUCCESS);
 
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
index 566d84f..1d1283e 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c
@@ -579,7 +579,7 @@
                                pTemp,
                                pTemp,
                                (LVM_INT16)NumSamples);
-    
+
     /*
      *  Process all delay lines
      */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
index a719053..8c7807f 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_SetControlParameters.c
@@ -64,12 +64,21 @@
         (
         (pNewParams->SampleRate != LVM_FS_8000) && (pNewParams->SampleRate != LVM_FS_11025) && (pNewParams->SampleRate != LVM_FS_12000)       &&
         (pNewParams->SampleRate != LVM_FS_16000) && (pNewParams->SampleRate != LVM_FS_22050) && (pNewParams->SampleRate != LVM_FS_24000)       &&
-        (pNewParams->SampleRate != LVM_FS_32000) && (pNewParams->SampleRate != LVM_FS_44100) && (pNewParams->SampleRate != LVM_FS_48000)      
+        (pNewParams->SampleRate != LVM_FS_32000) &&
+        (pNewParams->SampleRate != LVM_FS_44100) &&
+        (pNewParams->SampleRate != LVM_FS_48000)
 #ifdef HIGHER_FS
         && (pNewParams->SampleRate != LVM_FS_96000) && (pNewParams->SampleRate != LVM_FS_192000)
 #endif
         )
+#ifdef SUPPORT_MC
+        || ((pNewParams->SourceFormat != LVM_STEREO)       &&
+            (pNewParams->SourceFormat != LVM_MONOINSTEREO) &&
+            (pNewParams->SourceFormat != LVM_MONO)         &&
+            (pNewParams->SourceFormat != LVM_MULTICHANNEL)))
+#else
         || ((pNewParams->SourceFormat != LVM_STEREO) && (pNewParams->SourceFormat != LVM_MONOINSTEREO) && (pNewParams->SourceFormat != LVM_MONO)) )
+#endif
     {
         return (LVREV_OUTOFRANGE);
     }
diff --git a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
index e75695e..e507a7c 100644
--- a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
+++ b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
@@ -205,6 +205,9 @@
     LVM_Fs_en               SampleRate;             /* Sampling rate */
     LVM_INT16               EffectLevel;            /* Effect level */
     LVM_UINT16              ReverbLevel;            /* Reverb level in % */
+#ifdef SUPPORT_MC
+    LVM_INT32               NrChannels;
+#endif
 } LVCS_Params_t;
 
 
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
index a97e4f0..ab8ccd1 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
@@ -61,6 +61,15 @@
 
 /* Memory */
 #define LVCS_SCRATCHBUFFERS              6      /* Number of buffers required for inplace processing */
+#ifdef SUPPORT_MC
+/*
+ * The Concert Surround module applies processing only on the first two
+ * channels of a multichannel input. The data of first two channels is copied
+ * from the multichannel input into scratch buffer. The buffers added here
+ * are used for this purpose
+ */
+#define LVCS_MC_SCRATCHBUFFERS           2
+#endif
 
 /* General */
 #define LVCS_INVALID                0xFFFF      /* Invalid init parameter */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
index 3956d4d..ef1d9eb 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
@@ -76,6 +76,22 @@
     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
     LVM_FLOAT           *pScratch;
     LVCS_ReturnStatus_en err;
+#ifdef SUPPORT_MC
+    LVM_FLOAT           *pStIn;
+    LVM_INT32           channels = pInstance->Params.NrChannels;
+#define NrFrames NumSamples  // alias for clarity
+
+    /*In case of mono processing, stereo input is created from mono
+     *and stored in pInData before applying any of the effects.
+     *However we do not update the value pInstance->Params.NrChannels
+     *at this point.
+     *So to treat the pInData as stereo we are setting channels to 2
+     */
+    if (channels == 1)
+    {
+        channels = 2;
+    }
+#endif
 
     pScratch  = (LVM_FLOAT *) \
                   pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
@@ -83,6 +99,25 @@
     /*
      * Check if the processing is inplace
      */
+#ifdef SUPPORT_MC
+    /*
+     * The pInput buffer holds the first 2 (Left, Right) channels information.
+     * Hence the memory required by this buffer is 2 * NumFrames.
+     * The Concert Surround module carries out processing only on L, R.
+     */
+    pInput = pScratch + (2 * NrFrames);
+    pStIn  = pScratch + (LVCS_SCRATCHBUFFERS * NrFrames);
+    /* The first two channel data is extracted from the input data and
+     * copied into pInput buffer
+     */
+    Copy_Float_Mc_Stereo((LVM_FLOAT *)pInData,
+                         (LVM_FLOAT *)pInput,
+                         NrFrames,
+                         channels);
+    Copy_Float((LVM_FLOAT *)pInput,
+               (LVM_FLOAT *)pStIn,
+               (LVM_INT16)(2 * NrFrames));
+#else
     if (pInData == pOutData)
     {
         /* Processing inplace */
@@ -96,14 +131,21 @@
         /* Processing outplace */
         pInput = pInData;
     }
-
+#endif
     /*
      * Call the stereo enhancer
      */
+#ifdef SUPPORT_MC
+    err = LVCS_StereoEnhancer(hInstance,              /* Instance handle */
+                              pStIn,                  /* Pointer to the input data */
+                              pOutData,               /* Pointer to the output data */
+                              NrFrames);              /* Number of frames to process */
+#else
     err = LVCS_StereoEnhancer(hInstance,              /* Instance handle */
                               pInData,                    /* Pointer to the input data */
                               pOutData,                   /* Pointer to the output data */
                               NumSamples);                /* Number of samples to process */
+#endif
 
     /*
      * Call the reverb generator
@@ -112,7 +154,7 @@
                                pOutData,                  /* Pointer to the input data */
                                pOutData,                  /* Pointer to the output data */
                                NumSamples);               /* Number of samples to process */
-    
+
     /*
      * Call the equaliser
      */
@@ -239,7 +281,15 @@
 
     LVCS_Instance_t *pInstance = (LVCS_Instance_t  *)hInstance;
     LVCS_ReturnStatus_en err;
-
+#ifdef SUPPORT_MC
+    /*Extract number of Channels info*/
+    LVM_INT32 channels = pInstance->Params.NrChannels;
+#define NrFrames NumSamples  // alias for clarity
+    if (channels == 1)
+    {
+        channels = 2;
+    }
+#endif
     /*
      * Check the number of samples is not too large
      */
@@ -260,8 +310,8 @@
                                   pInData,
                                   pOutData,
                                   NumSamples);
-            
-            
+
+
         /*
          * Compress to reduce expansion effect of Concert Sound and correct volume
          * differences for difference settings. Not applied in test modes
@@ -376,17 +426,32 @@
                             (LVM_INT16)NumSamples);
             }
         }
+#ifdef SUPPORT_MC
+        Copy_Float_Stereo_Mc(pInData,
+                             pOutData,
+                             NrFrames,
+                             channels);
+#endif
     }
     else
     {
         if (pInData != pOutData)
         {
+#ifdef SUPPORT_MC
+            /*
+             * The algorithm is disabled so just copy the data
+             */
+            Copy_Float((LVM_FLOAT *)pInData,               /* Source */
+                       (LVM_FLOAT *)pOutData,                  /* Destination */
+                       (LVM_INT16)(channels * NrFrames));    /* All Channels*/
+#else
             /*
              * The algorithm is disabled so just copy the data
              */
             Copy_Float((LVM_FLOAT *)pInData,               /* Source */
                        (LVM_FLOAT *)pOutData,                  /* Destination */
                        (LVM_INT16)(2 * NumSamples));             /* Left and right */
+#endif
         }
     }
 
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
index e154e29..0765764 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Tables.c
@@ -515,16 +515,16 @@
 
 #if defined(BUILD_FLOAT) && defined(HIGHER_FS)
 const LVM_INT16 LVCS_VolumeTCTable[11] = {LVCS_VOL_TC_Fs8000,
-		                                  LVCS_VOL_TC_Fs11025,
-										  LVCS_VOL_TC_Fs12000,
-										  LVCS_VOL_TC_Fs16000,
-										  LVCS_VOL_TC_Fs22050,
-										  LVCS_VOL_TC_Fs24000,
-										  LVCS_VOL_TC_Fs32000,
-										  LVCS_VOL_TC_Fs44100,
-										  LVCS_VOL_TC_Fs48000,
-										  LVCS_VOL_TC_Fs96000,
-										  LVCS_VOL_TC_Fs192000
+                                          LVCS_VOL_TC_Fs11025,
+                                          LVCS_VOL_TC_Fs12000,
+                                          LVCS_VOL_TC_Fs16000,
+                                          LVCS_VOL_TC_Fs22050,
+                                          LVCS_VOL_TC_Fs24000,
+                                          LVCS_VOL_TC_Fs32000,
+                                          LVCS_VOL_TC_Fs44100,
+                                          LVCS_VOL_TC_Fs48000,
+                                          LVCS_VOL_TC_Fs96000,
+                                          LVCS_VOL_TC_Fs192000
 };
 #else
 const LVM_INT16 LVCS_VolumeTCTable[9] = {LVCS_VOL_TC_Fs8000,
@@ -546,16 +546,16 @@
 /************************************************************************************/
 #if defined(BUILD_FLOAT) && defined(HIGHER_FS)
 const LVM_INT32   LVCS_SampleRateTable[11] = {8000,
-		                                      11025,
-											  12000,
-											  16000,
-											  22050,
-											  24000,
-											  32000,
-											  44100,
-											  48000,
-											  96000,
-											  192000
+                                              11025,
+                                              12000,
+                                              16000,
+                                              22050,
+                                              24000,
+                                              32000,
+                                              44100,
+                                              48000,
+                                              96000,
+                                              192000
 };
 #else
 const LVM_INT16   LVCS_SampleRateTable[9] = {8000,
diff --git a/media/libeffects/lvm/tests/Android.bp b/media/libeffects/lvm/tests/Android.bp
new file mode 100644
index 0000000..8ee807c
--- /dev/null
+++ b/media/libeffects/lvm/tests/Android.bp
@@ -0,0 +1,46 @@
+// Build the unit tests for effects
+
+cc_test {
+    name: "lvmtest",
+    host_supported: false,
+    proprietary: true,
+
+    include_dirs: [
+        "frameworks/av/media/libeffects/lvm/lib/Bass/lib",
+        "frameworks/av/media/libeffects/lvm/lib/Bass/src",
+        "frameworks/av/media/libeffects/lvm/lib/Bundle/src",
+        "frameworks/av/media/libeffects/lvm/lib/Common/src",
+        "frameworks/av/media/libeffects/lvm/lib/Eq/lib",
+        "frameworks/av/media/libeffects/lvm/lib/Eq/src",
+        "frameworks/av/media/libeffects/lvm/lib/SpectrumAnalyzer/lib",
+        "frameworks/av/media/libeffects/lvm/lib/SpectrumAnalyzer/src",
+        "frameworks/av/media/libeffects/lvm/lib/StereoWidening/lib",
+        "frameworks/av/media/libeffects/lvm/lib/StereoWidening/src",
+        "frameworks/av/media/libeffects/lvm/wrapper/Bundle",
+    ],
+
+    header_libs: [
+        "libaudioeffects",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libmusicbundle",
+    ],
+
+    srcs: ["lvmtest.cpp"],
+
+    cflags: [
+        "-DBUILD_FLOAT",
+        "-DHIGHER_FS",
+        "-DSUPPORT_MC",
+
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
diff --git a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..340469a
--- /dev/null
+++ b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    echo "Android build environment not set"
+    exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm -j
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount
+
+# location of test files
+testdir="/data/local/tmp/lvmTest"
+
+#flags="-bE -tE -eqE -csE"
+flags="-csE -tE -eqE"
+
+
+echo "========================================"
+echo "testing lvm"
+adb shell mkdir $testdir
+adb push $ANDROID_BUILD_TOP/cts/tests/tests/media/res/raw/sinesweepraw.raw $testdir
+adb push $OUT/testcases/lvmtest/arm64/lvmtest $testdir
+
+# run multichannel effects at different channel counts, saving only the stereo channel pair.
+adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw -o:$testdir/sinesweep_1.raw\
+                          -ch:1 -fs:44100 $flags
+adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw -o:$testdir/sinesweep_2.raw\
+                           -ch:2 -fs:44100 $flags
+adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw -o:$testdir/sinesweep_4.raw\
+                           -ch:4 -fs:44100 $flags
+adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw -o:$testdir/sinesweep_6.raw\
+                           -ch:6 -fs:44100 $flags
+adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw -o:$testdir/sinesweep_8.raw\
+                           -ch:8 -fs:44100 $flags
+
+# two channel files should be identical to higher channel computation (first 2 channels).
+adb shell cmp $testdir/sinesweep_2.raw $testdir/sinesweep_2.raw
+adb shell cmp $testdir/sinesweep_2.raw $testdir/sinesweep_4.raw
+adb shell cmp $testdir/sinesweep_2.raw $testdir/sinesweep_6.raw
+adb shell cmp $testdir/sinesweep_2.raw $testdir/sinesweep_8.raw
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
new file mode 100644
index 0000000..01c5955
--- /dev/null
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -0,0 +1,682 @@
+/*
+ * Copyright (C) 2011 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 <assert.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vector>
+
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <log/log.h>
+
+#include "EffectBundle.h"
+#include "LVM_Private.h"
+
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) \
+  do {               \
+  } while (false)
+#endif
+
+#define CHECK_ARG(cond)                                \
+  {                                                    \
+    if (!(cond)) {                                     \
+      ALOGE("\tLVM_ERROR : Invalid argument: " #cond); \
+      return -EINVAL;                                  \
+    }                                                  \
+  \
+}
+
+#define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc)     \
+  {                                                             \
+    if ((LvmStatus) == LVM_NULLADDRESS) {                       \
+      ALOGE(                                                    \
+          "\tLVM_ERROR : Parameter error - "                    \
+          "null pointer returned by %s in %s\n\n\n\n",          \
+          callingFunc, calledFunc);                             \
+    }                                                           \
+    if ((LvmStatus) == LVM_ALIGNMENTERROR) {                    \
+      ALOGE(                                                    \
+          "\tLVM_ERROR : Parameter error - "                    \
+          "bad alignment returned by %s in %s\n\n\n\n",         \
+          callingFunc, calledFunc);                             \
+    }                                                           \
+    if ((LvmStatus) == LVM_INVALIDNUMSAMPLES) {                 \
+      ALOGE(                                                    \
+          "\tLVM_ERROR : Parameter error - "                    \
+          "bad number of samples returned by %s in %s\n\n\n\n", \
+          callingFunc, calledFunc);                             \
+    }                                                           \
+    if ((LvmStatus) == LVM_OUTOFRANGE) {                        \
+      ALOGE(                                                    \
+          "\tLVM_ERROR : Parameter error - "                    \
+          "out of range returned by %s in %s\n",                \
+          callingFunc, calledFunc);                             \
+    }                                                           \
+  }
+
+struct lvmConfigParams_t {
+  int              samplingFreq    = 44100;
+  int              nrChannels      = 2;
+  int              fChannels       = 2;
+  int              bassEffectLevel = 0;
+  int              eqPresetLevel   = 0;
+  int              frameLength     = 256;
+  LVM_BE_Mode_en   bassEnable      = LVM_BE_OFF;
+  LVM_TE_Mode_en   trebleEnable    = LVM_TE_OFF;
+  LVM_EQNB_Mode_en eqEnable        = LVM_EQNB_OFF;
+  LVM_Mode_en      csEnable        = LVM_MODE_OFF;
+};
+
+void printUsage() {
+  printf("\nUsage: ");
+  printf("\n     <exceutable> -i:<input_file> -o:<out_file> [options]\n");
+  printf("\nwhere, \n     <inputfile>  is the input file name");
+  printf("\n                  on which LVM effects are applied");
+  printf("\n     <outputfile> processed output file");
+  printf("\n     and options are mentioned below");
+  printf("\n");
+  printf("\n     -help (or) -h");
+  printf("\n           Prints this usage information");
+  printf("\n");
+  printf("\n     -ch:<process_channels> (1 through 8)\n\n");
+  printf("\n     -fch:<file_channels> (1 through 8)\n\n");
+  printf("\n     -basslvl:<effect_level>");
+  printf("\n           A value that ranges between 0 - 15 default 0");
+  printf("\n");
+  printf("\n     -eqPreset:<preset Value>");
+  printf("\n           0 - Normal");
+  printf("\n           1 - Classical");
+  printf("\n           2 - Dance");
+  printf("\n           3 - Flat");
+  printf("\n           4 - Folk");
+  printf("\n           5 - Heavy Metal");
+  printf("\n           6 - Hip Hop");
+  printf("\n           7 - Jazz");
+  printf("\n           8 - Pop");
+  printf("\n           9 - Rock");
+  printf("\n           default 0");
+  printf("\n     -bE ");
+  printf("\n           Enable Dynamic Bass Enhancement");
+  printf("\n");
+  printf("\n     -tE ");
+  printf("\n           Enable Treble Boost");
+  printf("\n");
+  printf("\n     -csE ");
+  printf("\n           Enable Concert Surround");
+  printf("\n");
+  printf("\n     -eqE ");
+  printf("\n           Enable Equalizer");
+}
+
+//----------------------------------------------------------------------------
+// LvmEffect_free()
+//----------------------------------------------------------------------------
+// Purpose: Free all memory associated with the Bundle.
+//
+// Inputs:
+//  pContext:   effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+void LvmEffect_free(struct EffectContext *pContext) {
+  LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
+  LVM_MemTab_t MemTab;
+
+  /* Free the algorithm memory */
+  LvmStatus = LVM_GetMemoryTable(pContext->pBundledContext->hInstance, &MemTab,
+                                 LVM_NULL);
+
+  LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmEffect_free")
+
+  for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
+    if (MemTab.Region[i].Size != 0) {
+      if (MemTab.Region[i].pBaseAddress != NULL) {
+        ALOGV("\tLvmEffect_free - START freeing %" PRIu32
+              " bytes for region %u at %p\n",
+              MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
+
+        free(MemTab.Region[i].pBaseAddress);
+
+        ALOGV("\tLvmEffect_free - END   freeing %" PRIu32
+              " bytes for region %u at %p\n",
+              MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
+      } else {
+        ALOGE(
+            "\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer "
+            "%" PRIu32 " bytes for region %u at %p ERROR\n",
+            MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
+      }
+    }
+  }
+} /* end LvmEffect_free */
+
+//----------------------------------------------------------------------------
+// LvmBundle_init()
+//----------------------------------------------------------------------------
+// Purpose: Initialize engine with default configuration, creates instance
+// with all effects disabled.
+//
+// Inputs:
+//  pContext:   effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int LvmBundle_init(struct EffectContext *pContext, LVM_ControlParams_t *params) {
+  ALOGV("\tLvmBundle_init start");
+
+  pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+  pContext->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+  pContext->config.inputCfg.format = EFFECT_BUFFER_FORMAT;
+  pContext->config.inputCfg.samplingRate = 44100;
+  pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
+  pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+  pContext->config.inputCfg.bufferProvider.cookie = NULL;
+  pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+  pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+  pContext->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+  pContext->config.outputCfg.format = EFFECT_BUFFER_FORMAT;
+  pContext->config.outputCfg.samplingRate = 44100;
+  pContext->config.outputCfg.bufferProvider.getBuffer = NULL;
+  pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+  pContext->config.outputCfg.bufferProvider.cookie = NULL;
+  pContext->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+  if (pContext->pBundledContext->hInstance != NULL) {
+    ALOGV(
+        "\tLvmBundle_init pContext->pBassBoost != NULL "
+        "-> Calling pContext->pBassBoost->free()");
+
+    LvmEffect_free(pContext);
+
+    ALOGV(
+        "\tLvmBundle_init pContext->pBassBoost != NULL "
+        "-> Called pContext->pBassBoost->free()");
+  }
+
+  LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
+  LVM_InstParams_t InstParams;                 /* Instance parameters */
+  LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS];  /* Equaliser band definitions */
+  LVM_HeadroomParams_t HeadroomParams;         /* Headroom parameters */
+  LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS];
+  LVM_MemTab_t MemTab; /* Memory allocation table */
+  bool bMallocFailure = LVM_FALSE;
+
+  /* Set the capabilities */
+  InstParams.BufferMode = LVM_UNMANAGED_BUFFERS;
+  InstParams.MaxBlockSize = MAX_CALL_SIZE;
+  InstParams.EQNB_NumBands = MAX_NUM_BANDS;
+  InstParams.PSA_Included = LVM_PSA_ON;
+
+  /* Allocate memory, forcing alignment */
+  LvmStatus = LVM_GetMemoryTable(LVM_NULL, &MemTab, &InstParams);
+
+  LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmBundle_init");
+  if (LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+  ALOGV("\tCreateInstance Succesfully called LVM_GetMemoryTable\n");
+
+  /* Allocate memory */
+  for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
+    if (MemTab.Region[i].Size != 0) {
+      MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
+
+      if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
+        ALOGE(
+            "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
+            "%" PRIu32 " bytes for region %u\n",
+            MemTab.Region[i].Size, i);
+        bMallocFailure = LVM_TRUE;
+        break;
+      } else {
+        ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32
+              " bytes for region %u at %p\n",
+              MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
+      }
+    }
+  }
+
+  /* If one or more of the memory regions failed to allocate, free the regions
+   * that were
+   * succesfully allocated and return with an error
+   */
+  if (bMallocFailure == LVM_TRUE) {
+    for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
+      if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
+        ALOGE(
+            "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
+            "%" PRIu32 " bytes for region %u Not freeing\n",
+            MemTab.Region[i].Size, i);
+      } else {
+        ALOGE(
+            "\tLVM_ERROR :LvmBundle_init CreateInstance Failed: but allocated "
+            "%" PRIu32 " bytes for region %u at %p- free\n",
+            MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
+        free(MemTab.Region[i].pBaseAddress);
+      }
+    }
+    return -EINVAL;
+  }
+  ALOGV("\tLvmBundle_init CreateInstance Succesfully malloc'd memory\n");
+
+  /* Initialise */
+  pContext->pBundledContext->hInstance = LVM_NULL;
+
+  /* Init sets the instance handle */
+  LvmStatus = LVM_GetInstanceHandle(&pContext->pBundledContext->hInstance,
+                                    &MemTab, &InstParams);
+
+  LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "LvmBundle_init");
+  if (LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+  ALOGV(
+      "\tLvmBundle_init CreateInstance Succesfully called "
+      "LVM_GetInstanceHandle\n");
+
+  /* Set the initial process parameters */
+  /* General parameters */
+  params->OperatingMode = LVM_MODE_ON;
+  params->SampleRate = LVM_FS_44100;
+  params->SourceFormat = LVM_STEREO;
+  params->SpeakerType = LVM_HEADPHONES;
+
+  pContext->pBundledContext->SampleRate = LVM_FS_44100;
+
+  /* Concert Sound parameters */
+  params->VirtualizerOperatingMode = LVM_MODE_OFF;
+  params->VirtualizerType = LVM_CONCERTSOUND;
+  params->VirtualizerReverbLevel = 100;
+  params->CS_EffectLevel = LVM_CS_EFFECT_NONE;
+
+  /* N-Band Equaliser parameters */
+  params->EQNB_OperatingMode = LVM_EQNB_ON;
+  params->EQNB_NBands = FIVEBAND_NUMBANDS;
+  params->pEQNB_BandDefinition = &BandDefs[0];
+
+  for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+    BandDefs[i].Frequency = EQNB_5BandPresetsFrequencies[i];
+    BandDefs[i].QFactor = EQNB_5BandPresetsQFactors[i];
+    BandDefs[i].Gain = EQNB_5BandSoftPresets[i];
+  }
+
+  /* Volume Control parameters */
+  params->VC_EffectLevel = 0;
+  params->VC_Balance = 0;
+
+  /* Treble Enhancement parameters */
+  params->TE_OperatingMode = LVM_TE_OFF;
+  params->TE_EffectLevel = 0;
+
+  /* PSA Control parameters */
+  params->PSA_Enable = LVM_PSA_OFF;
+  params->PSA_PeakDecayRate = (LVM_PSA_DecaySpeed_en)0;
+
+  /* Bass Enhancement parameters */
+  params->BE_OperatingMode = LVM_BE_ON;
+  params->BE_EffectLevel = 0;
+  params->BE_CentreFreq = LVM_BE_CENTRE_90Hz;
+  params->BE_HPF = LVM_BE_HPF_ON;
+
+  /* PSA Control parameters */
+  params->PSA_Enable = LVM_PSA_OFF;
+  params->PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
+
+  /* TE Control parameters */
+  params->TE_OperatingMode = LVM_TE_OFF;
+  params->TE_EffectLevel = 0;
+
+  /* Activate the initial settings */
+  LvmStatus =
+      LVM_SetControlParameters(pContext->pBundledContext->hInstance, params);
+
+  LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmBundle_init");
+  if (LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+  ALOGV(
+      "\tLvmBundle_init CreateInstance Succesfully called "
+      "LVM_SetControlParameters\n");
+
+  /* Set the headroom parameters */
+  HeadroomBandDef[0].Limit_Low = 20;
+  HeadroomBandDef[0].Limit_High = 4999;
+  HeadroomBandDef[0].Headroom_Offset = 0;
+  HeadroomBandDef[1].Limit_Low = 5000;
+  HeadroomBandDef[1].Limit_High = 24000;
+  HeadroomBandDef[1].Headroom_Offset = 0;
+  HeadroomParams.pHeadroomDefinition = &HeadroomBandDef[0];
+  HeadroomParams.Headroom_OperatingMode = LVM_HEADROOM_ON;
+  HeadroomParams.NHeadroomBands = 2;
+
+  LvmStatus = LVM_SetHeadroomParams(pContext->pBundledContext->hInstance,
+                                    &HeadroomParams);
+
+  LVM_ERROR_CHECK(LvmStatus, "LVM_SetHeadroomParams", "LvmBundle_init");
+  if (LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+  ALOGV(
+      "\tLvmBundle_init CreateInstance Succesfully called "
+      "LVM_SetHeadroomParams\n");
+  ALOGV("\tLvmBundle_init End");
+  return 0;
+} /* end LvmBundle_init */
+
+int lvmCreate(struct EffectContext *pContext,
+              lvmConfigParams_t    *plvmConfigParams,
+              LVM_ControlParams_t  *params) {
+  int ret = 0;
+  pContext->pBundledContext = NULL;
+  pContext->pBundledContext = (BundledEffectContext *)malloc(sizeof(struct BundledEffectContext));
+  if (NULL == pContext->pBundledContext) {
+    return -EINVAL;
+  }
+
+  pContext->pBundledContext->SessionNo = 0;
+  pContext->pBundledContext->SessionId = 0;
+  pContext->pBundledContext->hInstance = NULL;
+  pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
+  pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
+  pContext->pBundledContext->bBassEnabled = LVM_FALSE;
+  pContext->pBundledContext->bBassTempDisabled = LVM_FALSE;
+  pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
+  pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE;
+  pContext->pBundledContext->nOutputDevice = AUDIO_DEVICE_NONE;
+  pContext->pBundledContext->nVirtualizerForcedDevice = AUDIO_DEVICE_NONE;
+  pContext->pBundledContext->NumberEffectsEnabled = 0;
+  pContext->pBundledContext->NumberEffectsCalled = 0;
+  pContext->pBundledContext->firstVolume = LVM_TRUE;
+  pContext->pBundledContext->volume = 0;
+
+  /* Saved strength is used to return the exact strength that was used in the
+   * set to the get
+   * because we map the original strength range of 0:1000 to 1:15, and this will
+   * avoid
+   * quantisation like effect when returning
+   */
+  pContext->pBundledContext->BassStrengthSaved = 0;
+  pContext->pBundledContext->VirtStrengthSaved = 0;
+  pContext->pBundledContext->CurPreset = PRESET_CUSTOM;
+  pContext->pBundledContext->levelSaved = 0;
+  pContext->pBundledContext->bMuteEnabled = LVM_FALSE;
+  pContext->pBundledContext->bStereoPositionEnabled = LVM_FALSE;
+  pContext->pBundledContext->positionSaved = 0;
+  pContext->pBundledContext->workBuffer = NULL;
+  pContext->pBundledContext->frameCount = -1;
+  pContext->pBundledContext->SamplesToExitCountVirt = 0;
+  pContext->pBundledContext->SamplesToExitCountBb = 0;
+  pContext->pBundledContext->SamplesToExitCountEq = 0;
+#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
+  pContext->pBundledContext->pInputBuffer = NULL;
+  pContext->pBundledContext->pOutputBuffer = NULL;
+#endif
+  for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+    pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
+  }
+  pContext->config.inputCfg.channels = plvmConfigParams->nrChannels;
+  ALOGV("\tEffectCreate - Calling LvmBundle_init");
+  ret = LvmBundle_init(pContext, params);
+
+  if (ret < 0) {
+    ALOGE("\tLVM_ERROR : lvmCreate() Bundle init failed");
+    return ret;
+  }
+  return 0;
+}
+
+int lvmControl(struct EffectContext *pContext,
+               lvmConfigParams_t    *plvmConfigParams,
+               LVM_ControlParams_t  *params) {
+  LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
+  LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS];  /* Equaliser band definitions */
+  int eqPresetLevel = plvmConfigParams->eqPresetLevel;
+  int nrChannels = plvmConfigParams->nrChannels;
+  params->NrChannels = nrChannels;
+
+  /* Set the initial process parameters */
+  /* General parameters */
+  params->OperatingMode = LVM_MODE_ON;
+  params->SampleRate = LVM_FS_44100;
+  params->SourceFormat = LVM_STEREO;
+  params->SpeakerType = LVM_HEADPHONES;
+
+  pContext->pBundledContext->SampleRate = LVM_FS_44100;
+
+  /* Concert Sound parameters */
+  params->VirtualizerOperatingMode = plvmConfigParams->csEnable;
+  params->VirtualizerType = LVM_CONCERTSOUND;
+  params->VirtualizerReverbLevel = 100;
+  params->CS_EffectLevel = LVM_CS_EFFECT_NONE;
+
+  /* N-Band Equaliser parameters */
+  params->EQNB_OperatingMode = plvmConfigParams->eqEnable;
+  params->pEQNB_BandDefinition = &BandDefs[0];
+  for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+    BandDefs[i].Frequency = EQNB_5BandPresetsFrequencies[i];
+    BandDefs[i].QFactor = EQNB_5BandPresetsQFactors[i];
+    BandDefs[i].Gain =
+        EQNB_5BandSoftPresets[(FIVEBAND_NUMBANDS * eqPresetLevel) + i];
+  }
+
+  /* Volume Control parameters */
+  params->VC_EffectLevel = 0;
+  params->VC_Balance = 0;
+
+  /* Treble Enhancement parameters */
+  params->TE_OperatingMode = plvmConfigParams->trebleEnable;
+
+  /* PSA Control parameters */
+  params->PSA_Enable = LVM_PSA_ON;
+
+  /* Bass Enhancement parameters */
+  params->BE_OperatingMode = plvmConfigParams->bassEnable;
+
+  if (nrChannels == 1) {
+    params->SourceFormat = LVM_MONO;
+  }
+  if (nrChannels == 2) {
+    params->SourceFormat = LVM_STEREO;
+  }
+  if ((nrChannels > 2) && (nrChannels <= 8)) {
+    params->SourceFormat = LVM_MULTICHANNEL;
+  }
+
+  /* Activate the initial settings */
+  LvmStatus =
+      LVM_SetControlParameters(pContext->pBundledContext->hInstance, params);
+
+  LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmBundle_init");
+  if (LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+  LvmStatus = LVM_ApplyNewSettings(pContext->pBundledContext->hInstance);
+
+  if (LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+  return 0;
+}
+
+int lvmExecute(float *floatIn, float *floatOut, struct EffectContext *pContext,
+               lvmConfigParams_t *plvmConfigParams) {
+  const int frameLength = plvmConfigParams->frameLength;
+  return
+      LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
+                  floatIn,                              /* Input buffer */
+                  floatOut,                             /* Output buffer */
+                  (LVM_UINT16)frameLength, /* Number of samples to read */
+                  0);                      /* Audio Time */
+}
+
+int lvmMainProcess(lvmConfigParams_t *plvmConfigParams, FILE *finp, FILE *fout) {
+  struct EffectContext context;
+  LVM_ControlParams_t params;
+
+  int errCode = lvmCreate(&context, plvmConfigParams, &params);
+  if (errCode) {
+    ALOGE("Error: lvmCreate returned with %d\n", errCode);
+    return errCode;
+  }
+
+  errCode = lvmControl(&context, plvmConfigParams, &params);
+  if (errCode) {
+    ALOGE("Error: lvmControl returned with %d\n", errCode);
+    return errCode;
+  }
+
+  const int channelCount = plvmConfigParams->nrChannels;
+  const int frameLength = plvmConfigParams->frameLength;
+  const int frameSize = channelCount * sizeof(float);  // processing size
+  const int ioChannelCount = plvmConfigParams->fChannels;
+  const int ioFrameSize = ioChannelCount * sizeof(short); // file load size
+  const int maxChannelCount = std::max(channelCount, ioChannelCount);
+  /*
+   * Mono input will be converted to 2 channels internally in the process call
+   * by copying the same data into the second channel.
+   * Hence when channelCount is 1, output buffer should be allocated for
+   * 2 channels. The memAllocChCount takes care of allocation of sufficient
+   * memory for the output buffer.
+   */
+  const int memAllocChCount = (channelCount == 1 ? 2 : channelCount);
+
+  std::vector<short> in(frameLength * maxChannelCount);
+  std::vector<short> out(frameLength * maxChannelCount);
+  std::vector<float> floatIn(frameLength * channelCount);
+  std::vector<float> floatOut(frameLength * memAllocChCount);
+
+  int frameCounter = 0;
+  while (fread(in.data(), ioFrameSize, frameLength, finp) == (size_t)frameLength) {
+    if (ioChannelCount != channelCount) {
+        adjust_channels(in.data(), ioChannelCount, in.data(), channelCount,
+               sizeof(short), frameLength * ioFrameSize);
+    }
+    memcpy_to_float_from_i16(floatIn.data(), in.data(), frameLength * channelCount);
+
+#if 1
+    errCode = lvmExecute(floatIn.data(), floatOut.data(), &context, plvmConfigParams);
+    if (errCode) {
+      printf("\nError: lvmExecute returned with %d\n", errCode);
+      return errCode;
+    }
+
+    (void)frameSize; // eliminate warning
+#else
+    memcpy(floatOut.data(), floatIn.data(), frameLength * frameSize);
+#endif
+    memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * channelCount);
+    if (ioChannelCount != channelCount) {
+        adjust_channels(out.data(), channelCount, out.data(), ioChannelCount,
+               sizeof(short), frameLength * channelCount * sizeof(short));
+    }
+    (void) fwrite(out.data(), ioFrameSize, frameLength, fout);
+    frameCounter += frameLength;
+  }
+  printf("frameCounter: [%d]\n", frameCounter);
+  return 0;
+}
+
+int main(int argc, const char *argv[]) {
+  if (argc == 1) {
+    printUsage();
+    return -1;
+  }
+
+  lvmConfigParams_t lvmConfigParams{}; // default initialize
+  FILE *finp = nullptr, *fout = nullptr;
+
+  for (int i = 1; i < argc; i++) {
+    printf("%s ", argv[i]);
+    if (!strncmp(argv[i], "-i:", 3)) {
+      finp = fopen(argv[i] + 3, "rb");
+    } else if (!strncmp(argv[i], "-o:", 3)) {
+      fout = fopen(argv[i] + 3, "wb");
+    } else if (!strncmp(argv[i], "-fs:", 4)) {
+      const int samplingFreq = atoi(argv[i] + 4);
+      if (samplingFreq != 8000 && samplingFreq != 11025 &&
+          samplingFreq != 12000 && samplingFreq != 16000 &&
+          samplingFreq != 22050 && samplingFreq != 24000 &&
+          samplingFreq != 32000 && samplingFreq != 44100 &&
+          samplingFreq != 48000 && samplingFreq != 96000) {
+        ALOGE("\nError: Unsupported Sampling Frequency : %d\n", samplingFreq);
+        return -1;
+      }
+      lvmConfigParams.samplingFreq = samplingFreq;
+    } else if (!strncmp(argv[i], "-ch:", 4)) {
+      const int nrChannels = atoi(argv[i] + 4);
+      if (nrChannels > 8 || nrChannels < 1) {
+        ALOGE("\nError: Unsupported number of channels : %d\n", nrChannels);
+        return -1;
+      }
+      lvmConfigParams.nrChannels = nrChannels;
+    } else if (!strncmp(argv[i], "-fch:", 5)) {
+      const int fChannels = atoi(argv[i] + 5);
+      if (fChannels > 8 || fChannels < 1) {
+             ALOGE("\nError: Unsupported number of file channels : %d\n", fChannels);
+             return -1;
+           }
+           lvmConfigParams.fChannels = fChannels;
+    } else if (!strncmp(argv[i], "-basslvl:", 9)) {
+      const int bassEffectLevel = atoi(argv[i] + 9);
+      if (bassEffectLevel > 15 || bassEffectLevel < 0) {
+        ALOGE("\nError: Unsupported Bass Effect Level : %d\n",
+               bassEffectLevel);
+        printUsage();
+        return -1;
+      }
+      lvmConfigParams.bassEffectLevel = bassEffectLevel;
+    } else if (!strncmp(argv[i], "-eqPreset:", 10)) {
+      const int eqPresetLevel = atoi(argv[i] + 10);
+      if (eqPresetLevel > 9 || eqPresetLevel < 0) {
+        ALOGE("\nError: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
+        printUsage();
+        return -1;
+      }
+      lvmConfigParams.eqPresetLevel = eqPresetLevel;
+    } else if (!strcmp(argv[i], "-bE")) {
+      lvmConfigParams.bassEnable = LVM_BE_ON;
+    } else if (!strcmp(argv[i], "-eqE")) {
+      lvmConfigParams.eqEnable = LVM_EQNB_ON;
+    } else if (!strcmp(argv[i], "-tE")) {
+      lvmConfigParams.trebleEnable = LVM_TE_ON;
+    } else if (!strcmp(argv[i], "-csE")) {
+      lvmConfigParams.csEnable = LVM_MODE_ON;
+    } else if (!strcmp(argv[i], "-h")) {
+      printUsage();
+      return 0;
+    }
+  }
+
+  if (finp == nullptr || fout == nullptr) {
+    ALOGE("\nError: missing input/output files\n");
+    printUsage();
+    // ok not to close.
+    return -1;
+  }
+
+  const int errCode = lvmMainProcess(&lvmConfigParams, finp, fout);
+  fclose(finp);
+  fclose(fout);
+
+  if (errCode) {
+    ALOGE("Error: lvmMainProcess returns with the error: %d \n", errCode);
+    return -1;
+  }
+  return 0;
+}
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index 10fd970..16fa126 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -18,6 +18,7 @@
         "-fvisibility=hidden",
         "-DBUILD_FLOAT",
         "-DHIGHER_FS",
+        "-DSUPPORT_MC",
 
         "-Wall",
         "-Werror",
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 53d266a..09e9964 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -435,7 +435,7 @@
             (pSessionContext->bEqualizerInstantiated ==LVM_FALSE) &&
             (pSessionContext->bVirtualizerInstantiated==LVM_FALSE))
     {
-        #ifdef LVM_PCM
+#ifdef LVM_PCM
         if (pContext->pBundledContext->PcmInPtr != NULL) {
             fclose(pContext->pBundledContext->PcmInPtr);
             pContext->pBundledContext->PcmInPtr = NULL;
@@ -444,7 +444,7 @@
             fclose(pContext->pBundledContext->PcmOutPtr);
             pContext->pBundledContext->PcmOutPtr = NULL;
         }
-        #endif
+#endif
 
 
         // Clear the SessionIndex
@@ -751,19 +751,21 @@
 
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
     effect_buffer_t         *pOutTmp;
+    const LVM_INT32 NrChannels =
+        audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
 #ifndef NATIVE_FLOAT_BUFFER
     if (pContext->pBundledContext->pInputBuffer == nullptr ||
             pContext->pBundledContext->frameCount < frameCount) {
         free(pContext->pBundledContext->pInputBuffer);
         pContext->pBundledContext->pInputBuffer =
-                (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * FCC_2);
+                (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * NrChannels);
     }
 
     if (pContext->pBundledContext->pOutputBuffer == nullptr ||
             pContext->pBundledContext->frameCount < frameCount) {
         free(pContext->pBundledContext->pOutputBuffer);
         pContext->pBundledContext->pOutputBuffer =
-                (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * FCC_2);
+                (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * NrChannels);
     }
 
     if (pContext->pBundledContext->pInputBuffer == nullptr ||
@@ -784,7 +786,7 @@
                 free(pContext->pBundledContext->workBuffer);
             }
             pContext->pBundledContext->workBuffer =
-                    (effect_buffer_t *)calloc(frameCount, sizeof(effect_buffer_t) * FCC_2);
+                    (effect_buffer_t *)calloc(frameCount, sizeof(effect_buffer_t) * NrChannels);
             if (pContext->pBundledContext->workBuffer == NULL) {
                 return -ENOMEM;
             }
@@ -798,13 +800,15 @@
 
 #ifdef LVM_PCM
     fwrite(pIn,
-            frameCount*sizeof(effect_buffer_t) * FCC_2, 1, pContext->pBundledContext->PcmInPtr);
+           frameCount * sizeof(effect_buffer_t) * NrChannels,
+           1,
+           pContext->pBundledContext->PcmInPtr);
     fflush(pContext->pBundledContext->PcmInPtr);
 #endif
 
 #ifndef NATIVE_FLOAT_BUFFER
     /* Converting input data from fixed point to float point */
-    memcpy_to_float_from_i16(pInputBuff, pIn, frameCount * FCC_2);
+    memcpy_to_float_from_i16(pInputBuff, pIn, frameCount * NrChannels);
 
     /* Process the samples */
     LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
@@ -814,7 +818,7 @@
                             0);                                   /* Audio Time */
 
     /* Converting output data from float point to fixed point */
-    memcpy_to_i16_from_float(pOutTmp, pOutputBuff, frameCount * FCC_2);
+    memcpy_to_i16_from_float(pOutTmp, pOutputBuff, frameCount * NrChannels);
 
 #else
     /* Process the samples */
@@ -829,12 +833,14 @@
 
 #ifdef LVM_PCM
     fwrite(pOutTmp,
-            frameCount*sizeof(effect_buffer_t) * FCC_2, 1, pContext->pBundledContext->PcmOutPtr);
+           frameCount * sizeof(effect_buffer_t) * NrChannels,
+           1,
+           pContext->pBundledContext->PcmOutPtr);
     fflush(pContext->pBundledContext->PcmOutPtr);
 #endif
 
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
-        for (int i = 0; i < frameCount * FCC_2; i++) {
+        for (int i = 0; i < frameCount * NrChannels; i++) {
 #ifndef NATIVE_FLOAT_BUFFER
             pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
 #else
@@ -1232,45 +1238,50 @@
     CHECK_ARG(pConfig->inputCfg.samplingRate == pConfig->outputCfg.samplingRate);
     CHECK_ARG(pConfig->inputCfg.channels == pConfig->outputCfg.channels);
     CHECK_ARG(pConfig->inputCfg.format == pConfig->outputCfg.format);
+#ifdef SUPPORT_MC
+    CHECK_ARG(audio_channel_count_from_out_mask(pConfig->inputCfg.channels) <= LVM_MAX_CHANNELS);
+#else
     CHECK_ARG(pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO);
+#endif
     CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
               || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
     CHECK_ARG(pConfig->inputCfg.format == EFFECT_BUFFER_FORMAT);
     pContext->config = *pConfig;
+    const LVM_INT16 NrChannels = audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
 
     switch (pConfig->inputCfg.samplingRate) {
     case 8000:
         SampleRate = LVM_FS_8000;
-        pContext->pBundledContext->SamplesPerSecond = 8000*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 8000 * NrChannels;
         break;
     case 16000:
         SampleRate = LVM_FS_16000;
-        pContext->pBundledContext->SamplesPerSecond = 16000*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 16000 * NrChannels;
         break;
     case 22050:
         SampleRate = LVM_FS_22050;
-        pContext->pBundledContext->SamplesPerSecond = 22050*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 22050 * NrChannels;
         break;
     case 32000:
         SampleRate = LVM_FS_32000;
-        pContext->pBundledContext->SamplesPerSecond = 32000*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 32000 * NrChannels;
         break;
     case 44100:
         SampleRate = LVM_FS_44100;
-        pContext->pBundledContext->SamplesPerSecond = 44100*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 44100 * NrChannels;
         break;
     case 48000:
         SampleRate = LVM_FS_48000;
-        pContext->pBundledContext->SamplesPerSecond = 48000*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 48000 * NrChannels;
         break;
 #if defined(BUILD_FLOAT) && defined(HIGHER_FS)
     case 96000:
         SampleRate = LVM_FS_96000;
-        pContext->pBundledContext->SamplesPerSecond = 96000*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 96000 * NrChannels;
         break;
     case 192000:
         SampleRate = LVM_FS_192000;
-        pContext->pBundledContext->SamplesPerSecond = 192000*2; // 2 secs Stereo
+        pContext->pBundledContext->SamplesPerSecond = 192000 * NrChannels;
         break;
 #endif
     default:
@@ -1294,6 +1305,10 @@
 
         ActiveParams.SampleRate = SampleRate;
 
+#ifdef SUPPORT_MC
+        ActiveParams.NrChannels = NrChannels;
+#endif
+
         LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
 
         LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_setConfig")
@@ -1498,6 +1513,7 @@
     case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
     case AUDIO_DEVICE_OUT_USB_HEADSET:
+    // case AUDIO_DEVICE_OUT_USB_DEVICE:  // For USB testing of the virtualizer only.
         return 0;
     default :
         return -EINVAL;
@@ -1520,10 +1536,9 @@
 int VirtualizerIsConfigurationSupported(audio_channel_mask_t channelMask,
         audio_devices_t deviceType) {
     uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
-    if ((channelCount == 0) || (channelCount > 2)) {
+    if (channelCount < 1 || channelCount > LVM_MAX_CHANNELS) {
         return -EINVAL;
     }
-
     return VirtualizerIsDeviceSupported(deviceType);
 }
 
@@ -3216,6 +3231,7 @@
     EffectContext * pContext = (EffectContext *) self;
     int    status = 0;
     int    processStatus = 0;
+    const int NrChannels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
 
 //ALOGV("\tEffect_process Start : Enabled = %d     Called = %d (%8d %8d %8d)",
 //pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled,
@@ -3246,7 +3262,7 @@
         (pContext->EffectType == LVM_BASS_BOOST)){
         //ALOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountBb > 0){
-            pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * 2; // STEREO
+            pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * NrChannels;
             //ALOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountBb);
         }
@@ -3266,7 +3282,7 @@
         (pContext->EffectType == LVM_EQUALIZER)){
         //ALOGV("\tEffect_process() LVM_EQUALIZER Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountEq > 0){
-            pContext->pBundledContext->SamplesToExitCountEq -= outBuffer->frameCount * 2; // STEREO
+            pContext->pBundledContext->SamplesToExitCountEq -= outBuffer->frameCount * NrChannels;
             //ALOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountEq);
         }
@@ -3280,7 +3296,8 @@
         (pContext->EffectType == LVM_VIRTUALIZER)){
         //ALOGV("\tEffect_process() LVM_VIRTUALIZER Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
-            pContext->pBundledContext->SamplesToExitCountVirt -= outBuffer->frameCount * 2;// STEREO
+            pContext->pBundledContext->SamplesToExitCountVirt -=
+                outBuffer->frameCount * NrChannels;
             //ALOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountVirt);
         }
@@ -3331,7 +3348,7 @@
         //pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
 
         if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
-            for (size_t i = 0; i < outBuffer->frameCount * FCC_2; ++i){
+            for (size_t i = 0; i < outBuffer->frameCount * NrChannels; ++i) {
 #ifdef NATIVE_FLOAT_BUFFER
                 outBuffer->f32[i] += inBuffer->f32[i];
 #else