blob: ddb920d3132161032015a6b0a92d300eee7203a0 [file] [log] [blame]
Ram Mohane4064ce2022-12-20 18:05:14 +05301/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Ram Mohane4064ce2022-12-20 18:05:14 +053017#include <set>
18#include <string>
Ram Mohane4064ce2022-12-20 18:05:14 +053019#include <unordered_set>
20
Mikhail Naganov872d4a62023-03-09 18:19:01 -080021#define LOG_TAG "VtsHalDynamicsProcessingTest"
22#include <android-base/logging.h>
Sneha Patilabc94642024-11-13 08:41:05 +000023#include <audio_utils/power.h>
24#include <audio_utils/primitives.h>
Mikhail Naganov872d4a62023-03-09 18:19:01 -080025
Ram Mohane4064ce2022-12-20 18:05:14 +053026#include <Utils.h>
Mikhail Naganov872d4a62023-03-09 18:19:01 -080027
Ram Mohane4064ce2022-12-20 18:05:14 +053028#include "EffectHelper.h"
Ram Mohanafdf90b2023-03-23 08:48:25 +053029#include "EffectRangeSpecific.h"
Ram Mohane4064ce2022-12-20 18:05:14 +053030
31using namespace android;
Ram Mohanafdf90b2023-03-23 08:48:25 +053032using namespace aidl::android::hardware::audio::effect::DynamicsProcessingRanges;
Ram Mohane4064ce2022-12-20 18:05:14 +053033
Ram Mohane4064ce2022-12-20 18:05:14 +053034using aidl::android::hardware::audio::effect::Descriptor;
35using aidl::android::hardware::audio::effect::DynamicsProcessing;
Shunkai Yaof8be1ac2023-03-06 18:41:27 +000036using aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing;
Ram Mohane4064ce2022-12-20 18:05:14 +053037using aidl::android::hardware::audio::effect::IEffect;
38using aidl::android::hardware::audio::effect::IFactory;
Ram Mohane4064ce2022-12-20 18:05:14 +053039using aidl::android::hardware::audio::effect::Parameter;
Jaideep Sharma74498412023-09-13 15:25:25 +053040using android::hardware::audio::common::testing::detail::TestExecutionTracer;
Ram Mohane4064ce2022-12-20 18:05:14 +053041
Sneha Patilba665282025-02-06 08:37:48 +000042constexpr int32_t kMinDataTestHalVersion = 3;
43
Ram Mohane4064ce2022-12-20 18:05:14 +053044/**
45 * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
46 * VtsAudioEffectTargetTest.
47 */
48class DynamicsProcessingTestHelper : public EffectHelper {
49 public:
50 DynamicsProcessingTestHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair,
Aayush Sonifbb5cd32024-11-21 10:51:46 +000051 int32_t channelLayout = kDefaultChannelLayout)
52 : mChannelLayout(channelLayout),
Sneha Patilabc94642024-11-13 08:41:05 +000053 mChannelCount(::aidl::android::hardware::audio::common::getChannelCount(
54 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout))) {
Ram Mohane4064ce2022-12-20 18:05:14 +053055 std::tie(mFactory, mDescriptor) = pair;
Ram Mohane4064ce2022-12-20 18:05:14 +053056 }
57
58 // setup
59 void SetUpDynamicsProcessingEffect() {
60 ASSERT_NE(nullptr, mFactory);
61 ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Ram Mohane4064ce2022-12-20 18:05:14 +053062 Parameter::Specific specific = getDefaultParamSpecific();
Shunkai Yao61f9dd22024-05-08 22:34:36 +000063 Parameter::Common common = createParamCommon(
Sneha Patilabc94642024-11-13 08:41:05 +000064 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
65 kSamplingFrequency /* oSampleRate */, kFrameCount /* iFrameCount */,
66 kFrameCount /* oFrameCount */,
Ram Mohane4064ce2022-12-20 18:05:14 +053067 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout),
68 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
Sneha Patilabc94642024-11-13 08:41:05 +000069 ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
Ram Mohane4064ce2022-12-20 18:05:14 +053070 ASSERT_NE(nullptr, mEffect);
71 mEngineConfigApplied = mEngineConfigPreset;
72 }
73
74 Parameter::Specific getDefaultParamSpecific() {
75 DynamicsProcessing dp = DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
76 mEngineConfigPreset);
77 Parameter::Specific specific =
78 Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(dp);
79 return specific;
80 }
81
82 // teardown
83 void TearDownDynamicsProcessingEffect() {
84 ASSERT_NO_FATAL_FAILURE(close(mEffect));
85 ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
86 }
87
88 // utils functions for parameter checking
Ram Mohane4064ce2022-12-20 18:05:14 +053089 bool isParamEqual(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dpRef,
90 const DynamicsProcessing& dpTest);
Ram Mohane4064ce2022-12-20 18:05:14 +053091 bool isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture& refCfg,
92 const DynamicsProcessing::EngineArchitecture& testCfg);
93
94 template <typename T>
95 std::vector<T> filterEnabledVector(const std::vector<T>& vec);
96
97 template <typename T>
98 bool isAidlVectorEqualAfterFilter(const std::vector<T>& source, const std::vector<T>& target);
99
100 template <typename T>
101 bool isAidlVectorEqual(const std::vector<T>& source, const std::vector<T>& target);
102
Ram Mohanafdf90b2023-03-23 08:48:25 +0530103 template <typename T>
104 bool isChannelConfigValid(const std::vector<T>& cfgs) {
105 auto& channelCount = mChannelCount;
106 return std::all_of(cfgs.cbegin(), cfgs.cend(), [channelCount](const T& cfg) {
107 return (cfg.channel >= 0 && cfg.channel < channelCount);
108 });
109 }
110
111 template <typename T>
112 bool isBandConfigValid(const std::vector<T>& cfgs, int bandCount);
113
114 bool isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp);
115
Ram Mohane4064ce2022-12-20 18:05:14 +0530116 // get set params and validate
117 void SetAndGetDynamicsProcessingParameters();
118
Sneha Patilabc94642024-11-13 08:41:05 +0000119 bool isAllParamsValid();
120
Sneha Patilcbf86a42024-11-26 10:41:54 +0000121 void setParamsAndProcess(std::vector<float>& input, std::vector<float>& output);
122
123 float calculateDb(const std::vector<float>& input, size_t startSamplePos);
124
Sneha Patil2da23d72025-02-25 10:54:18 +0000125 void getMagnitudeValue(const std::vector<float>& output, std::vector<float>& bufferMag);
126
127 void checkInputAndOutputEquality(const std::vector<float>& outputMag);
128
129 void setUpDataTest(const std::vector<int>& testFrequencies, float fullScaleSineDb);
130
131 void createChannelConfig();
132
Ram Mohane4064ce2022-12-20 18:05:14 +0530133 // enqueue test parameters
134 void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg);
135 void addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
136 void addPostEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
137 void addMbcChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
138 void addPreEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
139 void addPostEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
140 void addMbcBandConfigs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
141 void addLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig>& cfg);
142 void addInputGain(const std::vector<DynamicsProcessing::InputGain>& inputGain);
143
Sneha Patilba665282025-02-06 08:37:48 +0000144 void checkHalVersion();
145
Ram Mohane4064ce2022-12-20 18:05:14 +0530146 static constexpr float kPreferredProcessingDurationMs = 10.0f;
147 static constexpr int kBandCount = 5;
Sneha Patilabc94642024-11-13 08:41:05 +0000148 static constexpr int kSamplingFrequency = 44100;
149 static constexpr int kFrameCount = 2048;
Sneha Patilcbf86a42024-11-26 10:41:54 +0000150 static constexpr int kInputFrequency = 1000;
151 static constexpr size_t kStartIndex = 15 * kSamplingFrequency / 1000; // skip 15ms
Sneha Patil2da23d72025-02-25 10:54:18 +0000152 static constexpr float kToleranceDb = 0.5;
153 static constexpr int kNPointFFT = 1024;
154 static constexpr float kBinWidth = (float)kSamplingFrequency / kNPointFFT;
155 // Full scale sine wave with 1000 Hz frequency is -3 dB
156 static constexpr float kSineFullScaleDb = -3;
157 // Full scale sine wave with 100 Hz and 1000 Hz frequency is -6 dB
158 static constexpr float kSineMultitoneFullScaleDb = -6;
159 const std::vector<int> kCutoffFreqHz = {200 /*0th band cutoff*/, 2000 /*1st band cutoff*/};
160 std::vector<int> mMultitoneTestFrequencies = {100, 1000};
161 // Calculating normalizing factor by dividing the number of FFT points by half and the number of
162 // test frequencies. The normalization accounts for the FFT splitting the signal into positive
163 // and negative frequencies. Additionally, during multi-tone input generation, sample values are
164 // normalized to the range [-1, 1] by dividing them by the number of test frequencies.
165 float mNormalizingFactor = (kNPointFFT / (2 * mMultitoneTestFrequencies.size()));
166 std::vector<int> mBinOffsets;
167 std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
168 std::vector<float> mInput;
169 float mInputDb;
Ram Mohane4064ce2022-12-20 18:05:14 +0530170 std::shared_ptr<IFactory> mFactory;
171 std::shared_ptr<IEffect> mEffect;
172 Descriptor mDescriptor;
Sneha Patilabc94642024-11-13 08:41:05 +0000173 IEffect::OpenEffectReturn mOpenEffectReturn;
Ram Mohane4064ce2022-12-20 18:05:14 +0530174 DynamicsProcessing::EngineArchitecture mEngineConfigApplied;
175 DynamicsProcessing::EngineArchitecture mEngineConfigPreset{
176 .resolutionPreference =
177 DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
178 .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
179 .preEqStage = {.inUse = true, .bandCount = kBandCount},
180 .postEqStage = {.inUse = true, .bandCount = kBandCount},
181 .mbcStage = {.inUse = true, .bandCount = kBandCount},
182 .limiterInUse = true,
183 };
184
185 std::unordered_set<int /* channelId */> mPreEqChannelEnable;
186 std::unordered_set<int /* channelId */> mPostEqChannelEnable;
187 std::unordered_set<int /* channelId */> mMbcChannelEnable;
188 std::unordered_set<int /* channelId */> mLimiterChannelEnable;
189 static const std::set<std::vector<DynamicsProcessing::ChannelConfig>> kChannelConfigTestSet;
190 static const std::set<DynamicsProcessing::StageEnablement> kStageEnablementTestSet;
191 static const std::set<std::vector<DynamicsProcessing::InputGain>> kInputGainTestSet;
192
193 private:
Ram Mohane4064ce2022-12-20 18:05:14 +0530194 std::vector<std::pair<DynamicsProcessing::Tag, DynamicsProcessing>> mTags;
Sneha Patilabc94642024-11-13 08:41:05 +0000195
196 protected:
Aayush Sonifbb5cd32024-11-21 10:51:46 +0000197 const int32_t mChannelLayout;
Sneha Patilabc94642024-11-13 08:41:05 +0000198 const int mChannelCount;
Aayush Sonifbb5cd32024-11-21 10:51:46 +0000199
Ram Mohane4064ce2022-12-20 18:05:14 +0530200 void CleanUp() {
201 mTags.clear();
202 mPreEqChannelEnable.clear();
203 mPostEqChannelEnable.clear();
204 mMbcChannelEnable.clear();
205 mLimiterChannelEnable.clear();
206 }
207};
208
209// test value set for DynamicsProcessing::StageEnablement
210const std::set<DynamicsProcessing::StageEnablement>
211 DynamicsProcessingTestHelper::kStageEnablementTestSet = {
212 {.inUse = true, .bandCount = DynamicsProcessingTestHelper::kBandCount},
213 {.inUse = true, .bandCount = 0},
214 {.inUse = true, .bandCount = -1},
Ram Mohanafdf90b2023-03-23 08:48:25 +0530215 {.inUse = false, .bandCount = 0},
216 {.inUse = false, .bandCount = -1},
Ram Mohane4064ce2022-12-20 18:05:14 +0530217 {.inUse = false, .bandCount = DynamicsProcessingTestHelper::kBandCount}};
218
219// test value set for DynamicsProcessing::ChannelConfig
220const std::set<std::vector<DynamicsProcessing::ChannelConfig>>
221 DynamicsProcessingTestHelper::kChannelConfigTestSet = {
222 {{.channel = -1, .enable = false},
223 {.channel = 0, .enable = true},
224 {.channel = 1, .enable = false},
225 {.channel = 2, .enable = true}},
Ram Mohane4064ce2022-12-20 18:05:14 +0530226 {{.channel = -1, .enable = false}, {.channel = 2, .enable = true}},
Ram Mohane4064ce2022-12-20 18:05:14 +0530227 {{.channel = 0, .enable = true}, {.channel = 1, .enable = true}}};
228
229// test value set for DynamicsProcessing::InputGain
230const std::set<std::vector<DynamicsProcessing::InputGain>>
231 DynamicsProcessingTestHelper::kInputGainTestSet = {
232 {{.channel = 0, .gainDb = 10.f},
233 {.channel = 1, .gainDb = 0.f},
234 {.channel = 2, .gainDb = -10.f}},
Ram Mohane4064ce2022-12-20 18:05:14 +0530235 {{.channel = -1, .gainDb = -10.f}, {.channel = -2, .gainDb = 10.f}},
Ram Mohanafdf90b2023-03-23 08:48:25 +0530236 {{.channel = -1, .gainDb = 10.f}, {.channel = 0, .gainDb = -10.f}},
237 {{.channel = 0, .gainDb = 10.f}, {.channel = 1, .gainDb = -10.f}}};
Ram Mohane4064ce2022-12-20 18:05:14 +0530238
Ram Mohanafdf90b2023-03-23 08:48:25 +0530239template <typename T>
240bool DynamicsProcessingTestHelper::isBandConfigValid(const std::vector<T>& cfgs, int bandCount) {
Shunkai Yao53238b12024-03-29 23:09:04 +0000241 std::unordered_set<int> freqs;
Ram Mohanafdf90b2023-03-23 08:48:25 +0530242 for (auto cfg : cfgs) {
243 if (cfg.channel < 0 || cfg.channel >= mChannelCount) return false;
244 if (cfg.band < 0 || cfg.band >= bandCount) return false;
Shunkai Yao53238b12024-03-29 23:09:04 +0000245 // duplicated band index
246 if (freqs.find(cfg.band) != freqs.end()) return false;
247 freqs.insert(cfg.band);
Ram Mohanafdf90b2023-03-23 08:48:25 +0530248 }
Shunkai Yao53238b12024-03-29 23:09:04 +0000249 return true;
Ram Mohanafdf90b2023-03-23 08:48:25 +0530250}
251
252bool DynamicsProcessingTestHelper::isParamValid(const DynamicsProcessing::Tag& tag,
253 const DynamicsProcessing& dp) {
254 switch (tag) {
255 case DynamicsProcessing::preEq: {
Ram Mohanafdf90b2023-03-23 08:48:25 +0530256 return isChannelConfigValid(dp.get<DynamicsProcessing::preEq>());
257 }
258 case DynamicsProcessing::postEq: {
Ram Mohanafdf90b2023-03-23 08:48:25 +0530259 return isChannelConfigValid(dp.get<DynamicsProcessing::postEq>());
260 }
261 case DynamicsProcessing::mbc: {
Ram Mohanafdf90b2023-03-23 08:48:25 +0530262 return isChannelConfigValid(dp.get<DynamicsProcessing::mbc>());
263 }
264 case DynamicsProcessing::preEqBand: {
Ram Mohanafdf90b2023-03-23 08:48:25 +0530265 return isBandConfigValid(dp.get<DynamicsProcessing::preEqBand>(),
266 mEngineConfigApplied.preEqStage.bandCount);
267 }
268 case DynamicsProcessing::postEqBand: {
Ram Mohanafdf90b2023-03-23 08:48:25 +0530269 return isBandConfigValid(dp.get<DynamicsProcessing::postEqBand>(),
270 mEngineConfigApplied.postEqStage.bandCount);
271 }
272 case DynamicsProcessing::mbcBand: {
Ram Mohanafdf90b2023-03-23 08:48:25 +0530273 return isBandConfigValid(dp.get<DynamicsProcessing::mbcBand>(),
274 mEngineConfigApplied.mbcStage.bandCount);
275 }
276 case DynamicsProcessing::limiter: {
Ram Mohanafdf90b2023-03-23 08:48:25 +0530277 return isChannelConfigValid(dp.get<DynamicsProcessing::limiter>());
278 }
279 case DynamicsProcessing::inputGain: {
280 return isChannelConfigValid(dp.get<DynamicsProcessing::inputGain>());
281 }
282 default: {
283 return true;
284 }
285 }
286 return true;
287}
Ram Mohane4064ce2022-12-20 18:05:14 +0530288
Ram Mohane4064ce2022-12-20 18:05:14 +0530289bool DynamicsProcessingTestHelper::isParamEqual(const DynamicsProcessing::Tag& tag,
290 const DynamicsProcessing& dpRef,
291 const DynamicsProcessing& dpTest) {
292 switch (tag) {
293 case DynamicsProcessing::engineArchitecture: {
294 return isEngineConfigEqual(dpRef.get<DynamicsProcessing::engineArchitecture>(),
295 dpTest.get<DynamicsProcessing::engineArchitecture>());
296 }
297 case DynamicsProcessing::preEq: {
298 const auto& source = dpRef.get<DynamicsProcessing::preEq>();
299 const auto& target = dpTest.get<DynamicsProcessing::preEq>();
300 return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(source, target);
301 }
302 case DynamicsProcessing::postEq: {
303 return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
304 dpRef.get<DynamicsProcessing::postEq>(),
305 dpTest.get<DynamicsProcessing::postEq>());
306 }
307 case DynamicsProcessing::mbc: {
308 return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
309 dpRef.get<DynamicsProcessing::mbc>(), dpTest.get<DynamicsProcessing::mbc>());
310 }
311 case DynamicsProcessing::preEqBand: {
312 return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
313 dpRef.get<DynamicsProcessing::preEqBand>(),
314 dpTest.get<DynamicsProcessing::preEqBand>());
315 }
316 case DynamicsProcessing::postEqBand: {
317 return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
318 dpRef.get<DynamicsProcessing::postEqBand>(),
319 dpTest.get<DynamicsProcessing::postEqBand>());
320 }
321 case DynamicsProcessing::mbcBand: {
322 return isAidlVectorEqualAfterFilter<DynamicsProcessing::MbcBandConfig>(
323 dpRef.get<DynamicsProcessing::mbcBand>(),
324 dpTest.get<DynamicsProcessing::mbcBand>());
325 }
326 case DynamicsProcessing::limiter: {
327 return isAidlVectorEqualAfterFilter<DynamicsProcessing::LimiterConfig>(
328 dpRef.get<DynamicsProcessing::limiter>(),
329 dpTest.get<DynamicsProcessing::limiter>());
330 }
331 case DynamicsProcessing::inputGain: {
332 return isAidlVectorEqual<DynamicsProcessing::InputGain>(
333 dpRef.get<DynamicsProcessing::inputGain>(),
334 dpTest.get<DynamicsProcessing::inputGain>());
335 }
Shunkai Yaob2325e52023-03-03 19:34:47 +0000336 case DynamicsProcessing::vendor: {
Ram Mohane4064ce2022-12-20 18:05:14 +0530337 return false;
338 }
339 }
340}
341
Ram Mohane4064ce2022-12-20 18:05:14 +0530342bool DynamicsProcessingTestHelper::isEngineConfigEqual(
343 const DynamicsProcessing::EngineArchitecture& ref,
344 const DynamicsProcessing::EngineArchitecture& test) {
345 return ref == test;
346}
347
348template <typename T>
349std::vector<T> DynamicsProcessingTestHelper::filterEnabledVector(const std::vector<T>& vec) {
350 std::vector<T> ret;
351 std::copy_if(vec.begin(), vec.end(), std::back_inserter(ret),
352 [](const auto& v) { return v.enable; });
353 return ret;
354}
355
356template <typename T>
357bool DynamicsProcessingTestHelper::isAidlVectorEqual(const std::vector<T>& source,
358 const std::vector<T>& target) {
359 if (source.size() != target.size()) return false;
360
361 auto tempS = source;
362 auto tempT = target;
363 std::sort(tempS.begin(), tempS.end());
364 std::sort(tempT.begin(), tempT.end());
365 return tempS == tempT;
366}
367
368template <typename T>
369bool DynamicsProcessingTestHelper::isAidlVectorEqualAfterFilter(const std::vector<T>& source,
370 const std::vector<T>& target) {
371 return isAidlVectorEqual<T>(filterEnabledVector<T>(source), filterEnabledVector<T>(target));
372}
373
374void DynamicsProcessingTestHelper::SetAndGetDynamicsProcessingParameters() {
Sneha Patilabc94642024-11-13 08:41:05 +0000375 for (const auto& [tag, dp] : mTags) {
Ram Mohane4064ce2022-12-20 18:05:14 +0530376 // validate parameter
377 Descriptor desc;
378 ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
Ram Mohanafdf90b2023-03-23 08:48:25 +0530379 bool valid = isParamInRange(dp, desc.capability.range.get<Range::dynamicsProcessing>());
380 if (valid) valid = isParamValid(tag, dp);
Ram Mohane4064ce2022-12-20 18:05:14 +0530381 const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
382
383 // set parameter
384 Parameter expectParam;
385 Parameter::Specific specific;
386 specific.set<Parameter::Specific::dynamicsProcessing>(dp);
387 expectParam.set<Parameter::specific>(specific);
Shunkai Yao0a0c45e2023-02-13 17:41:11 +0000388 ASSERT_STATUS(expected, mEffect->setParameter(expectParam))
389 << "\n"
390 << expectParam.toString() << "\n"
391 << desc.toString();
Ram Mohane4064ce2022-12-20 18:05:14 +0530392
393 // only get if parameter in range and set success
394 if (expected == EX_NONE) {
395 Parameter getParam;
396 Parameter::Id id;
397 DynamicsProcessing::Id dpId;
398 dpId.set<DynamicsProcessing::Id::commonTag>(tag);
399 id.set<Parameter::Id::dynamicsProcessingTag>(dpId);
400 // if set success, then get should match
401 EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
402 Parameter::Specific specificTest = getParam.get<Parameter::specific>();
403 const auto& target = specificTest.get<Parameter::Specific::dynamicsProcessing>();
404 EXPECT_TRUE(isParamEqual(tag, dp, target)) << dp.toString() << "\n"
405 << target.toString();
406 // update mEngineConfigApplied after setting successfully
407 if (tag == DynamicsProcessing::engineArchitecture) {
408 mEngineConfigApplied = target.get<DynamicsProcessing::engineArchitecture>();
409 }
410 }
411 }
412}
413
Sneha Patilabc94642024-11-13 08:41:05 +0000414bool DynamicsProcessingTestHelper::isAllParamsValid() {
415 if (mTags.empty()) {
416 return false;
417 }
418 for (const auto& [tag, dp] : mTags) {
419 // validate parameter
420 if (!isParamInRange(dp, mDescriptor.capability.range.get<Range::dynamicsProcessing>())) {
421 return false;
422 }
423 if (!isParamValid(tag, dp)) {
424 return false;
425 }
426 }
427 return true;
428}
429
Aayush Sonifbb5cd32024-11-21 10:51:46 +0000430// This function calculates power for both and mono and stereo data as the total power for
431// interleaved multichannel data can be calculated by treating it as a continuous mono input.
Sneha Patilcbf86a42024-11-26 10:41:54 +0000432float DynamicsProcessingTestHelper::calculateDb(const std::vector<float>& input,
433 size_t startSamplePos = 0) {
434 return audio_utils_compute_power_mono(input.data() + startSamplePos, AUDIO_FORMAT_PCM_FLOAT,
435 input.size() - startSamplePos);
436}
437
438void DynamicsProcessingTestHelper::setParamsAndProcess(std::vector<float>& input,
439 std::vector<float>& output) {
440 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
441 if (isAllParamsValid()) {
442 ASSERT_NO_FATAL_FAILURE(
443 processAndWriteToOutput(input, output, mEffect, &mOpenEffectReturn));
444 ASSERT_GT(output.size(), kStartIndex);
445 }
446}
447
Sneha Patil2da23d72025-02-25 10:54:18 +0000448void DynamicsProcessingTestHelper::getMagnitudeValue(const std::vector<float>& output,
449 std::vector<float>& bufferMag) {
450 std::vector<float> subOutput(output.begin() + kStartIndex, output.end());
451 EXPECT_NO_FATAL_FAILURE(calculateMagnitudeMono(bufferMag, subOutput, mBinOffsets, kNPointFFT));
452}
453
454void DynamicsProcessingTestHelper::checkInputAndOutputEquality(
455 const std::vector<float>& outputMag) {
456 std::vector<float> inputMag(mBinOffsets.size());
457 EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(mInput, inputMag));
458 for (size_t i = 0; i < inputMag.size(); i++) {
459 EXPECT_NEAR(calculateDb({inputMag[i] / mNormalizingFactor}),
460 calculateDb({outputMag[i] / mNormalizingFactor}), kToleranceDb);
461 }
462}
463
464void DynamicsProcessingTestHelper::setUpDataTest(const std::vector<int>& testFrequencies,
465 float fullScaleSineDb) {
466 ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect());
467 SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
Sneha Patile5ca2472025-03-11 12:55:39 +0000468 mInput.resize(kFrameCount * mChannelCount);
Sneha Patil2da23d72025-02-25 10:54:18 +0000469 ASSERT_NO_FATAL_FAILURE(
470 generateSineWave(testFrequencies, mInput, 1.0, kSamplingFrequency, mChannelLayout));
471 mInputDb = calculateDb(mInput);
472 ASSERT_NEAR(mInputDb, fullScaleSineDb, kToleranceDb);
473}
474
475void DynamicsProcessingTestHelper::createChannelConfig() {
476 for (int i = 0; i < mChannelCount; i++) {
477 mChannelConfig.push_back(DynamicsProcessing::ChannelConfig(i, true));
478 }
479}
480
Ram Mohane4064ce2022-12-20 18:05:14 +0530481void DynamicsProcessingTestHelper::addEngineConfig(
482 const DynamicsProcessing::EngineArchitecture& cfg) {
483 DynamicsProcessing dp;
484 dp.set<DynamicsProcessing::engineArchitecture>(cfg);
485 mTags.push_back({DynamicsProcessing::engineArchitecture, dp});
486}
487
488void DynamicsProcessingTestHelper::addPreEqChannelConfig(
489 const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
490 DynamicsProcessing dp;
491 dp.set<DynamicsProcessing::preEq>(cfgs);
492 mTags.push_back({DynamicsProcessing::preEq, dp});
493 for (auto& cfg : cfgs) {
494 if (cfg.enable) mPreEqChannelEnable.insert(cfg.channel);
495 }
496}
497
498void DynamicsProcessingTestHelper::addPostEqChannelConfig(
499 const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
500 DynamicsProcessing dp;
501 dp.set<DynamicsProcessing::postEq>(cfgs);
502 mTags.push_back({DynamicsProcessing::postEq, dp});
503 for (auto& cfg : cfgs) {
504 if (cfg.enable) mPostEqChannelEnable.insert(cfg.channel);
505 }
506}
507
508void DynamicsProcessingTestHelper::addMbcChannelConfig(
509 const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
510 DynamicsProcessing dp;
511 dp.set<DynamicsProcessing::mbc>(cfgs);
512 mTags.push_back({DynamicsProcessing::mbc, dp});
513 for (auto& cfg : cfgs) {
514 if (cfg.enable) mMbcChannelEnable.insert(cfg.channel);
515 }
516}
517
518void DynamicsProcessingTestHelper::addPreEqBandConfigs(
519 const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
520 DynamicsProcessing dp;
521 dp.set<DynamicsProcessing::preEqBand>(cfgs);
522 mTags.push_back({DynamicsProcessing::preEqBand, dp});
523}
524
525void DynamicsProcessingTestHelper::addPostEqBandConfigs(
526 const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
527 DynamicsProcessing dp;
528 dp.set<DynamicsProcessing::postEqBand>(cfgs);
529 mTags.push_back({DynamicsProcessing::postEqBand, dp});
530}
531
532void DynamicsProcessingTestHelper::addMbcBandConfigs(
533 const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
534 DynamicsProcessing dp;
535 dp.set<DynamicsProcessing::mbcBand>(cfgs);
536 mTags.push_back({DynamicsProcessing::mbcBand, dp});
537}
538
539void DynamicsProcessingTestHelper::addLimiterConfig(
540 const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
541 DynamicsProcessing dp;
542 dp.set<DynamicsProcessing::limiter>(cfgs);
543 mTags.push_back({DynamicsProcessing::limiter, dp});
544 for (auto& cfg : cfgs) {
545 if (cfg.enable) mLimiterChannelEnable.insert(cfg.channel);
546 }
547}
548
549void DynamicsProcessingTestHelper::addInputGain(
550 const std::vector<DynamicsProcessing::InputGain>& inputGains) {
551 DynamicsProcessing dp;
552 dp.set<DynamicsProcessing::inputGain>(inputGains);
553 mTags.push_back({DynamicsProcessing::inputGain, dp});
554}
555
Sneha Patilba665282025-02-06 08:37:48 +0000556void DynamicsProcessingTestHelper::checkHalVersion() {
557 if (int32_t version;
558 mEffect->getInterfaceVersion(&version).isOk() && version < kMinDataTestHalVersion) {
559 GTEST_SKIP() << "Skipping the data test for version: " << version << "\n";
560 }
561}
562
Sneha Patilabc94642024-11-13 08:41:05 +0000563void fillLimiterConfig(std::vector<DynamicsProcessing::LimiterConfig>& limiterConfigList,
564 int channelIndex, bool enable, int linkGroup, float attackTime,
565 float releaseTime, float ratio, float threshold, float postGain) {
566 DynamicsProcessing::LimiterConfig cfg;
567 cfg.channel = channelIndex;
568 cfg.enable = enable;
569 cfg.linkGroup = linkGroup;
570 cfg.attackTimeMs = attackTime;
571 cfg.releaseTimeMs = releaseTime;
572 cfg.ratio = ratio;
573 cfg.thresholdDb = threshold;
574 cfg.postGainDb = postGain;
575 limiterConfigList.push_back(cfg);
576}
577
Sneha Patilc3252762024-11-21 10:51:46 +0000578DynamicsProcessing::MbcBandConfig createMbcBandConfig(int channel, int band, float cutoffFreqHz,
579 float attackTimeMs, float releaseTimeMs,
580 float ratio, float thresholdDb,
581 float kneeWidthDb, float noiseGate,
582 float expanderRatio, float preGainDb,
583 float postGainDb) {
584 return DynamicsProcessing::MbcBandConfig{.channel = channel,
585 .band = band,
586 .enable = true,
587 .cutoffFrequencyHz = cutoffFreqHz,
588 .attackTimeMs = attackTimeMs,
589 .releaseTimeMs = releaseTimeMs,
590 .ratio = ratio,
591 .thresholdDb = thresholdDb,
592 .kneeWidthDb = kneeWidthDb,
593 .noiseGateThresholdDb = noiseGate,
594 .expanderRatio = expanderRatio,
595 .preGainDb = preGainDb,
596 .postGainDb = postGainDb};
597}
598
Sneha Patil2da23d72025-02-25 10:54:18 +0000599DynamicsProcessing::EqBandConfig creatEqBandConfig(int channel, int band, float cutOffFreqHz,
Sneha Patil4d8a91c2025-03-03 08:03:43 +0000600 float gainDb, bool enable) {
Sneha Patil2da23d72025-02-25 10:54:18 +0000601 return DynamicsProcessing::EqBandConfig{.channel = channel,
602 .band = band,
Sneha Patil4d8a91c2025-03-03 08:03:43 +0000603 .enable = enable,
Sneha Patil2da23d72025-02-25 10:54:18 +0000604 .cutoffFrequencyHz = cutOffFreqHz,
605 .gainDb = gainDb};
606}
607
Ram Mohane4064ce2022-12-20 18:05:14 +0530608/**
609 * Test DynamicsProcessing Engine Configuration
610 */
611enum EngineArchitectureTestParamName {
612 ENGINE_TEST_INSTANCE_NAME,
613 ENGINE_TEST_RESOLUTION_PREFERENCE,
614 ENGINE_TEST_PREFERRED_DURATION,
Shunkai Yaof137ba42024-04-11 17:11:03 +0000615 ENGINE_TEST_STAGE_ENABLEMENT
Ram Mohane4064ce2022-12-20 18:05:14 +0530616};
617using EngineArchitectureTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
618 DynamicsProcessing::ResolutionPreference, float,
Shunkai Yaof137ba42024-04-11 17:11:03 +0000619 DynamicsProcessing::StageEnablement>;
Ram Mohane4064ce2022-12-20 18:05:14 +0530620
621void fillEngineArchConfig(DynamicsProcessing::EngineArchitecture& cfg,
622 const EngineArchitectureTestParams& params) {
623 cfg.resolutionPreference = std::get<ENGINE_TEST_RESOLUTION_PREFERENCE>(params);
624 cfg.preferredProcessingDurationMs = std::get<ENGINE_TEST_PREFERRED_DURATION>(params);
625 cfg.preEqStage = cfg.postEqStage = cfg.mbcStage =
626 std::get<ENGINE_TEST_STAGE_ENABLEMENT>(params);
Shunkai Yaof137ba42024-04-11 17:11:03 +0000627 cfg.limiterInUse = true;
Ram Mohane4064ce2022-12-20 18:05:14 +0530628}
629
630class DynamicsProcessingTestEngineArchitecture
631 : public ::testing::TestWithParam<EngineArchitectureTestParams>,
632 public DynamicsProcessingTestHelper {
633 public:
634 DynamicsProcessingTestEngineArchitecture()
635 : DynamicsProcessingTestHelper(std::get<ENGINE_TEST_INSTANCE_NAME>(GetParam())) {
636 fillEngineArchConfig(mCfg, GetParam());
637 };
638
Aayush Soni63d6e2a2025-03-04 13:37:28 +0000639 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
Ram Mohane4064ce2022-12-20 18:05:14 +0530640
641 void TearDown() override { TearDownDynamicsProcessingEffect(); }
642
643 DynamicsProcessing::EngineArchitecture mCfg;
644};
645
646TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
Sneha Patil3587ae52025-01-06 05:59:08 +0000647 addEngineConfig(mCfg);
Sneha Patilabc94642024-11-13 08:41:05 +0000648 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +0530649}
650
651INSTANTIATE_TEST_SUITE_P(
652 DynamicsProcessingTest, DynamicsProcessingTestEngineArchitecture,
653 ::testing::Combine(
654 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
Shunkai Yaof8be1ac2023-03-06 18:41:27 +0000655 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
Ram Mohanafdf90b2023-03-23 08:48:25 +0530656 testing::Values(
657 DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION,
658 DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
659 static_cast<DynamicsProcessing::ResolutionPreference>(-1)), // variant
660 testing::Values(-10.f, 0.f, 10.f), // processing duration
Ram Mohane4064ce2022-12-20 18:05:14 +0530661 testing::ValuesIn(
Shunkai Yaof137ba42024-04-11 17:11:03 +0000662 DynamicsProcessingTestHelper::kStageEnablementTestSet) // preEQ/postEQ/mbc
663 ),
Ram Mohane4064ce2022-12-20 18:05:14 +0530664 [](const auto& info) {
665 auto descriptor = std::get<ENGINE_TEST_INSTANCE_NAME>(info.param).second;
666 DynamicsProcessing::EngineArchitecture cfg;
667 fillEngineArchConfig(cfg, info.param);
Jaideep Sharmae4c7a962023-06-14 19:14:44 +0530668 std::string name = getPrefix(descriptor) + "_Cfg_" + cfg.toString();
Ram Mohane4064ce2022-12-20 18:05:14 +0530669 std::replace_if(
670 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
671 return name;
672 });
673GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEngineArchitecture);
674
675/**
676 * Test DynamicsProcessing Input Gain
677 */
678enum InputGainTestParamName {
679 INPUT_GAIN_INSTANCE_NAME,
680 INPUT_GAIN_PARAM,
681};
682class DynamicsProcessingTestInputGain
683 : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
684 std::vector<DynamicsProcessing::InputGain>>>,
685 public DynamicsProcessingTestHelper {
686 public:
687 DynamicsProcessingTestInputGain()
688 : DynamicsProcessingTestHelper(std::get<INPUT_GAIN_INSTANCE_NAME>(GetParam())),
Sneha Patilabc94642024-11-13 08:41:05 +0000689 mInputGain(std::get<INPUT_GAIN_PARAM>(GetParam())) {};
Ram Mohane4064ce2022-12-20 18:05:14 +0530690
Aayush Soni63d6e2a2025-03-04 13:37:28 +0000691 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
Ram Mohane4064ce2022-12-20 18:05:14 +0530692
693 void TearDown() override { TearDownDynamicsProcessingEffect(); }
694
695 const std::vector<DynamicsProcessing::InputGain> mInputGain;
696};
697
698TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
Sneha Patil3587ae52025-01-06 05:59:08 +0000699 addInputGain(mInputGain);
Sneha Patilabc94642024-11-13 08:41:05 +0000700 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +0530701}
702
703INSTANTIATE_TEST_SUITE_P(
704 DynamicsProcessingTest, DynamicsProcessingTestInputGain,
705 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
Shunkai Yaof8be1ac2023-03-06 18:41:27 +0000706 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
Ram Mohane4064ce2022-12-20 18:05:14 +0530707 testing::ValuesIn(DynamicsProcessingTestInputGain::kInputGainTestSet)),
708 [](const auto& info) {
709 auto descriptor = std::get<INPUT_GAIN_INSTANCE_NAME>(info.param).second;
710 std::string gains =
711 ::android::internal::ToString(std::get<INPUT_GAIN_PARAM>(info.param));
712 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
713 descriptor.common.name + "_UUID_" +
Shunkai Yao6f822452024-03-29 18:45:30 +0000714 toString(descriptor.common.id.uuid) + "_inputGains_" + gains;
Ram Mohane4064ce2022-12-20 18:05:14 +0530715 std::replace_if(
716 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
717 return name;
718 });
719GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestInputGain);
720
Sneha Patilcbf86a42024-11-26 10:41:54 +0000721class DynamicsProcessingInputGainDataTest
722 : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
723 public DynamicsProcessingTestHelper {
724 public:
725 DynamicsProcessingInputGainDataTest()
Sneha Patile5ca2472025-03-11 12:55:39 +0000726 : DynamicsProcessingTestHelper((GetParam()), AudioChannelLayout::LAYOUT_MONO) {}
Sneha Patilcbf86a42024-11-26 10:41:54 +0000727
Aayush Soni63d6e2a2025-03-04 13:37:28 +0000728 void SetUp() override {
Sneha Patile5ca2472025-03-11 12:55:39 +0000729 ASSERT_NO_FATAL_FAILURE(setUpDataTest({kInputFrequency}, kSineFullScaleDb));
Aayush Soni63d6e2a2025-03-04 13:37:28 +0000730 }
Sneha Patilcbf86a42024-11-26 10:41:54 +0000731
732 void TearDown() override { TearDownDynamicsProcessingEffect(); }
733
734 void cleanUpInputGainConfig() {
735 CleanUp();
736 mInputGain.clear();
737 }
738
739 std::vector<DynamicsProcessing::InputGain> mInputGain;
Sneha Patilcbf86a42024-11-26 10:41:54 +0000740};
741
742TEST_P(DynamicsProcessingInputGainDataTest, SetAndGetInputGain) {
743 std::vector<float> gainDbValues = {-85, -40, 0, 40, 85};
744 for (float gainDb : gainDbValues) {
745 cleanUpInputGainConfig();
746 for (int i = 0; i < mChannelCount; i++) {
747 mInputGain.push_back(DynamicsProcessing::InputGain(i, gainDb));
748 }
749 std::vector<float> output(mInput.size());
Sneha Patil3587ae52025-01-06 05:59:08 +0000750 addInputGain(mInputGain);
Sneha Patilcbf86a42024-11-26 10:41:54 +0000751 EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
752 if (!isAllParamsValid()) {
753 continue;
754 }
755 float outputDb = calculateDb(output, kStartIndex);
756 EXPECT_NEAR(outputDb, mInputDb + gainDb, kToleranceDb)
757 << "InputGain: " << gainDb << ", OutputDb: " << outputDb;
758 }
759}
760
761INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingInputGainDataTest,
762 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
763 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
764 [](const auto& info) {
765 auto descriptor = info.param;
766 std::string name = getPrefix(descriptor.second);
767 std::replace_if(
768 name.begin(), name.end(),
769 [](const char c) { return !std::isalnum(c); }, '_');
770 return name;
771 });
772GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingInputGainDataTest);
773
Ram Mohane4064ce2022-12-20 18:05:14 +0530774/**
775 * Test DynamicsProcessing Limiter Config
776 */
777enum LimiterConfigTestParamName {
778 LIMITER_INSTANCE_NAME,
779 LIMITER_CHANNEL,
Ram Mohane4064ce2022-12-20 18:05:14 +0530780 LIMITER_LINK_GROUP,
Ram Mohane4064ce2022-12-20 18:05:14 +0530781 LIMITER_ATTACK_TIME,
782 LIMITER_RELEASE_TIME,
783 LIMITER_RATIO,
784 LIMITER_THRESHOLD,
785 LIMITER_POST_GAIN,
Ram Mohane4064ce2022-12-20 18:05:14 +0530786};
Ram Mohane4064ce2022-12-20 18:05:14 +0530787
Shunkai Yaof137ba42024-04-11 17:11:03 +0000788using LimiterConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
Sneha Patilabc94642024-11-13 08:41:05 +0000789 int32_t, int32_t, float, float, float, float, float>;
Ram Mohane4064ce2022-12-20 18:05:14 +0530790
Sneha Patilabc94642024-11-13 08:41:05 +0000791void fillLimiterConfig(std::vector<DynamicsProcessing::LimiterConfig>& cfg,
Ram Mohane4064ce2022-12-20 18:05:14 +0530792 const LimiterConfigTestParams& params) {
Sneha Patilabc94642024-11-13 08:41:05 +0000793 fillLimiterConfig(cfg, std::get<LIMITER_CHANNEL>(params), true,
794 std::get<LIMITER_LINK_GROUP>(params), std::get<LIMITER_ATTACK_TIME>(params),
795 std::get<LIMITER_RELEASE_TIME>(params), std::get<LIMITER_RATIO>(params),
796 std::get<LIMITER_THRESHOLD>(params), std::get<LIMITER_POST_GAIN>(params));
Ram Mohane4064ce2022-12-20 18:05:14 +0530797}
798
799class DynamicsProcessingTestLimiterConfig
800 : public ::testing::TestWithParam<LimiterConfigTestParams>,
801 public DynamicsProcessingTestHelper {
802 public:
803 DynamicsProcessingTestLimiterConfig()
Shunkai Yaof137ba42024-04-11 17:11:03 +0000804 : DynamicsProcessingTestHelper(std::get<LIMITER_INSTANCE_NAME>(GetParam())) {
Sneha Patilabc94642024-11-13 08:41:05 +0000805 fillLimiterConfig(mLimiterConfigList, GetParam());
Ram Mohane4064ce2022-12-20 18:05:14 +0530806 }
807
Aayush Soni63d6e2a2025-03-04 13:37:28 +0000808 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
Ram Mohane4064ce2022-12-20 18:05:14 +0530809
810 void TearDown() override { TearDownDynamicsProcessingEffect(); }
811
812 DynamicsProcessing::LimiterConfig mCfg;
Sneha Patilabc94642024-11-13 08:41:05 +0000813 std::vector<DynamicsProcessing::LimiterConfig> mLimiterConfigList;
Ram Mohane4064ce2022-12-20 18:05:14 +0530814};
815
816TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
Sneha Patil3587ae52025-01-06 05:59:08 +0000817 addEngineConfig(mEngineConfigPreset);
818 addLimiterConfig(mLimiterConfigList);
Sneha Patilabc94642024-11-13 08:41:05 +0000819 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +0530820}
821
822INSTANTIATE_TEST_SUITE_P(
823 DynamicsProcessingTest, DynamicsProcessingTestLimiterConfig,
824 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
Shunkai Yaof8be1ac2023-03-06 18:41:27 +0000825 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
Sneha Patilabc94642024-11-13 08:41:05 +0000826 testing::Values(-1, 0, 1, 2), // channel index
827 testing::Values(3), // link group
828 testing::Values(-1, 1), // attackTime
829 testing::Values(-60, 60), // releaseTime
830 testing::Values(-2.5, 2.5), // ratio
831 testing::Values(-2, 2), // thresh
832 testing::Values(-3.14, 3.14) // postGain
833 ),
Ram Mohane4064ce2022-12-20 18:05:14 +0530834 [](const auto& info) {
835 auto descriptor = std::get<LIMITER_INSTANCE_NAME>(info.param).second;
Sneha Patilabc94642024-11-13 08:41:05 +0000836 std::vector<DynamicsProcessing::LimiterConfig> cfg;
Ram Mohane4064ce2022-12-20 18:05:14 +0530837 fillLimiterConfig(cfg, info.param);
Sneha Patilabc94642024-11-13 08:41:05 +0000838 std::string name =
839 "Implementer_" + getPrefix(descriptor) + "_limiterConfig_" + cfg[0].toString();
Ram Mohane4064ce2022-12-20 18:05:14 +0530840 std::replace_if(
841 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
842 return name;
843 });
844GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestLimiterConfig);
845
Sneha Patilabc94642024-11-13 08:41:05 +0000846using LimiterConfigDataTestParams = std::pair<std::shared_ptr<IFactory>, Descriptor>;
847
848class DynamicsProcessingLimiterConfigDataTest
849 : public ::testing::TestWithParam<LimiterConfigDataTestParams>,
850 public DynamicsProcessingTestHelper {
851 public:
Sneha Patile5ca2472025-03-11 12:55:39 +0000852 DynamicsProcessingLimiterConfigDataTest(LimiterConfigDataTestParams param = GetParam(),
853 int32_t layout = AudioChannelLayout::LAYOUT_MONO)
854 : DynamicsProcessingTestHelper(param, layout) {}
Sneha Patilabc94642024-11-13 08:41:05 +0000855
Aayush Soni63d6e2a2025-03-04 13:37:28 +0000856 void SetUp() override {
Sneha Patile5ca2472025-03-11 12:55:39 +0000857 ASSERT_NO_FATAL_FAILURE(setUpDataTest({kInputFrequency}, kSineFullScaleDb));
Aayush Soni63d6e2a2025-03-04 13:37:28 +0000858 }
Sneha Patilabc94642024-11-13 08:41:05 +0000859
860 void TearDown() override { TearDownDynamicsProcessingEffect(); }
861
Sneha Patilabc94642024-11-13 08:41:05 +0000862 void computeThreshold(float ratio, float outputDb, float& threshold) {
863 EXPECT_NE(ratio, 0);
864 threshold = (mInputDb - (ratio * outputDb)) / (1 - ratio);
865 }
866
867 void computeRatio(float threshold, float outputDb, float& ratio) {
868 float inputOverThreshold = mInputDb - threshold;
869 float outputOverThreshold = outputDb - threshold;
870 EXPECT_NE(outputOverThreshold, 0);
871 ratio = inputOverThreshold / outputOverThreshold;
872 }
873
Sneha Patilcbf86a42024-11-26 10:41:54 +0000874 void setLimiterParamsAndProcess(std::vector<float>& input, std::vector<float>& output) {
Sneha Patil3587ae52025-01-06 05:59:08 +0000875 addEngineConfig(mEngineConfigPreset);
876 addLimiterConfig(mLimiterConfigList);
Sneha Patilcbf86a42024-11-26 10:41:54 +0000877 EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(input, output));
Sneha Patilabc94642024-11-13 08:41:05 +0000878 }
879
880 void cleanUpLimiterConfig() {
881 CleanUp();
882 mLimiterConfigList.clear();
883 }
884 static constexpr float kDefaultLinkerGroup = 3;
885 static constexpr float kDefaultAttackTime = 0;
886 static constexpr float kDefaultReleaseTime = 0;
887 static constexpr float kDefaultRatio = 4;
Sneha Patilcbf86a42024-11-26 10:41:54 +0000888 static constexpr float kDefaultThreshold = -10;
Sneha Patilabc94642024-11-13 08:41:05 +0000889 static constexpr float kDefaultPostGain = 0;
Sneha Patil2da23d72025-02-25 10:54:18 +0000890 static constexpr float kLimiterTestToleranceDb = 0.05;
Sneha Patilabc94642024-11-13 08:41:05 +0000891 std::vector<DynamicsProcessing::LimiterConfig> mLimiterConfigList;
Sneha Patilabc94642024-11-13 08:41:05 +0000892 int mBufferSize;
893};
894
895TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingThresholdDb) {
896 std::vector<float> thresholdValues = {-200, -150, -100, -50, -5, 0};
897 std::vector<float> output(mInput.size());
898 float previousThreshold = -FLT_MAX;
899 for (float threshold : thresholdValues) {
Sneha Patilcbf86a42024-11-26 10:41:54 +0000900 cleanUpLimiterConfig();
Sneha Patilabc94642024-11-13 08:41:05 +0000901 for (int i = 0; i < mChannelCount; i++) {
902 fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
903 kDefaultReleaseTime, kDefaultRatio, threshold, kDefaultPostGain);
904 }
Sneha Patilc3252762024-11-21 10:51:46 +0000905 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
Sneha Patilabc94642024-11-13 08:41:05 +0000906 if (!isAllParamsValid()) {
907 continue;
908 }
909 float outputDb = calculateDb(output, kStartIndex);
910 if (threshold >= mInputDb || kDefaultRatio == 1) {
Sneha Patil2da23d72025-02-25 10:54:18 +0000911 EXPECT_NEAR(mInputDb, outputDb, kLimiterTestToleranceDb);
Sneha Patilabc94642024-11-13 08:41:05 +0000912 } else {
913 float calculatedThreshold = 0;
Sneha Patilc3252762024-11-21 10:51:46 +0000914 ASSERT_NO_FATAL_FAILURE(computeThreshold(kDefaultRatio, outputDb, calculatedThreshold));
Sneha Patilabc94642024-11-13 08:41:05 +0000915 ASSERT_GT(calculatedThreshold, previousThreshold);
916 previousThreshold = calculatedThreshold;
917 }
918 }
919}
920
921TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingRatio) {
922 std::vector<float> ratioValues = {1, 10, 20, 30, 40, 50};
923 std::vector<float> output(mInput.size());
Sneha Patilabc94642024-11-13 08:41:05 +0000924 float previousRatio = 0;
925 for (float ratio : ratioValues) {
Sneha Patilcbf86a42024-11-26 10:41:54 +0000926 cleanUpLimiterConfig();
Sneha Patilabc94642024-11-13 08:41:05 +0000927 for (int i = 0; i < mChannelCount; i++) {
928 fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
Sneha Patilcbf86a42024-11-26 10:41:54 +0000929 kDefaultReleaseTime, ratio, kDefaultThreshold, kDefaultPostGain);
Sneha Patilabc94642024-11-13 08:41:05 +0000930 }
Sneha Patilc3252762024-11-21 10:51:46 +0000931 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
Sneha Patilabc94642024-11-13 08:41:05 +0000932 if (!isAllParamsValid()) {
933 continue;
934 }
935 float outputDb = calculateDb(output, kStartIndex);
936
Sneha Patilcbf86a42024-11-26 10:41:54 +0000937 if (kDefaultThreshold >= mInputDb) {
Sneha Patil2da23d72025-02-25 10:54:18 +0000938 EXPECT_NEAR(mInputDb, outputDb, kLimiterTestToleranceDb);
Sneha Patilabc94642024-11-13 08:41:05 +0000939 } else {
940 float calculatedRatio = 0;
Sneha Patilc3252762024-11-21 10:51:46 +0000941 ASSERT_NO_FATAL_FAILURE(computeRatio(kDefaultThreshold, outputDb, calculatedRatio));
Sneha Patilabc94642024-11-13 08:41:05 +0000942 ASSERT_GT(calculatedRatio, previousRatio);
943 previousRatio = calculatedRatio;
944 }
945 }
946}
947
Sneha Patilcbf86a42024-11-26 10:41:54 +0000948TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingPostGain) {
949 std::vector<float> postGainDbValues = {-85, -40, 0, 40, 85};
950 std::vector<float> output(mInput.size());
951 for (float postGainDb : postGainDbValues) {
952 cleanUpLimiterConfig();
Sneha Patil903c6202025-01-30 06:37:10 +0000953 ASSERT_NO_FATAL_FAILURE(generateSineWave(kInputFrequency, mInput, dBToAmplitude(postGainDb),
954 kSamplingFrequency, mChannelLayout));
955 mInputDb = calculateDb(mInput);
Sneha Patil2da23d72025-02-25 10:54:18 +0000956 EXPECT_NEAR(mInputDb, kSineFullScaleDb - postGainDb, kLimiterTestToleranceDb);
Sneha Patilcbf86a42024-11-26 10:41:54 +0000957 for (int i = 0; i < mChannelCount; i++) {
958 fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
Sneha Patil903c6202025-01-30 06:37:10 +0000959 kDefaultReleaseTime, 1, kDefaultThreshold, postGainDb);
Sneha Patilcbf86a42024-11-26 10:41:54 +0000960 }
Sneha Patilc3252762024-11-21 10:51:46 +0000961 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
Sneha Patilcbf86a42024-11-26 10:41:54 +0000962 if (!isAllParamsValid()) {
963 continue;
964 }
965 float outputDb = calculateDb(output, kStartIndex);
Sneha Patil2da23d72025-02-25 10:54:18 +0000966 EXPECT_NEAR(outputDb, mInputDb + postGainDb, kLimiterTestToleranceDb)
Sneha Patilcbf86a42024-11-26 10:41:54 +0000967 << "PostGain: " << postGainDb << ", OutputDb: " << outputDb;
968 }
969}
970
Sneha Patilabc94642024-11-13 08:41:05 +0000971TEST_P(DynamicsProcessingLimiterConfigDataTest, LimiterEnableDisable) {
972 std::vector<bool> limiterEnableValues = {false, true};
973 std::vector<float> output(mInput.size());
974 for (bool isEnabled : limiterEnableValues) {
Sneha Patilcbf86a42024-11-26 10:41:54 +0000975 cleanUpLimiterConfig();
Sneha Patilabc94642024-11-13 08:41:05 +0000976 for (int i = 0; i < mChannelCount; i++) {
977 // Set non-default values
978 fillLimiterConfig(mLimiterConfigList, i, isEnabled, kDefaultLinkerGroup,
979 5 /*attack time*/, 5 /*release time*/, 10 /*ratio*/,
980 -10 /*threshold*/, 5 /*postgain*/);
981 }
Sneha Patilc3252762024-11-21 10:51:46 +0000982 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
Sneha Patilabc94642024-11-13 08:41:05 +0000983 if (!isAllParamsValid()) {
984 continue;
985 }
986 if (isEnabled) {
987 EXPECT_NE(mInputDb, calculateDb(output, kStartIndex));
988 } else {
Sneha Patil2da23d72025-02-25 10:54:18 +0000989 EXPECT_NEAR(mInputDb, calculateDb(output, kStartIndex), kLimiterTestToleranceDb);
Sneha Patilabc94642024-11-13 08:41:05 +0000990 }
991 }
992}
993
994INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingLimiterConfigDataTest,
995 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
996 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
997 [](const auto& info) {
998 auto descriptor = info.param;
999 std::string name = getPrefix(descriptor.second);
1000 std::replace_if(
1001 name.begin(), name.end(),
1002 [](const char c) { return !std::isalnum(c); }, '_');
1003 return name;
1004 });
Sneha Patild341d6f2024-11-28 06:27:19 +00001005GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingLimiterConfigDataTest);
Sneha Patilabc94642024-11-13 08:41:05 +00001006
Sneha Patile5ca2472025-03-11 12:55:39 +00001007class DynamicsProcessingLimiterLinkerDataTest : public DynamicsProcessingLimiterConfigDataTest {
1008 public:
1009 DynamicsProcessingLimiterLinkerDataTest()
1010 : DynamicsProcessingLimiterConfigDataTest(GetParam(), AudioChannelLayout::LAYOUT_STEREO) {}
1011
1012 void calculateExpectedOutputDb(std::vector<float>& expectedOutputDb) {
1013 std::vector<float> inputDbValues = calculateStereoDb(mInput, kStartIndex);
1014 ASSERT_EQ(inputDbValues.size(), kRatioThresholdPairValues.size());
1015 EXPECT_NEAR(inputDbValues[0], inputDbValues[1], kToleranceDb);
1016 for (size_t i = 0; i < kRatioThresholdPairValues.size(); i++) {
1017 const auto& [ratio, threshold] = kRatioThresholdPairValues[i];
1018 expectedOutputDb.push_back((inputDbValues[i] - threshold) / ratio + threshold);
1019 }
1020 }
1021
1022 std::vector<float> calculateStereoDb(const std::vector<float>& input,
1023 size_t startSamplePos = 0) {
1024 std::vector<float> leftChannel;
1025 std::vector<float> rightChannel;
1026 for (size_t i = 0; i < input.size(); i += 2) {
1027 leftChannel.push_back(input[i]);
1028 if (i + 1 < input.size()) {
1029 rightChannel.push_back(input[i + 1]);
1030 }
1031 }
1032 return {calculateDb(leftChannel, startSamplePos),
1033 calculateDb(rightChannel, startSamplePos)};
1034 }
1035
1036 void setLinkGroupAndProcess(std::vector<float>& output, bool hasSameLinkGroup) {
1037 for (int i = 0; i < mChannelCount; i++) {
1038 const auto& [ratio, threshold] = kRatioThresholdPairValues[i];
1039 ASSERT_NE(ratio, 0);
1040 int linkGroup = hasSameLinkGroup ? kDefaultLinkerGroup : i;
1041 fillLimiterConfig(mLimiterConfigList, i, true, linkGroup, kDefaultAttackTime,
1042 kDefaultReleaseTime, ratio, threshold, kDefaultPostGain);
1043 }
1044
1045 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
1046
1047 if (!isAllParamsValid()) {
1048 GTEST_SKIP() << "Invalid parameters. Skipping the test\n";
1049 }
1050 }
1051
1052 static constexpr float kMinDifferenceDb = 5;
1053 const std::vector<std::pair<float, float>> kRatioThresholdPairValues = {{2, -10}, {5, -20}};
1054};
1055
1056TEST_P(DynamicsProcessingLimiterLinkerDataTest, SameLinkGroupDifferentConfigs) {
1057 std::vector<float> output(mInput.size());
1058
1059 ASSERT_NO_FATAL_FAILURE(setLinkGroupAndProcess(output, true));
1060
1061 std::vector<float> outputDbValues = calculateStereoDb(output, kStartIndex);
1062
1063 std::vector<float> expectedOutputDbValues;
1064 ASSERT_NO_FATAL_FAILURE(calculateExpectedOutputDb(expectedOutputDbValues));
1065
1066 // Verify that the actual output dB is same as the calculated maximum attenuation.
1067 float expectedOutputDb = std::min(expectedOutputDbValues[0], expectedOutputDbValues[1]);
1068 EXPECT_NEAR(outputDbValues[0], expectedOutputDb, kToleranceDb);
1069 EXPECT_NEAR(outputDbValues[1], expectedOutputDb, kToleranceDb);
1070}
1071
1072TEST_P(DynamicsProcessingLimiterLinkerDataTest, DifferentLinkGroupDifferentConfigs) {
1073 std::vector<float> output(mInput.size());
1074
1075 ASSERT_NO_FATAL_FAILURE(setLinkGroupAndProcess(output, false));
1076
1077 std::vector<float> outputDbValues = calculateStereoDb(output, kStartIndex);
1078
1079 std::vector<float> expectedOutputDbValues;
1080 ASSERT_NO_FATAL_FAILURE(calculateExpectedOutputDb(expectedOutputDbValues));
1081
1082 // Verify that both channels have different compression levels
1083 EXPECT_GT(abs(expectedOutputDbValues[0] - expectedOutputDbValues[1]), kMinDifferenceDb)
1084 << "Left channel level: " << expectedOutputDbValues[0]
1085 << " Right channel level: " << expectedOutputDbValues[1];
1086
1087 // Verify that the actual output and the calculated dB values are same
1088 EXPECT_NEAR(outputDbValues[0], expectedOutputDbValues[0], kToleranceDb);
1089 EXPECT_NEAR(outputDbValues[1], expectedOutputDbValues[1], kToleranceDb);
1090}
1091
1092INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingLimiterLinkerDataTest,
1093 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1094 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
1095 [](const auto& info) {
1096 auto descriptor = info.param;
1097 std::string name = getPrefix(descriptor.second);
1098 std::replace_if(
1099 name.begin(), name.end(),
1100 [](const char c) { return !std::isalnum(c); }, '_');
1101 return name;
1102 });
1103GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingLimiterLinkerDataTest);
1104
Ram Mohane4064ce2022-12-20 18:05:14 +05301105/**
1106 * Test DynamicsProcessing ChannelConfig
1107 */
1108enum ChannelConfigTestParamName {
1109 BAND_CHANNEL_TEST_INSTANCE_NAME,
Shunkai Yaof137ba42024-04-11 17:11:03 +00001110 BAND_CHANNEL_TEST_CHANNEL_CONFIG
Ram Mohane4064ce2022-12-20 18:05:14 +05301111};
1112using ChannelConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
Shunkai Yaof137ba42024-04-11 17:11:03 +00001113 std::vector<DynamicsProcessing::ChannelConfig>>;
Ram Mohane4064ce2022-12-20 18:05:14 +05301114
1115class DynamicsProcessingTestChannelConfig
1116 : public ::testing::TestWithParam<ChannelConfigTestParams>,
1117 public DynamicsProcessingTestHelper {
1118 public:
1119 DynamicsProcessingTestChannelConfig()
1120 : DynamicsProcessingTestHelper(std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(GetParam())),
Shunkai Yaof137ba42024-04-11 17:11:03 +00001121 mCfg(std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(GetParam())) {}
Ram Mohane4064ce2022-12-20 18:05:14 +05301122
Aayush Soni63d6e2a2025-03-04 13:37:28 +00001123 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
Ram Mohane4064ce2022-12-20 18:05:14 +05301124
1125 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1126
1127 std::vector<DynamicsProcessing::ChannelConfig> mCfg;
Ram Mohane4064ce2022-12-20 18:05:14 +05301128};
1129
1130TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
Sneha Patil3587ae52025-01-06 05:59:08 +00001131 addEngineConfig(mEngineConfigPreset);
1132 addPreEqChannelConfig(mCfg);
Sneha Patilabc94642024-11-13 08:41:05 +00001133 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +05301134}
1135
1136TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
Sneha Patil3587ae52025-01-06 05:59:08 +00001137 addEngineConfig(mEngineConfigPreset);
1138 addPostEqChannelConfig(mCfg);
Sneha Patilabc94642024-11-13 08:41:05 +00001139 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +05301140}
1141
1142TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
Sneha Patil3587ae52025-01-06 05:59:08 +00001143 addEngineConfig(mEngineConfigPreset);
1144 addMbcChannelConfig(mCfg);
Sneha Patilabc94642024-11-13 08:41:05 +00001145 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +05301146}
1147
1148INSTANTIATE_TEST_SUITE_P(
1149 DynamicsProcessingTest, DynamicsProcessingTestChannelConfig,
1150 ::testing::Combine(
1151 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
Shunkai Yaof8be1ac2023-03-06 18:41:27 +00001152 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
Ram Mohane4064ce2022-12-20 18:05:14 +05301153 testing::ValuesIn(
Shunkai Yaof137ba42024-04-11 17:11:03 +00001154 DynamicsProcessingTestHelper::kChannelConfigTestSet)), // channel config
Ram Mohane4064ce2022-12-20 18:05:14 +05301155 [](const auto& info) {
1156 auto descriptor = std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(info.param).second;
Ram Mohane4064ce2022-12-20 18:05:14 +05301157 std::string channelConfig = ::android::internal::ToString(
1158 std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(info.param));
1159
1160 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
1161 descriptor.common.name + "_UUID_" +
Shunkai Yaof137ba42024-04-11 17:11:03 +00001162 toString(descriptor.common.id.uuid) + "_" + channelConfig;
Ram Mohane4064ce2022-12-20 18:05:14 +05301163 std::replace_if(
1164 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
1165 return name;
1166 });
1167GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestChannelConfig);
1168
1169/**
1170 * Test DynamicsProcessing EqBandConfig
1171 */
1172enum EqBandConfigTestParamName {
1173 EQ_BAND_INSTANCE_NAME,
1174 EQ_BAND_CHANNEL,
Ram Mohane4064ce2022-12-20 18:05:14 +05301175 EQ_BAND_CUT_OFF_FREQ,
Shunkai Yaof137ba42024-04-11 17:11:03 +00001176 EQ_BAND_GAIN
Ram Mohane4064ce2022-12-20 18:05:14 +05301177};
1178using EqBandConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
Sneha Patilabc94642024-11-13 08:41:05 +00001179 std::vector<std::pair<int, float>>, float>;
Ram Mohane4064ce2022-12-20 18:05:14 +05301180
1181void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
1182 const EqBandConfigTestParams& params) {
1183 const std::vector<std::pair<int, float>> cutOffFreqs = std::get<EQ_BAND_CUT_OFF_FREQ>(params);
1184 int bandCount = cutOffFreqs.size();
Ram Mohane4064ce2022-12-20 18:05:14 +05301185 for (int i = 0; i < bandCount; i++) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001186 cfgs.push_back(creatEqBandConfig(std::get<EQ_BAND_CHANNEL>(params), cutOffFreqs[i].first,
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001187 cutOffFreqs[i].second, std::get<EQ_BAND_GAIN>(params),
1188 true));
Ram Mohane4064ce2022-12-20 18:05:14 +05301189 }
1190}
1191
1192class DynamicsProcessingTestEqBandConfig : public ::testing::TestWithParam<EqBandConfigTestParams>,
1193 public DynamicsProcessingTestHelper {
1194 public:
1195 DynamicsProcessingTestEqBandConfig()
Shunkai Yaof137ba42024-04-11 17:11:03 +00001196 : DynamicsProcessingTestHelper(std::get<EQ_BAND_INSTANCE_NAME>(GetParam())) {
Ram Mohane4064ce2022-12-20 18:05:14 +05301197 fillEqBandConfig(mCfgs, GetParam());
1198 }
1199
Aayush Soni63d6e2a2025-03-04 13:37:28 +00001200 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
Ram Mohane4064ce2022-12-20 18:05:14 +05301201
1202 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1203
1204 std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
Ram Mohane4064ce2022-12-20 18:05:14 +05301205};
1206
1207TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
Ram Mohane4064ce2022-12-20 18:05:14 +05301208 mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
Sneha Patil3587ae52025-01-06 05:59:08 +00001209 addEngineConfig(mEngineConfigPreset);
Ram Mohanafdf90b2023-03-23 08:48:25 +05301210 std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
1211 for (int i = 0; i < mChannelCount; i++) {
1212 cfgs[i].channel = i;
1213 cfgs[i].enable = true;
1214 }
Sneha Patil3587ae52025-01-06 05:59:08 +00001215 addPreEqChannelConfig(cfgs);
1216 addPreEqBandConfigs(mCfgs);
Sneha Patilabc94642024-11-13 08:41:05 +00001217 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +05301218}
1219
1220TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
Ram Mohane4064ce2022-12-20 18:05:14 +05301221 mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
Sneha Patil3587ae52025-01-06 05:59:08 +00001222 addEngineConfig(mEngineConfigPreset);
Ram Mohanafdf90b2023-03-23 08:48:25 +05301223 std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
1224 for (int i = 0; i < mChannelCount; i++) {
1225 cfgs[i].channel = i;
1226 cfgs[i].enable = true;
1227 }
Sneha Patil3587ae52025-01-06 05:59:08 +00001228 addPostEqChannelConfig(cfgs);
1229 addPostEqBandConfigs(mCfgs);
Sneha Patilabc94642024-11-13 08:41:05 +00001230 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +05301231}
1232
1233std::vector<std::vector<std::pair<int, float>>> kBands{
1234 {
1235 {0, 600},
1236 {1, 2000},
1237 {2, 6000},
1238 {3, 10000},
1239 {4, 16000},
Sneha Patil0ecc1782025-02-17 11:21:32 +00001240 {5, 20000},
1241 {6, 26000},
1242 {7, 30000},
1243 {8, 36000},
1244 {9, 40000},
1245 }, // 10 bands
Ram Mohane4064ce2022-12-20 18:05:14 +05301246 {
1247 {0, 800},
1248 {3, 15000},
1249 {2, 6000},
1250 {1, 2000},
1251 }, // 4 bands, unsorted
1252 {
1253 {0, 650},
1254 {1, 2000},
1255 {2, 6000},
1256 {3, 10000},
1257 {3, 16000},
1258 }, // 5 bands, missing band
1259 {
1260 {0, 900},
1261 {1, 8000},
1262 {2, 4000},
1263 {3, 12000},
1264 }, // 4 bands, cutoff freq not increasing
1265 {
1266 {0, 450},
1267 {1, 2000},
1268 {7, 6000},
1269 {3, 10000},
1270 {4, 16000},
1271 }, // bad band index
1272 {
1273 {0, 1},
1274 {1, 8000},
1275 }, // too low cutoff freq
1276 {
1277 {0, 1200},
1278 {1, 80000},
1279 }, // too high cutoff freq
1280};
1281
1282INSTANTIATE_TEST_SUITE_P(
1283 DynamicsProcessingTest, DynamicsProcessingTestEqBandConfig,
Ram Mohanafdf90b2023-03-23 08:48:25 +05301284 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1285 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
Sneha Patilabc94642024-11-13 08:41:05 +00001286 testing::Values(-1, 0, 10), // channel index
1287 testing::ValuesIn(kBands), // band index, cut off frequencies
Shunkai Yaof137ba42024-04-11 17:11:03 +00001288 testing::Values(-3.14f, 3.14f) // gain
1289 ),
Ram Mohane4064ce2022-12-20 18:05:14 +05301290 [](const auto& info) {
1291 auto descriptor = std::get<EQ_BAND_INSTANCE_NAME>(info.param).second;
1292 std::vector<DynamicsProcessing::EqBandConfig> cfgs;
1293 fillEqBandConfig(cfgs, info.param);
Ram Mohane4064ce2022-12-20 18:05:14 +05301294 std::string bands = ::android::internal::ToString(cfgs);
Ram Mohane4064ce2022-12-20 18:05:14 +05301295 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
1296 descriptor.common.name + "_UUID_" +
Shunkai Yaof137ba42024-04-11 17:11:03 +00001297 toString(descriptor.common.id.uuid) + "_bands_" + bands;
Ram Mohane4064ce2022-12-20 18:05:14 +05301298 std::replace_if(
1299 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
1300 return name;
1301 });
1302GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEqBandConfig);
1303
Sneha Patil2da23d72025-02-25 10:54:18 +00001304class DynamicsProcessingEqBandConfigDataTest
1305 : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
1306 public DynamicsProcessingTestHelper {
1307 public:
1308 DynamicsProcessingEqBandConfigDataTest()
1309 : DynamicsProcessingTestHelper(GetParam(), AudioChannelLayout::LAYOUT_MONO) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001310 mBinOffsets.resize(mMultitoneTestFrequencies.size());
1311 }
1312
1313 void SetUp() override {
1314 ASSERT_NO_FATAL_FAILURE(
1315 setUpDataTest(mMultitoneTestFrequencies, kSineMultitoneFullScaleDb));
1316 }
1317
1318 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1319
1320 void addEqParam(bool isPreEq) {
1321 createChannelConfig();
1322 auto stage = isPreEq ? mEngineConfigPreset.preEqStage : mEngineConfigPreset.postEqStage;
1323 stage.bandCount = mCfgs.size();
1324 addEngineConfig(mEngineConfigPreset);
1325 isPreEq ? addPreEqChannelConfig(mChannelConfig) : addPostEqChannelConfig(mChannelConfig);
1326 isPreEq ? addPreEqBandConfigs(mCfgs) : addPostEqBandConfigs(mCfgs);
1327 }
1328
1329 void setEqParamAndProcess(std::vector<float>& output, bool isPreEq) {
1330 addEqParam(isPreEq);
1331 ASSERT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
1332 }
1333
1334 void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs, int channelIndex,
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001335 int bandIndex, int cutOffFreqHz, float gainDb, bool enable) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001336 cfgs.push_back(creatEqBandConfig(channelIndex, bandIndex, static_cast<float>(cutOffFreqHz),
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001337 gainDb, enable));
Sneha Patil2da23d72025-02-25 10:54:18 +00001338 }
1339
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001340 void validateOutput(const std::vector<float>& output, float gainDb, size_t bandIndex,
1341 bool enable) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001342 std::vector<float> outputMag(mBinOffsets.size());
1343 EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(output, outputMag));
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001344 if (gainDb == 0 || !enable) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001345 EXPECT_NO_FATAL_FAILURE(checkInputAndOutputEquality(outputMag));
1346 } else if (gainDb > 0) {
1347 // For positive gain, current band's magnitude is greater than the other band's
1348 // magnitude
1349 EXPECT_GT(outputMag[bandIndex], outputMag[bandIndex ^ 1]);
1350 } else {
1351 // For negative gain, current band's magnitude is less than the other band's magnitude
1352 EXPECT_LT(outputMag[bandIndex], outputMag[bandIndex ^ 1]);
1353 }
1354 }
1355
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001356 void analyseMultiBandOutput(float gainDb, bool isPreEq, bool enable = true) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001357 std::vector<float> output(mInput.size());
1358 roundToFreqCenteredToFftBin(mMultitoneTestFrequencies, mBinOffsets, kBinWidth);
1359 // Set Equalizer values for two bands
1360 for (size_t i = 0; i < kCutoffFreqHz.size(); i++) {
1361 for (int channelIndex = 0; channelIndex < mChannelCount; channelIndex++) {
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001362 fillEqBandConfig(mCfgs, channelIndex, i, kCutoffFreqHz[i], gainDb, enable);
1363 fillEqBandConfig(mCfgs, channelIndex, i ^ 1, kCutoffFreqHz[i ^ 1], 0, enable);
Sneha Patil2da23d72025-02-25 10:54:18 +00001364 }
1365 ASSERT_NO_FATAL_FAILURE(setEqParamAndProcess(output, isPreEq));
1366
1367 if (isAllParamsValid()) {
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001368 ASSERT_NO_FATAL_FAILURE(validateOutput(output, gainDb, i, enable));
Sneha Patil2da23d72025-02-25 10:54:18 +00001369 }
1370 cleanUpEqConfig();
1371 }
1372 }
1373
1374 void cleanUpEqConfig() {
1375 CleanUp();
1376 mCfgs.clear();
1377 mChannelConfig.clear();
1378 }
1379
1380 const std::vector<float> kTestGainDbValues = {-200, -100, 0, 100, 200};
1381 std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
1382};
1383
1384TEST_P(DynamicsProcessingEqBandConfigDataTest, IncreasingPreEqGain) {
1385 for (float gainDb : kTestGainDbValues) {
1386 ASSERT_NO_FATAL_FAILURE(generateSineWave(mMultitoneTestFrequencies, mInput,
1387 dBToAmplitude(gainDb), kSamplingFrequency,
1388 mChannelLayout));
1389 cleanUpEqConfig();
1390 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(gainDb, true /*pre-equalizer*/));
1391 }
1392}
1393
1394TEST_P(DynamicsProcessingEqBandConfigDataTest, IncreasingPostEqGain) {
1395 for (float gainDb : kTestGainDbValues) {
1396 ASSERT_NO_FATAL_FAILURE(generateSineWave(mMultitoneTestFrequencies, mInput,
1397 dBToAmplitude(gainDb), kSamplingFrequency,
1398 mChannelLayout));
1399 cleanUpEqConfig();
1400 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(gainDb, false /*post-equalizer*/));
1401 }
1402}
1403
Sneha Patil4d8a91c2025-03-03 08:03:43 +00001404TEST_P(DynamicsProcessingEqBandConfigDataTest, PreEqEnableDisable) {
1405 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(10 /*gain dB*/, true /*pre-equalizer*/,
1406 false /*disable equalizer*/));
1407}
1408
1409TEST_P(DynamicsProcessingEqBandConfigDataTest, PostEqEnableDisable) {
1410 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(10 /*gain dB*/, false /*post-equalizer*/,
1411 false /*disable equalizer*/));
1412}
1413
Sneha Patil2da23d72025-02-25 10:54:18 +00001414INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingEqBandConfigDataTest,
1415 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1416 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
1417 [](const auto& info) {
1418 auto descriptor = info.param;
1419 std::string name = getPrefix(descriptor.second);
1420 std::replace_if(
1421 name.begin(), name.end(),
1422 [](const char c) { return !std::isalnum(c); }, '_');
1423 return name;
1424 });
1425GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingEqBandConfigDataTest);
1426
Ram Mohane4064ce2022-12-20 18:05:14 +05301427/**
1428 * Test DynamicsProcessing MbcBandConfig
1429 */
1430
1431enum MbcBandConfigParamName {
1432 MBC_BAND_INSTANCE_NAME,
1433 MBC_BAND_CHANNEL,
Ram Mohane4064ce2022-12-20 18:05:14 +05301434 MBC_BAND_CUTOFF_FREQ,
Ram Mohane4064ce2022-12-20 18:05:14 +05301435 MBC_BAND_ADDITIONAL
1436};
1437enum MbcBandConfigAdditional {
1438 MBC_ADD_ATTACK_TIME,
1439 MBC_ADD_RELEASE_TIME,
1440 MBC_ADD_RATIO,
1441 MBC_ADD_THRESHOLD,
1442 MBC_ADD_KNEE_WIDTH,
1443 MBC_ADD_NOISE_GATE_THRESHOLD,
1444 MBC_ADD_EXPENDER_RATIO,
1445 MBC_ADD_PRE_GAIN,
1446 MBC_ADD_POST_GAIN,
1447 MBC_ADD_MAX_NUM
1448};
1449using TestParamsMbcBandConfigAdditional = std::array<float, MBC_ADD_MAX_NUM>;
1450
Ram Mohanafdf90b2023-03-23 08:48:25 +05301451// attackTime, releaseTime, ratio, thresh, kneeWidth, noise, expander, preGain, postGain
Ram Mohane4064ce2022-12-20 18:05:14 +05301452static constexpr std::array<TestParamsMbcBandConfigAdditional, 4> kMbcBandConfigAdditionalParam = {
1453 {{-3, -10, -2, -2, -5, -90, -2.5, -2, -2},
1454 {0, 0, 0, 0, 0, 0, 0, 0, 0},
1455 {-3, 10, -2, 2, -5, 90, -2.5, 2, -2},
Ram Mohanafdf90b2023-03-23 08:48:25 +05301456 {3, 10, 2, -2, -5, 90, 2.5, 2, 2}}};
Ram Mohane4064ce2022-12-20 18:05:14 +05301457
1458using TestParamsMbcBandConfig =
Sneha Patilabc94642024-11-13 08:41:05 +00001459 std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
Shunkai Yaof137ba42024-04-11 17:11:03 +00001460 std::vector<std::pair<int, float>>, TestParamsMbcBandConfigAdditional>;
Ram Mohane4064ce2022-12-20 18:05:14 +05301461
1462void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
1463 const TestParamsMbcBandConfig& params) {
Sneha Patilc3252762024-11-21 10:51:46 +00001464 const auto& cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
1465 const auto& additional = std::get<MBC_BAND_ADDITIONAL>(params);
1466
1467 cfgs.resize(cutOffFreqs.size());
1468
1469 for (size_t i = 0; i < cutOffFreqs.size(); ++i) {
1470 cfgs[i] = createMbcBandConfig(std::get<MBC_BAND_CHANNEL>(params),
1471 cutOffFreqs[i].first, // band channel
1472 cutOffFreqs[i].second, // band cutoff frequency
1473 additional[MBC_ADD_ATTACK_TIME],
1474 additional[MBC_ADD_RELEASE_TIME], additional[MBC_ADD_RATIO],
1475 additional[MBC_ADD_THRESHOLD], additional[MBC_ADD_KNEE_WIDTH],
1476 additional[MBC_ADD_NOISE_GATE_THRESHOLD],
1477 additional[MBC_ADD_EXPENDER_RATIO],
1478 additional[MBC_ADD_PRE_GAIN], additional[MBC_ADD_POST_GAIN]);
Ram Mohane4064ce2022-12-20 18:05:14 +05301479 }
1480}
1481
1482class DynamicsProcessingTestMbcBandConfig
1483 : public ::testing::TestWithParam<TestParamsMbcBandConfig>,
1484 public DynamicsProcessingTestHelper {
1485 public:
1486 DynamicsProcessingTestMbcBandConfig()
Shunkai Yaof137ba42024-04-11 17:11:03 +00001487 : DynamicsProcessingTestHelper(std::get<MBC_BAND_INSTANCE_NAME>(GetParam())) {
Ram Mohane4064ce2022-12-20 18:05:14 +05301488 fillMbcBandConfig(mCfgs, GetParam());
1489 }
1490
Aayush Soni63d6e2a2025-03-04 13:37:28 +00001491 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
Ram Mohane4064ce2022-12-20 18:05:14 +05301492
1493 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1494
1495 std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
Ram Mohane4064ce2022-12-20 18:05:14 +05301496};
1497
1498TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
Ram Mohane4064ce2022-12-20 18:05:14 +05301499 mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
Sneha Patil3587ae52025-01-06 05:59:08 +00001500 addEngineConfig(mEngineConfigPreset);
Ram Mohanafdf90b2023-03-23 08:48:25 +05301501 std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
1502 for (int i = 0; i < mChannelCount; i++) {
1503 cfgs[i].channel = i;
1504 cfgs[i].enable = true;
1505 }
Sneha Patil3587ae52025-01-06 05:59:08 +00001506 addMbcChannelConfig(cfgs);
1507 addMbcBandConfigs(mCfgs);
Sneha Patilabc94642024-11-13 08:41:05 +00001508 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
Ram Mohane4064ce2022-12-20 18:05:14 +05301509}
1510
1511INSTANTIATE_TEST_SUITE_P(
1512 DynamicsProcessingTest, DynamicsProcessingTestMbcBandConfig,
Ram Mohanafdf90b2023-03-23 08:48:25 +05301513 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1514 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
Sneha Patilabc94642024-11-13 08:41:05 +00001515 testing::Values(-1, 0, 10), // channel index
1516 testing::ValuesIn(kBands), // band index, cut off frequencies
Ram Mohanafdf90b2023-03-23 08:48:25 +05301517 testing::ValuesIn(kMbcBandConfigAdditionalParam)), // Additional
Ram Mohane4064ce2022-12-20 18:05:14 +05301518 [](const auto& info) {
1519 auto descriptor = std::get<MBC_BAND_INSTANCE_NAME>(info.param).second;
1520 std::vector<DynamicsProcessing::MbcBandConfig> cfgs;
1521 fillMbcBandConfig(cfgs, info.param);
Ram Mohane4064ce2022-12-20 18:05:14 +05301522 std::string mbcBands = ::android::internal::ToString(cfgs);
Ram Mohane4064ce2022-12-20 18:05:14 +05301523 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
1524 descriptor.common.name + "_UUID_" +
Shunkai Yaof137ba42024-04-11 17:11:03 +00001525 toString(descriptor.common.id.uuid) + "_bands_" + mbcBands;
Ram Mohane4064ce2022-12-20 18:05:14 +05301526 std::replace_if(
1527 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
1528 return name;
1529 });
1530GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestMbcBandConfig);
1531
Sneha Patilc3252762024-11-21 10:51:46 +00001532class DynamicsProcessingMbcBandConfigDataTest
1533 : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
1534 public DynamicsProcessingTestHelper {
1535 public:
1536 DynamicsProcessingMbcBandConfigDataTest()
1537 : DynamicsProcessingTestHelper(GetParam(), AudioChannelLayout::LAYOUT_MONO) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001538 mBinOffsets.resize(mMultitoneTestFrequencies.size());
Sneha Patilc3252762024-11-21 10:51:46 +00001539 }
1540
1541 void SetUp() override {
Sneha Patil2da23d72025-02-25 10:54:18 +00001542 ASSERT_NO_FATAL_FAILURE(
1543 setUpDataTest(mMultitoneTestFrequencies, kSineMultitoneFullScaleDb));
Sneha Patilc3252762024-11-21 10:51:46 +00001544 }
1545
1546 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1547
1548 void setMbcParamsAndProcess(std::vector<float>& output) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001549 createChannelConfig();
Sneha Patilc3252762024-11-21 10:51:46 +00001550 mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
1551 addEngineConfig(mEngineConfigPreset);
1552 addMbcChannelConfig(mChannelConfig);
1553 addMbcBandConfigs(mCfgs);
Sneha Patil903c6202025-01-30 06:37:10 +00001554 ASSERT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
Sneha Patilc3252762024-11-21 10:51:46 +00001555 }
1556
1557 void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs, int channelIndex,
1558 float threshold, float ratio, float noiseGate, float expanderRatio,
Sneha Patil7ba121b2025-01-22 09:19:39 +00001559 int bandIndex, int cutoffFreqHz, float preGain, float postGain) {
1560 cfgs.push_back(createMbcBandConfig(channelIndex, bandIndex,
1561 static_cast<float>(cutoffFreqHz), kDefaultAttackTime,
1562 kDefaultReleaseTime, ratio, threshold, kDefaultKneeWidth,
1563 noiseGate, expanderRatio, preGain, postGain));
Sneha Patilc3252762024-11-21 10:51:46 +00001564 }
1565
Sneha Patilc3252762024-11-21 10:51:46 +00001566 void validateOutput(const std::vector<float>& output, float threshold, float ratio,
1567 size_t bandIndex) {
Sneha Patilc3252762024-11-21 10:51:46 +00001568 std::vector<float> outputMag(mBinOffsets.size());
1569 EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(output, outputMag));
Sneha Patil7ba121b2025-01-22 09:19:39 +00001570 if (threshold >= mInputDb || ratio == 1) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001571 EXPECT_NO_FATAL_FAILURE(checkInputAndOutputEquality(outputMag));
Sneha Patilc3252762024-11-21 10:51:46 +00001572 } else {
1573 // Current band's magnitude is less than the other band's magnitude
1574 EXPECT_LT(outputMag[bandIndex], outputMag[bandIndex ^ 1]);
1575 }
1576 }
1577
1578 void analyseMultiBandOutput(float threshold, float ratio) {
1579 std::vector<float> output(mInput.size());
Sneha Patil2da23d72025-02-25 10:54:18 +00001580 roundToFreqCenteredToFftBin(mMultitoneTestFrequencies, mBinOffsets, kBinWidth);
Sneha Patilc3252762024-11-21 10:51:46 +00001581 // Set MBC values for two bands
Sneha Patil2da23d72025-02-25 10:54:18 +00001582 for (size_t i = 0; i < kCutoffFreqHz.size(); i++) {
Sneha Patilc3252762024-11-21 10:51:46 +00001583 for (int channelIndex = 0; channelIndex < mChannelCount; channelIndex++) {
1584 fillMbcBandConfig(mCfgs, channelIndex, threshold, ratio, kDefaultNoiseGateDb,
Sneha Patil2da23d72025-02-25 10:54:18 +00001585 kDefaultExpanderRatio, i, kCutoffFreqHz[i], kDefaultPreGainDb,
Sneha Patil7ba121b2025-01-22 09:19:39 +00001586 kDefaultPostGainDb);
Sneha Patilc3252762024-11-21 10:51:46 +00001587 fillMbcBandConfig(mCfgs, channelIndex, kDefaultThresholdDb, kDefaultRatio,
1588 kDefaultNoiseGateDb, kDefaultExpanderRatio, i ^ 1,
Sneha Patil2da23d72025-02-25 10:54:18 +00001589 kCutoffFreqHz[i ^ 1], kDefaultPreGainDb, kDefaultPostGainDb);
Sneha Patilc3252762024-11-21 10:51:46 +00001590 }
1591 ASSERT_NO_FATAL_FAILURE(setMbcParamsAndProcess(output));
1592
1593 if (isAllParamsValid()) {
1594 ASSERT_NO_FATAL_FAILURE(validateOutput(output, threshold, ratio, i));
1595 }
1596 cleanUpMbcConfig();
1597 }
1598 }
1599
1600 void cleanUpMbcConfig() {
1601 CleanUp();
1602 mCfgs.clear();
1603 mChannelConfig.clear();
1604 }
1605
Sneha Patilc3252762024-11-21 10:51:46 +00001606 static constexpr float kDefaultPostGainDb = 0;
1607 static constexpr float kDefaultPreGainDb = 0;
1608 static constexpr float kDefaultAttackTime = 0;
1609 static constexpr float kDefaultReleaseTime = 0;
1610 static constexpr float kDefaultKneeWidth = 0;
1611 static constexpr float kDefaultThresholdDb = 0;
1612 static constexpr float kDefaultNoiseGateDb = -10;
1613 static constexpr float kDefaultExpanderRatio = 1;
1614 static constexpr float kDefaultRatio = 1;
Sneha Patilc3252762024-11-21 10:51:46 +00001615 std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
Sneha Patilc3252762024-11-21 10:51:46 +00001616};
1617
1618TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingThreshold) {
1619 float ratio = 20;
1620 std::vector<float> thresholdValues = {-200, -100, 0, 100, 200};
1621
1622 for (float threshold : thresholdValues) {
1623 cleanUpMbcConfig();
1624 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(threshold, ratio));
1625 }
1626}
1627
1628TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingRatio) {
1629 float threshold = -20;
1630 std::vector<float> ratioValues = {1, 10, 20, 30, 40, 50};
1631
1632 for (float ratio : ratioValues) {
1633 cleanUpMbcConfig();
1634 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(threshold, ratio));
1635 }
1636}
1637
Sneha Patil7ba121b2025-01-22 09:19:39 +00001638TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingPostGain) {
1639 std::vector<float> postGainDbValues = {-55, -30, 0, 30, 55};
1640 std::vector<float> output(mInput.size());
1641 for (float postGainDb : postGainDbValues) {
Sneha Patil2da23d72025-02-25 10:54:18 +00001642 ASSERT_NO_FATAL_FAILURE(generateSineWave(mMultitoneTestFrequencies, mInput,
Sneha Patil903c6202025-01-30 06:37:10 +00001643 dBToAmplitude(postGainDb), kSamplingFrequency,
1644 mChannelLayout));
Sneha Patil7ba121b2025-01-22 09:19:39 +00001645 mInputDb = calculateDb(mInput);
Sneha Patil2da23d72025-02-25 10:54:18 +00001646 EXPECT_NEAR(mInputDb, kSineMultitoneFullScaleDb - postGainDb, kToleranceDb);
Sneha Patil7ba121b2025-01-22 09:19:39 +00001647 cleanUpMbcConfig();
1648 for (int i = 0; i < mChannelCount; i++) {
1649 fillMbcBandConfig(mCfgs, i, kDefaultThresholdDb, kDefaultRatio, kDefaultNoiseGateDb,
1650 kDefaultExpanderRatio, 0 /*band index*/, 2000 /*cutoffFrequency*/,
1651 kDefaultPreGainDb, postGainDb);
1652 }
1653 EXPECT_NO_FATAL_FAILURE(setMbcParamsAndProcess(output));
1654 if (!isAllParamsValid()) {
1655 continue;
1656 }
1657 float outputDb = calculateDb(output, kStartIndex);
1658 EXPECT_NEAR(outputDb, mInputDb + postGainDb, kToleranceDb)
1659 << "PostGain: " << postGainDb << ", OutputDb: " << outputDb;
1660 }
1661}
1662
Sneha Patilba665282025-02-06 08:37:48 +00001663TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingPreGain) {
1664 /*
1665 Depending on the pregain values, samples undergo either compression or expansion process.
1666 At -6 dB input,
1667 - Expansion is expected at -60 dB,
1668 - Compression at 10, 34 and 60 dB
1669 - No compression or expansion at -34, -10, -1 dB.
1670 */
1671 std::vector<float> preGainDbValues = {-60, -34, -10, -1, 10, 34, 60};
1672 std::vector<float> output(mInput.size());
1673 float thresholdDb = -7;
1674 float noiseGateDb = -40;
1675 std::vector<float> ratioValues = {1, 1.5, 2, 2.5, 3};
1676 for (float ratio : ratioValues) {
1677 for (float preGainDb : preGainDbValues) {
1678 float expectedOutputDb;
1679 float inputWithPreGain = mInputDb + preGainDb;
1680 if (inputWithPreGain > thresholdDb) {
1681 SCOPED_TRACE("Compressor ratio: " + std::to_string(ratio));
1682 expectedOutputDb =
1683 (inputWithPreGain - thresholdDb) / ratio + thresholdDb - preGainDb;
1684 } else if (inputWithPreGain < noiseGateDb) {
1685 SCOPED_TRACE("Expander ratio: " + std::to_string(ratio));
1686 expectedOutputDb =
1687 (inputWithPreGain - noiseGateDb) * ratio + noiseGateDb - preGainDb;
1688 } else {
1689 expectedOutputDb = mInputDb;
1690 }
1691 cleanUpMbcConfig();
1692 for (int i = 0; i < mChannelCount; i++) {
1693 fillMbcBandConfig(mCfgs, i, thresholdDb, ratio /*compressor ratio*/, noiseGateDb,
1694 ratio /*expander ratio*/, 0 /*band index*/,
1695 2000 /*cutoffFrequency*/, preGainDb, kDefaultPostGainDb);
1696 }
1697 EXPECT_NO_FATAL_FAILURE(setMbcParamsAndProcess(output));
1698 if (!isAllParamsValid()) {
1699 continue;
1700 }
1701 float outputDb = calculateDb(output, kStartIndex);
1702 EXPECT_NEAR(outputDb, expectedOutputDb, kToleranceDb)
1703 << "PreGain: " << preGainDb << ", OutputDb: " << outputDb;
1704 }
1705 }
1706}
1707
Sneha Patilc3252762024-11-21 10:51:46 +00001708INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingMbcBandConfigDataTest,
1709 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1710 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
1711 [](const auto& info) {
1712 auto descriptor = info.param;
1713 std::string name = getPrefix(descriptor.second);
1714 std::replace_if(
1715 name.begin(), name.end(),
1716 [](const char c) { return !std::isalnum(c); }, '_');
1717 return name;
1718 });
1719
1720GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingMbcBandConfigDataTest);
1721
Ram Mohane4064ce2022-12-20 18:05:14 +05301722int main(int argc, char** argv) {
1723 ::testing::InitGoogleTest(&argc, argv);
Jaideep Sharma74498412023-09-13 15:25:25 +05301724 ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
Ram Mohane4064ce2022-12-20 18:05:14 +05301725 ABinderProcess_setThreadPoolMaxThreadCount(1);
1726 ABinderProcess_startThreadPool();
1727 return RUN_ALL_TESTS();
1728}