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/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;
+}