libeffects: Add multichannel support to Reverb
Test: SoloTester and Clarity app
Test: Standalone application test
Bug: 129491957
Change-Id: Ifac02eb2a7ac3eba5fae9318c3ae1e1c7df4f681
diff --git a/media/libeffects/lvm/tests/build_and_run_all_unit_tests_reverb.sh b/media/libeffects/lvm/tests/build_and_run_all_unit_tests_reverb.sh
index 5a972db..0c3b0b5 100755
--- a/media/libeffects/lvm/tests/build_and_run_all_unit_tests_reverb.sh
+++ b/media/libeffects/lvm/tests/build_and_run_all_unit_tests_reverb.sh
@@ -41,47 +41,65 @@
192000
)
+flags_arr=(
+ "--M --fch 1"
+ "--fch 2"
+)
+
# run reverb at different configs, saving only the stereo channel
# pair.
error_count=0
+testcase_count=0
for cmd in "${cmds[@]}"
do
$cmd
- for preset_val in {0..6}
+ for flags in "${flags_arr[@]}"
do
- for fs in ${fs_arr[*]}
+ for preset_val in {0..6}
do
- for chMask in {1..22}
+ for fs in ${fs_arr[*]}
do
- adb shell LD_LIBRARY_PATH=/system/vendor/lib/soundfx $testdir/reverb_test \
- --input $testdir/sinesweepraw.raw \
- --output $testdir/sinesweep_$((chMask))_$((fs)).raw \
- --chMask $chMask --fs $fs --preset $preset_val
+ for chMask in {0..22}
+ do
+ adb shell LD_LIBRARY_PATH=/system/vendor/lib/soundfx $testdir/reverb_test \
+ --input $testdir/sinesweepraw.raw \
+ --output $testdir/sinesweep_$((chMask))_$((fs)).raw \
+ --chMask $chMask $flags --fs $fs --preset $preset_val
- shell_ret=$?
- if [ $shell_ret -ne 0 ]; then
- echo "error: $shell_ret"
- ((++error_count))
- fi
+ shell_ret=$?
+ if [ $shell_ret -ne 0 ]; then
+ echo "error: $shell_ret"
+ ((++error_count))
+ fi
- # two channel files should be identical to higher channel
- # computation (first 2 channels).
- if [[ "$chMask" -gt 1 ]]
- then
- adb shell cmp $testdir/sinesweep_1_$((fs)).raw \
- $testdir/sinesweep_$((chMask))_$((fs)).raw
- fi
- # cmp returns EXIT_FAILURE on mismatch.
- shell_ret=$?
- if [ $shell_ret -ne 0 ]; then
- echo "error: $shell_ret"
- ((++error_count))
- fi
+ if [[ "$chMask" -gt 0 ]] && [[ $flags != *"--fch 2"* ]]
+ then
+ # single channel files should be identical to higher channel
+ # computation (first channel).
+ adb shell cmp $testdir/sinesweep_0_$((fs)).raw \
+ $testdir/sinesweep_$((chMask))_$((fs)).raw
+ elif [[ "$chMask" -gt 1 ]]
+ then
+ # two channel files should be identical to higher channel
+ # computation (first 2 channels).
+ adb shell cmp $testdir/sinesweep_1_$((fs)).raw \
+ $testdir/sinesweep_$((chMask))_$((fs)).raw
+ fi
+
+ # cmp returns EXIT_FAILURE on mismatch.
+ shell_ret=$?
+ if [ $shell_ret -ne 0 ]; then
+ echo "error: $shell_ret"
+ ((++error_count))
+ fi
+ ((++testcase_count))
+ done
done
done
done
done
adb shell rm -r $testdir
+echo "$testcase_count tests performed"
echo "$error_count errors"
exit $error_count
diff --git a/media/libeffects/lvm/tests/reverb_test.cpp b/media/libeffects/lvm/tests/reverb_test.cpp
index a9cf348..f403229 100644
--- a/media/libeffects/lvm/tests/reverb_test.cpp
+++ b/media/libeffects/lvm/tests/reverb_test.cpp
@@ -297,6 +297,9 @@
config.inputCfg.samplingRate = config.outputCfg.samplingRate = revConfigParams.sampleRate;
config.inputCfg.channels = config.outputCfg.channels = revConfigParams.chMask;
config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+ if (AUDIO_CHANNEL_OUT_MONO == revConfigParams.chMask) {
+ config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+ }
if (int status =
reverbCreateEffect(&effectHandle, &config, sessionId, ioId, revConfigParams.auxiliary);
status != 0) {
@@ -332,15 +335,15 @@
* 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
+ * 2 channels. The outChannelCount takes care of allocation of sufficient
* memory for the output buffer.
*/
- const int memAllocChCount = (channelCount == 1 ? 2 : channelCount);
+ const int outChannelCount = (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);
+ std::vector<float> floatOut(frameLength * outChannelCount);
int frameCounter = 0;
@@ -374,11 +377,11 @@
#else
memcpy(floatOut.data(), floatIn.data(), frameLength * frameSize);
#endif
- memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * channelCount);
+ memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * outChannelCount);
- if (ioChannelCount != channelCount) {
- adjust_channels(out.data(), channelCount, out.data(), ioChannelCount, sizeof(short),
- frameLength * channelCount * sizeof(short));
+ if (ioChannelCount != outChannelCount) {
+ adjust_channels(out.data(), outChannelCount, out.data(), ioChannelCount, sizeof(short),
+ frameLength * outChannelCount * sizeof(short));
}
(void)fwrite(out.data(), ioFrameSize, frameLength, outputFp.get());
frameCounter += frameLength;
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index afc4220..021020c 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -53,6 +53,7 @@
cppflags: [
"-fvisibility=hidden",
+ "-DSUPPORT_MC",
"-Wall",
"-Werror",
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 39f5bb6..b95494d 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -259,6 +259,9 @@
int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
+#ifdef SUPPORT_MC
+ channels = (pContext->auxiliary == true)? channels : FCC_2;
+#endif
// Allocate memory for reverb process (*2 is for STEREO)
pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(process_buffer_t) * channels;
pContext->bufferSizeOut = LVREV_MAX_FRAME_SIZE * sizeof(process_buffer_t) * FCC_2;
@@ -343,11 +346,18 @@
int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; /* Function call status */
- // Check that the input is either mono or stereo
+ // Reverb only effects the stereo channels in multichannel source.
+#ifdef SUPPORT_MC
+ if (channels < 1 || channels > LVM_MAX_CHANNELS) {
+ ALOGE("\tLVREV_ERROR : process invalid PCM channels %d", channels);
+ return -EINVAL;
+ }
+#else
if (!(channels == 1 || channels == FCC_2) ) {
ALOGE("\tLVREV_ERROR : process invalid PCM format");
return -EINVAL;
}
+#endif
size_t inSize = frameCount * sizeof(process_buffer_t) * channels;
size_t outSize = frameCount * sizeof(process_buffer_t) * FCC_2;
@@ -380,12 +390,28 @@
static_assert(std::is_same<decltype(*pIn), decltype(*pContext->InFrames)>::value,
"pIn and InFrames must be same type");
memcpy(pContext->InFrames, pIn, frameCount * channels * sizeof(*pIn));
+ } else {
+ // mono input is duplicated
+#ifdef SUPPORT_MC
+ if (channels >= FCC_2) {
+ for (int i = 0; i < frameCount; i++) {
+ pContext->InFrames[FCC_2 * i] =
+ (process_buffer_t)pIn[channels * i] * REVERB_SEND_LEVEL;
+ pContext->InFrames[FCC_2 * i + 1] =
+ (process_buffer_t)pIn[channels * i + 1] * REVERB_SEND_LEVEL;
+ }
} else {
- // insert reverb input is always stereo
+ for (int i = 0; i < frameCount; i++) {
+ pContext->InFrames[FCC_2 * i] = pContext->InFrames[FCC_2 * i + 1] =
+ (process_buffer_t)pIn[i] * REVERB_SEND_LEVEL;
+ }
+ }
+#else
for (int i = 0; i < frameCount; i++) {
pContext->InFrames[2 * i] = (process_buffer_t)pIn[2 * i] * REVERB_SEND_LEVEL;
pContext->InFrames[2 * i + 1] = (process_buffer_t)pIn[2 * i + 1] * REVERB_SEND_LEVEL;
}
+#endif
}
if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
@@ -412,10 +438,26 @@
if (pContext->auxiliary) {
// nothing to do here
} else {
+#ifdef SUPPORT_MC
+ if (channels >= FCC_2) {
+ for (int i = 0; i < frameCount; i++) {
+ // Mix with dry input
+ pContext->OutFrames[FCC_2 * i] += pIn[channels * i];
+ pContext->OutFrames[FCC_2 * i + 1] += pIn[channels * i + 1];
+ }
+ } else {
+ for (int i = 0; i < frameCount; i++) {
+ // Mix with dry input
+ pContext->OutFrames[FCC_2 * i] += pIn[i];
+ pContext->OutFrames[FCC_2 * i + 1] += pIn[i];
+ }
+ }
+#else
for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
// Mix with dry input
pContext->OutFrames[i] += pIn[i];
}
+#endif
// apply volume with ramp if needed
if ((pContext->leftVolume != pContext->prevLeftVolume ||
pContext->rightVolume != pContext->prevRightVolume) &&
@@ -450,6 +492,35 @@
}
}
+#ifdef SUPPORT_MC
+ if (channels > 2) {
+ //Accumulate if required
+ if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (int i = 0; i < frameCount; i++) {
+ pOut[channels * i] += pContext->OutFrames[FCC_2 * i];
+ pOut[channels * i + 1] += pContext->OutFrames[FCC_2 * i + 1];
+ }
+ } else {
+ for (int i = 0; i < frameCount; i++) {
+ pOut[channels * i] = pContext->OutFrames[FCC_2 * i];
+ pOut[channels * i + 1] = pContext->OutFrames[FCC_2 * i + 1];
+ }
+ }
+ for (int i = 0; i < frameCount; i++) {
+ for (int j = FCC_2; j < channels; j++) {
+ pOut[channels * i + j] = pIn[channels * i + j];
+ }
+ }
+ } else {
+ if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (int i = 0; i < frameCount * FCC_2; i++) {
+ pOut[i] += pContext->OutFrames[i];
+ }
+ } else {
+ memcpy(pOut, pContext->OutFrames, frameCount * sizeof(*pOut) * FCC_2);
+ }
+ }
+#else
// Accumulate if required
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
@@ -462,6 +533,7 @@
memcpy(pOut, pContext->OutFrames, frameCount * sizeof(*pOut) * FCC_2);
}
+#endif
return 0;
} /* end process */
@@ -525,9 +597,18 @@
CHECK_ARG(pConfig->inputCfg.samplingRate == pConfig->outputCfg.samplingRate);
CHECK_ARG(pConfig->inputCfg.format == pConfig->outputCfg.format);
+#ifdef SUPPORT_MC
+ int inputChannels = audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
+ CHECK_ARG((pContext->auxiliary && pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) ||
+ ((!pContext->auxiliary) &&
+ (inputChannels <= LVM_MAX_CHANNELS)));
+ int outputChannels = audio_channel_count_from_out_mask(pConfig->outputCfg.channels);
+ CHECK_ARG(outputChannels >= FCC_2 && outputChannels <= LVM_MAX_CHANNELS);
+#else
CHECK_ARG((pContext->auxiliary && pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) ||
((!pContext->auxiliary) && pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO));
CHECK_ARG(pConfig->outputCfg.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);
@@ -749,6 +830,11 @@
params.SourceFormat = LVM_STEREO;
}
+#ifdef SUPPORT_MC
+ if ((pContext->auxiliary == false) && (params.SourceFormat == LVM_MONO)) {
+ params.SourceFormat = LVM_STEREO;
+ }
+#endif
/* Reverb parameters */
params.Level = 0;
params.LPF = 23999;