DynamicsProcessing: Add test for threshold and ratio parameters of MBCBandConfig
This test compresses only one band at a time and validates that the
output magnitude of the compressed band is less than that of the other
band.
Bug: 305866207
Test: atest VtsHalDynamicsProcessingTargetTest
Change-Id: Iaeeb3968c47e2478fd5e528ae36d84c4dcc625a2
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
index 09b6621..1e6f186 100644
--- a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -506,6 +506,27 @@
limiterConfigList.push_back(cfg);
}
+DynamicsProcessing::MbcBandConfig createMbcBandConfig(int channel, int band, float cutoffFreqHz,
+ float attackTimeMs, float releaseTimeMs,
+ float ratio, float thresholdDb,
+ float kneeWidthDb, float noiseGate,
+ float expanderRatio, float preGainDb,
+ float postGainDb) {
+ return DynamicsProcessing::MbcBandConfig{.channel = channel,
+ .band = band,
+ .enable = true,
+ .cutoffFrequencyHz = cutoffFreqHz,
+ .attackTimeMs = attackTimeMs,
+ .releaseTimeMs = releaseTimeMs,
+ .ratio = ratio,
+ .thresholdDb = thresholdDb,
+ .kneeWidthDb = kneeWidthDb,
+ .noiseGateThresholdDb = noiseGate,
+ .expanderRatio = expanderRatio,
+ .preGainDb = preGainDb,
+ .postGainDb = postGainDb};
+}
+
/**
* Test DynamicsProcessing Engine Configuration
*/
@@ -818,7 +839,7 @@
fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
kDefaultReleaseTime, kDefaultRatio, threshold, kDefaultPostGain);
}
- EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
+ ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
if (!isAllParamsValid()) {
continue;
}
@@ -827,7 +848,7 @@
EXPECT_NEAR(mInputDb, outputDb, kToleranceDb);
} else {
float calculatedThreshold = 0;
- EXPECT_NO_FATAL_FAILURE(computeThreshold(kDefaultRatio, outputDb, calculatedThreshold));
+ ASSERT_NO_FATAL_FAILURE(computeThreshold(kDefaultRatio, outputDb, calculatedThreshold));
ASSERT_GT(calculatedThreshold, previousThreshold);
previousThreshold = calculatedThreshold;
}
@@ -844,7 +865,7 @@
fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
kDefaultReleaseTime, ratio, kDefaultThreshold, kDefaultPostGain);
}
- EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
+ ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
if (!isAllParamsValid()) {
continue;
}
@@ -854,7 +875,7 @@
EXPECT_NEAR(mInputDb, outputDb, kToleranceDb);
} else {
float calculatedRatio = 0;
- EXPECT_NO_FATAL_FAILURE(computeRatio(kDefaultThreshold, outputDb, calculatedRatio));
+ ASSERT_NO_FATAL_FAILURE(computeRatio(kDefaultThreshold, outputDb, calculatedRatio));
ASSERT_GT(calculatedRatio, previousRatio);
previousRatio = calculatedRatio;
}
@@ -870,7 +891,7 @@
fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
kDefaultReleaseTime, kDefaultRatio, -1, postGainDb);
}
- EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
+ ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
if (!isAllParamsValid()) {
continue;
}
@@ -891,7 +912,7 @@
5 /*attack time*/, 5 /*release time*/, 10 /*ratio*/,
-10 /*threshold*/, 5 /*postgain*/);
}
- EXPECT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
+ ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
if (!isAllParamsValid()) {
continue;
}
@@ -1150,25 +1171,21 @@
void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
const TestParamsMbcBandConfig& params) {
- const std::vector<std::pair<int, float>> cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
- const std::array<float, MBC_ADD_MAX_NUM> additional = std::get<MBC_BAND_ADDITIONAL>(params);
- int bandCount = cutOffFreqs.size();
- cfgs.resize(bandCount);
- for (int i = 0; i < bandCount; i++) {
- cfgs[i] = DynamicsProcessing::MbcBandConfig{
- .channel = std::get<MBC_BAND_CHANNEL>(params),
- .band = cutOffFreqs[i].first,
- .enable = true /*Mbc Band Enable*/,
- .cutoffFrequencyHz = cutOffFreqs[i].second,
- .attackTimeMs = additional[MBC_ADD_ATTACK_TIME],
- .releaseTimeMs = additional[MBC_ADD_RELEASE_TIME],
- .ratio = additional[MBC_ADD_RATIO],
- .thresholdDb = additional[MBC_ADD_THRESHOLD],
- .kneeWidthDb = additional[MBC_ADD_KNEE_WIDTH],
- .noiseGateThresholdDb = additional[MBC_ADD_NOISE_GATE_THRESHOLD],
- .expanderRatio = additional[MBC_ADD_EXPENDER_RATIO],
- .preGainDb = additional[MBC_ADD_PRE_GAIN],
- .postGainDb = additional[MBC_ADD_POST_GAIN]};
+ const auto& cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
+ const auto& additional = std::get<MBC_BAND_ADDITIONAL>(params);
+
+ cfgs.resize(cutOffFreqs.size());
+
+ for (size_t i = 0; i < cutOffFreqs.size(); ++i) {
+ cfgs[i] = createMbcBandConfig(std::get<MBC_BAND_CHANNEL>(params),
+ cutOffFreqs[i].first, // band channel
+ cutOffFreqs[i].second, // band cutoff frequency
+ additional[MBC_ADD_ATTACK_TIME],
+ additional[MBC_ADD_RELEASE_TIME], additional[MBC_ADD_RATIO],
+ additional[MBC_ADD_THRESHOLD], additional[MBC_ADD_KNEE_WIDTH],
+ additional[MBC_ADD_NOISE_GATE_THRESHOLD],
+ additional[MBC_ADD_EXPENDER_RATIO],
+ additional[MBC_ADD_PRE_GAIN], additional[MBC_ADD_POST_GAIN]);
}
}
@@ -1222,6 +1239,160 @@
});
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestMbcBandConfig);
+class DynamicsProcessingMbcBandConfigDataTest
+ : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingMbcBandConfigDataTest()
+ : DynamicsProcessingTestHelper(GetParam(), AudioChannelLayout::LAYOUT_MONO) {
+ mInput.resize(kFrameCount * mChannelCount);
+ mBinOffsets.resize(mTestFrequencies.size());
+ }
+
+ void SetUp() override {
+ SetUpDynamicsProcessingEffect();
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ ASSERT_NO_FATAL_FAILURE(generateSineWave(mTestFrequencies, mInput, 1.0, kSamplingFrequency,
+ mChannelLayout));
+ }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ void setMbcParamsAndProcess(std::vector<float>& output) {
+ for (int i = 0; i < mChannelCount; i++) {
+ mChannelConfig.push_back(DynamicsProcessing::ChannelConfig(i, true));
+ }
+ mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
+ addEngineConfig(mEngineConfigPreset);
+ addMbcChannelConfig(mChannelConfig);
+ addMbcBandConfigs(mCfgs);
+
+ if (isAllParamsValid()) {
+ ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
+ ASSERT_NO_FATAL_FAILURE(
+ processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
+ }
+ }
+
+ void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs, int channelIndex,
+ float threshold, float ratio, float noiseGate, float expanderRatio,
+ int bandIndex, int cutoffFreqHz) {
+ cfgs.push_back(createMbcBandConfig(
+ channelIndex, bandIndex, static_cast<float>(cutoffFreqHz), kDefaultAttackTime,
+ kDefaultReleaseTime, ratio, threshold, kDefaultKneeWidth, noiseGate, expanderRatio,
+ kDefaultPreGainDb, kDefaultPostGainDb));
+ }
+
+ void getMagnitudeValue(const std::vector<float>& output, std::vector<float>& bufferMag) {
+ std::vector<float> subOutput(output.begin() + kStartIndex, output.end());
+ EXPECT_NO_FATAL_FAILURE(
+ calculateMagnitudeMono(bufferMag, subOutput, mBinOffsets, kNPointFFT));
+ }
+
+ void validateOutput(const std::vector<float>& output, float threshold, float ratio,
+ size_t bandIndex) {
+ float inputDb = calculateDb(mInput);
+ std::vector<float> outputMag(mBinOffsets.size());
+ EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(output, outputMag));
+ if (threshold >= inputDb || ratio == 1) {
+ std::vector<float> inputMag(mBinOffsets.size());
+ EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(mInput, inputMag));
+ for (size_t i = 0; i < inputMag.size(); i++) {
+ EXPECT_NEAR(calculateDb({inputMag[i] / mNormalizingFactor}),
+ calculateDb({outputMag[i] / mNormalizingFactor}), kToleranceDb);
+ }
+ } else {
+ // Current band's magnitude is less than the other band's magnitude
+ EXPECT_LT(outputMag[bandIndex], outputMag[bandIndex ^ 1]);
+ }
+ }
+
+ void analyseMultiBandOutput(float threshold, float ratio) {
+ std::vector<float> output(mInput.size());
+ roundToFreqCenteredToFftBin(mTestFrequencies, mBinOffsets, kBinWidth);
+ std::vector<int> cutoffFreqHz = {200 /*0th band cutoff*/, 2000 /*1st band cutoff*/};
+ // Set MBC values for two bands
+ for (size_t i = 0; i < cutoffFreqHz.size(); i++) {
+ for (int channelIndex = 0; channelIndex < mChannelCount; channelIndex++) {
+ fillMbcBandConfig(mCfgs, channelIndex, threshold, ratio, kDefaultNoiseGateDb,
+ kDefaultExpanderRatio, i, cutoffFreqHz[i]);
+ fillMbcBandConfig(mCfgs, channelIndex, kDefaultThresholdDb, kDefaultRatio,
+ kDefaultNoiseGateDb, kDefaultExpanderRatio, i ^ 1,
+ cutoffFreqHz[i ^ 1]);
+ }
+ ASSERT_NO_FATAL_FAILURE(setMbcParamsAndProcess(output));
+
+ if (isAllParamsValid()) {
+ ASSERT_NO_FATAL_FAILURE(validateOutput(output, threshold, ratio, i));
+ }
+ cleanUpMbcConfig();
+ }
+ }
+
+ void cleanUpMbcConfig() {
+ CleanUp();
+ mCfgs.clear();
+ mChannelConfig.clear();
+ }
+
+ static constexpr int kNPointFFT = 1024;
+ static constexpr float kToleranceDb = 0.5;
+ static constexpr float kDefaultPostGainDb = 0;
+ static constexpr float kDefaultPreGainDb = 0;
+ static constexpr float kDefaultAttackTime = 0;
+ static constexpr float kDefaultReleaseTime = 0;
+ static constexpr float kDefaultKneeWidth = 0;
+ static constexpr float kDefaultThresholdDb = 0;
+ static constexpr float kDefaultNoiseGateDb = -10;
+ static constexpr float kDefaultExpanderRatio = 1;
+ static constexpr float kDefaultRatio = 1;
+ static constexpr float kBinWidth = (float)kSamplingFrequency / kNPointFFT;
+ std::vector<int> mTestFrequencies = {100, 1000};
+ // Calculating normalizing factor by dividing the number of FFT points by half and the number of
+ // test frequencies. The normalization accounts for the FFT splitting the signal into positive
+ // and negative frequencies. Additionally, during multi-tone input generation, sample values are
+ // normalized to the range [-1, 1] by dividing them by the number of test frequencies.
+ float mNormalizingFactor = (kNPointFFT / (2 * mTestFrequencies.size()));
+ std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
+ std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+ std::vector<int> mBinOffsets;
+ std::vector<float> mInput;
+};
+
+TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingThreshold) {
+ float ratio = 20;
+ std::vector<float> thresholdValues = {-200, -100, 0, 100, 200};
+
+ for (float threshold : thresholdValues) {
+ cleanUpMbcConfig();
+ ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(threshold, ratio));
+ }
+}
+
+TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingRatio) {
+ float threshold = -20;
+ std::vector<float> ratioValues = {1, 10, 20, 30, 40, 50};
+
+ for (float ratio : ratioValues) {
+ cleanUpMbcConfig();
+ ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(threshold, ratio));
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingMbcBandConfigDataTest,
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
+ [](const auto& info) {
+ auto descriptor = info.param;
+ std::string name = getPrefix(descriptor.second);
+ std::replace_if(
+ name.begin(), name.end(),
+ [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingMbcBandConfigDataTest);
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());