Loading media/libeffects/lvm/tests/Android.bp +30 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,36 @@ cc_test { ], } cc_test { name: "reverb_test", host_supported: false, proprietary: true, include_dirs: [ "frameworks/av/media/libeffects/lvm/wrapper/Reverb" ], header_libs: [ "libaudioeffects", ], shared_libs: [ "libaudioutils", "liblog", "libreverbwrapper", ], srcs: [ "reverb_test.cpp", ], cflags: [ "-Wall", "-Werror", "-Wextra", ], } cc_test { name: "snr", host_supported: false, Loading media/libeffects/lvm/tests/build_and_run_all_unit_tests_reverb.sh 0 → 100755 +87 −0 Original line number Diff line number Diff line #!/bin/bash # # reverb test # 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/revTest" echo "========================================" echo "testing reverb" adb shell mkdir -p $testdir adb push $ANDROID_BUILD_TOP/cts/tests/tests/media/res/raw/sinesweepraw.raw $testdir E_VAL=1 cmds="adb push $OUT/testcases/reverb_test/arm/reverb_test $testdir" fs_arr=( 8000 16000 22050 32000 44100 48000 88200 96000 176400 192000 ) # run reverb at different configs, saving only the stereo channel # pair. error_count=0 for cmd in "${cmds[@]}" do $cmd for preset_val in {0..6} do for fs in ${fs_arr[*]} do for chMask in {1..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 --fs $fs --preset $preset_val 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 done done done done adb shell rm -r $testdir echo "$error_count errors" exit $error_count media/libeffects/lvm/tests/reverb_test.cpp 0 → 100644 +395 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 <getopt.h> #include <inttypes.h> #include <iterator> #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 <system/audio.h> #include "EffectReverb.h" // This is the only symbol that needs to be exported extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM; // Global Variables enum ReverbParams { ARG_HELP = 1, ARG_INPUT, ARG_OUTPUT, ARG_FS, ARG_CH_MASK, ARG_PRESET, ARG_AUX, ARG_MONO_MODE, ARG_FILE_CH, }; const effect_uuid_t kReverbUuids[] = { {0x172cdf00, 0xa3bc, 0x11df, 0xa72f, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-insert mode {0xf29a1400, 0xa3bb, 0x11df, 0x8ddc, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-aux mode }; // structures struct reverbConfigParams_t { int fChannels = 2; int monoMode = false; int frameLength = 256; int preset = 0; int nrChannels = 2; int sampleRate = 48000; int auxiliary = 0; audio_channel_mask_t chMask = AUDIO_CHANNEL_OUT_STEREO; }; constexpr audio_channel_mask_t kReverbConfigChMask[] = { AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2, AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK, AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND, (1 << 4) - 1, AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA, (1 << 5) - 1, AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK, AUDIO_CHANNEL_OUT_5POINT1_SIDE, (1 << 6) - 1, AUDIO_CHANNEL_OUT_6POINT1, (1 << 7) - 1, AUDIO_CHANNEL_OUT_5POINT1POINT2, AUDIO_CHANNEL_OUT_7POINT1, (1 << 8) - 1, }; constexpr int kReverbConfigChMaskCount = std::size(kReverbConfigChMask); int reverbCreateEffect(effect_handle_t *pEffectHandle, effect_config_t *pConfig, int sessionId, int ioId, int auxFlag) { if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(&kReverbUuids[auxFlag], sessionId, ioId, pEffectHandle); status != 0) { ALOGE("Reverb create returned an error = %d\n", status); return EXIT_FAILURE; } int reply = 0; uint32_t replySize = sizeof(reply); (**pEffectHandle) ->command(*pEffectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t), pConfig, &replySize, &reply); return reply; } int reverbSetConfigParam(uint32_t paramType, uint32_t paramValue, effect_handle_t effectHandle) { int reply = 0; uint32_t replySize = sizeof(reply); uint32_t paramData[2] = {paramType, paramValue}; effect_param_t *effectParam = (effect_param_t *)malloc(sizeof(*effectParam) + sizeof(paramData)); memcpy(&effectParam->data[0], ¶mData[0], sizeof(paramData)); effectParam->psize = sizeof(paramData[0]); effectParam->vsize = sizeof(paramData[1]); int status = (*effectHandle) ->command(effectHandle, EFFECT_CMD_SET_PARAM, sizeof(effect_param_t) + sizeof(paramData), effectParam, &replySize, &reply); free(effectParam); if (status != 0) { ALOGE("Reverb set config returned an error = %d\n", status); return status; } return reply; } void printUsage() { printf("\nUsage: "); printf("\n <executable> [options]\n"); printf("\nwhere options are, "); printf("\n --input <inputfile>"); printf("\n path to the input file"); printf("\n --output <outputfile>"); printf("\n path to the output file"); printf("\n --help"); printf("\n prints this usage information"); printf("\n --chMask <channel_mask>\n"); printf("\n 0 - AUDIO_CHANNEL_OUT_MONO"); printf("\n 1 - AUDIO_CHANNEL_OUT_STEREO"); printf("\n 2 - AUDIO_CHANNEL_OUT_2POINT1"); printf("\n 3 - AUDIO_CHANNEL_OUT_2POINT0POINT2"); printf("\n 4 - AUDIO_CHANNEL_OUT_QUAD"); printf("\n 5 - AUDIO_CHANNEL_OUT_QUAD_BACK"); printf("\n 6 - AUDIO_CHANNEL_OUT_QUAD_SIDE"); printf("\n 7 - AUDIO_CHANNEL_OUT_SURROUND"); printf("\n 8 - canonical channel index mask for 4 ch: (1 << 4) - 1"); printf("\n 9 - AUDIO_CHANNEL_OUT_2POINT1POINT2"); printf("\n 10 - AUDIO_CHANNEL_OUT_3POINT0POINT2"); printf("\n 11 - AUDIO_CHANNEL_OUT_PENTA"); printf("\n 12 - canonical channel index mask for 5 ch: (1 << 5) - 1"); printf("\n 13 - AUDIO_CHANNEL_OUT_3POINT1POINT2"); printf("\n 14 - AUDIO_CHANNEL_OUT_5POINT1"); printf("\n 15 - AUDIO_CHANNEL_OUT_5POINT1_BACK"); printf("\n 16 - AUDIO_CHANNEL_OUT_5POINT1_SIDE"); printf("\n 17 - canonical channel index mask for 6 ch: (1 << 6) - 1"); printf("\n 18 - AUDIO_CHANNEL_OUT_6POINT1"); printf("\n 19 - canonical channel index mask for 7 ch: (1 << 7) - 1"); printf("\n 20 - AUDIO_CHANNEL_OUT_5POINT1POINT2"); printf("\n 21 - AUDIO_CHANNEL_OUT_7POINT1"); printf("\n 22 - canonical channel index mask for 8 ch: (1 << 8) - 1"); printf("\n default 0"); printf("\n --fs <sampling_freq>"); printf("\n Sampling frequency in Hz, default 48000."); printf("\n --preset <preset_value>"); printf("\n 0 - None"); printf("\n 1 - Small Room"); printf("\n 2 - Medium Room"); printf("\n 3 - Large Room"); printf("\n 4 - Medium Hall"); printf("\n 5 - Large Hall"); printf("\n 6 - Plate"); printf("\n default 0"); printf("\n --fch <file_channels>"); printf("\n number of channels in input file (1 through 8), default 1"); printf("\n --M"); printf("\n Mono mode (force all input audio channels to be identical)"); printf("\n --aux <auxiliary_flag> "); printf("\n 0 - Insert Mode on"); printf("\n 1 - auxiliary Mode on"); printf("\n default 0"); printf("\n"); } int main(int argc, const char *argv[]) { if (argc == 1) { printUsage(); return EXIT_FAILURE; } reverbConfigParams_t revConfigParams{}; // default initialize const char *inputFile = nullptr; const char *outputFile = nullptr; const option long_opts[] = { {"help", no_argument, nullptr, ARG_HELP}, {"input", required_argument, nullptr, ARG_INPUT}, {"output", required_argument, nullptr, ARG_OUTPUT}, {"fs", required_argument, nullptr, ARG_FS}, {"chMask", required_argument, nullptr, ARG_CH_MASK}, {"preset", required_argument, nullptr, ARG_PRESET}, {"aux", required_argument, nullptr, ARG_AUX}, {"M", no_argument, &revConfigParams.monoMode, true}, {"fch", required_argument, nullptr, ARG_FILE_CH}, {nullptr, 0, nullptr, 0}, }; while (true) { const int opt = getopt_long(argc, (char *const *)argv, "i:o:", long_opts, nullptr); if (opt == -1) { break; } switch (opt) { case ARG_HELP: printUsage(); return EXIT_SUCCESS; case ARG_INPUT: { inputFile = (char *)optarg; break; } case ARG_OUTPUT: { outputFile = (char *)optarg; break; } case ARG_FS: { revConfigParams.sampleRate = atoi(optarg); break; } case ARG_CH_MASK: { int chMaskIdx = atoi(optarg); if (chMaskIdx < 0 or chMaskIdx > kReverbConfigChMaskCount) { ALOGE("Channel Mask index not in correct range\n"); printUsage(); return EXIT_FAILURE; } revConfigParams.chMask = kReverbConfigChMask[chMaskIdx]; break; } case ARG_PRESET: { revConfigParams.preset = atoi(optarg); break; } case ARG_AUX: { revConfigParams.auxiliary = atoi(optarg); break; } case ARG_MONO_MODE: { break; } case ARG_FILE_CH: { revConfigParams.fChannels = atoi(optarg); break; } default: break; } } if (inputFile == nullptr) { ALOGE("Error: missing input files\n"); printUsage(); return EXIT_FAILURE; } std::unique_ptr<FILE, decltype(&fclose)> inputFp(fopen(inputFile, "rb"), &fclose); if (inputFp == nullptr) { ALOGE("Cannot open input file %s\n", inputFile); return EXIT_FAILURE; } if (outputFile == nullptr) { ALOGE("Error: missing output files\n"); printUsage(); return EXIT_FAILURE; } std::unique_ptr<FILE, decltype(&fclose)> outputFp(fopen(outputFile, "wb"), &fclose); if (outputFp == nullptr) { ALOGE("Cannot open output file %s\n", outputFile); return EXIT_FAILURE; } int32_t sessionId = 1; int32_t ioId = 1; effect_handle_t effectHandle = nullptr; effect_config_t config; 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 (int status = reverbCreateEffect(&effectHandle, &config, sessionId, ioId, revConfigParams.auxiliary); status != 0) { ALOGE("Create effect call returned error %i", status); return EXIT_FAILURE; } int reply = 0; uint32_t replySize = sizeof(reply); (*effectHandle)->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply); if (reply != 0) { ALOGE("Command enable call returned error %d\n", reply); return EXIT_FAILURE; } if (int status = reverbSetConfigParam(REVERB_PARAM_PRESET, (uint32_t)revConfigParams.preset, effectHandle); status != 0) { ALOGE("Invalid reverb preset. Error %d\n", status); return EXIT_FAILURE; } revConfigParams.nrChannels = audio_channel_count_from_out_mask(revConfigParams.chMask); const int channelCount = revConfigParams.nrChannels; const int frameLength = revConfigParams.frameLength; #ifdef BYPASS_EXEC const int frameSize = (int)channelCount * sizeof(float); #endif const int ioChannelCount = revConfigParams.fChannels; const int ioFrameSize = ioChannelCount * sizeof(short); 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, inputFp.get()) == (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); // Mono mode will replicate the first channel to all other channels. // This ensures all audio channels are identical. This is useful for testing // Bass Boost, which extracts a mono signal for processing. if (revConfigParams.monoMode && channelCount > 1) { for (int i = 0; i < frameLength; ++i) { auto *fp = &floatIn[i * channelCount]; std::fill(fp + 1, fp + channelCount, *fp); // replicate ch 0 } } audio_buffer_t inputBuffer, outputBuffer; inputBuffer.frameCount = outputBuffer.frameCount = frameLength; inputBuffer.f32 = floatIn.data(); outputBuffer.f32 = floatOut.data(); #ifndef BYPASS_EXEC if (int status = (*effectHandle)->process(effectHandle, &inputBuffer, &outputBuffer); status != 0) { ALOGE("\nError: Process returned with error %d\n", status); return EXIT_FAILURE; } #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, outputFp.get()); frameCounter += frameLength; } if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) { ALOGE("Audio Preprocessing release returned an error = %d\n", status); return EXIT_FAILURE; } printf("frameCounter: [%d]\n", frameCounter); return EXIT_SUCCESS; } Loading
media/libeffects/lvm/tests/Android.bp +30 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,36 @@ cc_test { ], } cc_test { name: "reverb_test", host_supported: false, proprietary: true, include_dirs: [ "frameworks/av/media/libeffects/lvm/wrapper/Reverb" ], header_libs: [ "libaudioeffects", ], shared_libs: [ "libaudioutils", "liblog", "libreverbwrapper", ], srcs: [ "reverb_test.cpp", ], cflags: [ "-Wall", "-Werror", "-Wextra", ], } cc_test { name: "snr", host_supported: false, Loading
media/libeffects/lvm/tests/build_and_run_all_unit_tests_reverb.sh 0 → 100755 +87 −0 Original line number Diff line number Diff line #!/bin/bash # # reverb test # 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/revTest" echo "========================================" echo "testing reverb" adb shell mkdir -p $testdir adb push $ANDROID_BUILD_TOP/cts/tests/tests/media/res/raw/sinesweepraw.raw $testdir E_VAL=1 cmds="adb push $OUT/testcases/reverb_test/arm/reverb_test $testdir" fs_arr=( 8000 16000 22050 32000 44100 48000 88200 96000 176400 192000 ) # run reverb at different configs, saving only the stereo channel # pair. error_count=0 for cmd in "${cmds[@]}" do $cmd for preset_val in {0..6} do for fs in ${fs_arr[*]} do for chMask in {1..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 --fs $fs --preset $preset_val 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 done done done done adb shell rm -r $testdir echo "$error_count errors" exit $error_count
media/libeffects/lvm/tests/reverb_test.cpp 0 → 100644 +395 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 <getopt.h> #include <inttypes.h> #include <iterator> #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 <system/audio.h> #include "EffectReverb.h" // This is the only symbol that needs to be exported extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM; // Global Variables enum ReverbParams { ARG_HELP = 1, ARG_INPUT, ARG_OUTPUT, ARG_FS, ARG_CH_MASK, ARG_PRESET, ARG_AUX, ARG_MONO_MODE, ARG_FILE_CH, }; const effect_uuid_t kReverbUuids[] = { {0x172cdf00, 0xa3bc, 0x11df, 0xa72f, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-insert mode {0xf29a1400, 0xa3bb, 0x11df, 0x8ddc, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // preset-aux mode }; // structures struct reverbConfigParams_t { int fChannels = 2; int monoMode = false; int frameLength = 256; int preset = 0; int nrChannels = 2; int sampleRate = 48000; int auxiliary = 0; audio_channel_mask_t chMask = AUDIO_CHANNEL_OUT_STEREO; }; constexpr audio_channel_mask_t kReverbConfigChMask[] = { AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2, AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK, AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND, (1 << 4) - 1, AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA, (1 << 5) - 1, AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK, AUDIO_CHANNEL_OUT_5POINT1_SIDE, (1 << 6) - 1, AUDIO_CHANNEL_OUT_6POINT1, (1 << 7) - 1, AUDIO_CHANNEL_OUT_5POINT1POINT2, AUDIO_CHANNEL_OUT_7POINT1, (1 << 8) - 1, }; constexpr int kReverbConfigChMaskCount = std::size(kReverbConfigChMask); int reverbCreateEffect(effect_handle_t *pEffectHandle, effect_config_t *pConfig, int sessionId, int ioId, int auxFlag) { if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(&kReverbUuids[auxFlag], sessionId, ioId, pEffectHandle); status != 0) { ALOGE("Reverb create returned an error = %d\n", status); return EXIT_FAILURE; } int reply = 0; uint32_t replySize = sizeof(reply); (**pEffectHandle) ->command(*pEffectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t), pConfig, &replySize, &reply); return reply; } int reverbSetConfigParam(uint32_t paramType, uint32_t paramValue, effect_handle_t effectHandle) { int reply = 0; uint32_t replySize = sizeof(reply); uint32_t paramData[2] = {paramType, paramValue}; effect_param_t *effectParam = (effect_param_t *)malloc(sizeof(*effectParam) + sizeof(paramData)); memcpy(&effectParam->data[0], ¶mData[0], sizeof(paramData)); effectParam->psize = sizeof(paramData[0]); effectParam->vsize = sizeof(paramData[1]); int status = (*effectHandle) ->command(effectHandle, EFFECT_CMD_SET_PARAM, sizeof(effect_param_t) + sizeof(paramData), effectParam, &replySize, &reply); free(effectParam); if (status != 0) { ALOGE("Reverb set config returned an error = %d\n", status); return status; } return reply; } void printUsage() { printf("\nUsage: "); printf("\n <executable> [options]\n"); printf("\nwhere options are, "); printf("\n --input <inputfile>"); printf("\n path to the input file"); printf("\n --output <outputfile>"); printf("\n path to the output file"); printf("\n --help"); printf("\n prints this usage information"); printf("\n --chMask <channel_mask>\n"); printf("\n 0 - AUDIO_CHANNEL_OUT_MONO"); printf("\n 1 - AUDIO_CHANNEL_OUT_STEREO"); printf("\n 2 - AUDIO_CHANNEL_OUT_2POINT1"); printf("\n 3 - AUDIO_CHANNEL_OUT_2POINT0POINT2"); printf("\n 4 - AUDIO_CHANNEL_OUT_QUAD"); printf("\n 5 - AUDIO_CHANNEL_OUT_QUAD_BACK"); printf("\n 6 - AUDIO_CHANNEL_OUT_QUAD_SIDE"); printf("\n 7 - AUDIO_CHANNEL_OUT_SURROUND"); printf("\n 8 - canonical channel index mask for 4 ch: (1 << 4) - 1"); printf("\n 9 - AUDIO_CHANNEL_OUT_2POINT1POINT2"); printf("\n 10 - AUDIO_CHANNEL_OUT_3POINT0POINT2"); printf("\n 11 - AUDIO_CHANNEL_OUT_PENTA"); printf("\n 12 - canonical channel index mask for 5 ch: (1 << 5) - 1"); printf("\n 13 - AUDIO_CHANNEL_OUT_3POINT1POINT2"); printf("\n 14 - AUDIO_CHANNEL_OUT_5POINT1"); printf("\n 15 - AUDIO_CHANNEL_OUT_5POINT1_BACK"); printf("\n 16 - AUDIO_CHANNEL_OUT_5POINT1_SIDE"); printf("\n 17 - canonical channel index mask for 6 ch: (1 << 6) - 1"); printf("\n 18 - AUDIO_CHANNEL_OUT_6POINT1"); printf("\n 19 - canonical channel index mask for 7 ch: (1 << 7) - 1"); printf("\n 20 - AUDIO_CHANNEL_OUT_5POINT1POINT2"); printf("\n 21 - AUDIO_CHANNEL_OUT_7POINT1"); printf("\n 22 - canonical channel index mask for 8 ch: (1 << 8) - 1"); printf("\n default 0"); printf("\n --fs <sampling_freq>"); printf("\n Sampling frequency in Hz, default 48000."); printf("\n --preset <preset_value>"); printf("\n 0 - None"); printf("\n 1 - Small Room"); printf("\n 2 - Medium Room"); printf("\n 3 - Large Room"); printf("\n 4 - Medium Hall"); printf("\n 5 - Large Hall"); printf("\n 6 - Plate"); printf("\n default 0"); printf("\n --fch <file_channels>"); printf("\n number of channels in input file (1 through 8), default 1"); printf("\n --M"); printf("\n Mono mode (force all input audio channels to be identical)"); printf("\n --aux <auxiliary_flag> "); printf("\n 0 - Insert Mode on"); printf("\n 1 - auxiliary Mode on"); printf("\n default 0"); printf("\n"); } int main(int argc, const char *argv[]) { if (argc == 1) { printUsage(); return EXIT_FAILURE; } reverbConfigParams_t revConfigParams{}; // default initialize const char *inputFile = nullptr; const char *outputFile = nullptr; const option long_opts[] = { {"help", no_argument, nullptr, ARG_HELP}, {"input", required_argument, nullptr, ARG_INPUT}, {"output", required_argument, nullptr, ARG_OUTPUT}, {"fs", required_argument, nullptr, ARG_FS}, {"chMask", required_argument, nullptr, ARG_CH_MASK}, {"preset", required_argument, nullptr, ARG_PRESET}, {"aux", required_argument, nullptr, ARG_AUX}, {"M", no_argument, &revConfigParams.monoMode, true}, {"fch", required_argument, nullptr, ARG_FILE_CH}, {nullptr, 0, nullptr, 0}, }; while (true) { const int opt = getopt_long(argc, (char *const *)argv, "i:o:", long_opts, nullptr); if (opt == -1) { break; } switch (opt) { case ARG_HELP: printUsage(); return EXIT_SUCCESS; case ARG_INPUT: { inputFile = (char *)optarg; break; } case ARG_OUTPUT: { outputFile = (char *)optarg; break; } case ARG_FS: { revConfigParams.sampleRate = atoi(optarg); break; } case ARG_CH_MASK: { int chMaskIdx = atoi(optarg); if (chMaskIdx < 0 or chMaskIdx > kReverbConfigChMaskCount) { ALOGE("Channel Mask index not in correct range\n"); printUsage(); return EXIT_FAILURE; } revConfigParams.chMask = kReverbConfigChMask[chMaskIdx]; break; } case ARG_PRESET: { revConfigParams.preset = atoi(optarg); break; } case ARG_AUX: { revConfigParams.auxiliary = atoi(optarg); break; } case ARG_MONO_MODE: { break; } case ARG_FILE_CH: { revConfigParams.fChannels = atoi(optarg); break; } default: break; } } if (inputFile == nullptr) { ALOGE("Error: missing input files\n"); printUsage(); return EXIT_FAILURE; } std::unique_ptr<FILE, decltype(&fclose)> inputFp(fopen(inputFile, "rb"), &fclose); if (inputFp == nullptr) { ALOGE("Cannot open input file %s\n", inputFile); return EXIT_FAILURE; } if (outputFile == nullptr) { ALOGE("Error: missing output files\n"); printUsage(); return EXIT_FAILURE; } std::unique_ptr<FILE, decltype(&fclose)> outputFp(fopen(outputFile, "wb"), &fclose); if (outputFp == nullptr) { ALOGE("Cannot open output file %s\n", outputFile); return EXIT_FAILURE; } int32_t sessionId = 1; int32_t ioId = 1; effect_handle_t effectHandle = nullptr; effect_config_t config; 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 (int status = reverbCreateEffect(&effectHandle, &config, sessionId, ioId, revConfigParams.auxiliary); status != 0) { ALOGE("Create effect call returned error %i", status); return EXIT_FAILURE; } int reply = 0; uint32_t replySize = sizeof(reply); (*effectHandle)->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply); if (reply != 0) { ALOGE("Command enable call returned error %d\n", reply); return EXIT_FAILURE; } if (int status = reverbSetConfigParam(REVERB_PARAM_PRESET, (uint32_t)revConfigParams.preset, effectHandle); status != 0) { ALOGE("Invalid reverb preset. Error %d\n", status); return EXIT_FAILURE; } revConfigParams.nrChannels = audio_channel_count_from_out_mask(revConfigParams.chMask); const int channelCount = revConfigParams.nrChannels; const int frameLength = revConfigParams.frameLength; #ifdef BYPASS_EXEC const int frameSize = (int)channelCount * sizeof(float); #endif const int ioChannelCount = revConfigParams.fChannels; const int ioFrameSize = ioChannelCount * sizeof(short); 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, inputFp.get()) == (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); // Mono mode will replicate the first channel to all other channels. // This ensures all audio channels are identical. This is useful for testing // Bass Boost, which extracts a mono signal for processing. if (revConfigParams.monoMode && channelCount > 1) { for (int i = 0; i < frameLength; ++i) { auto *fp = &floatIn[i * channelCount]; std::fill(fp + 1, fp + channelCount, *fp); // replicate ch 0 } } audio_buffer_t inputBuffer, outputBuffer; inputBuffer.frameCount = outputBuffer.frameCount = frameLength; inputBuffer.f32 = floatIn.data(); outputBuffer.f32 = floatOut.data(); #ifndef BYPASS_EXEC if (int status = (*effectHandle)->process(effectHandle, &inputBuffer, &outputBuffer); status != 0) { ALOGE("\nError: Process returned with error %d\n", status); return EXIT_FAILURE; } #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, outputFp.get()); frameCounter += frameLength; } if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) { ALOGE("Audio Preprocessing release returned an error = %d\n", status); return EXIT_FAILURE; } printf("frameCounter: [%d]\n", frameCounter); return EXIT_SUCCESS; }