1 /*
2 * Copyright 2021 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
17 #include <audio_effects/effect_presetreverb.h>
18 #include <VectorArithmetic.h>
19
20 #include "EffectTestHelper.h"
21 using namespace android;
22
23 constexpr effect_uuid_t kEffectUuids[] = {
24 // NXP SW insert environmental reverb
25 {0xc7a511a0, 0xa3bb, 0x11df, 0x860e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
26 // NXP SW insert preset reverb
27 {0x172cdf00, 0xa3bc, 0x11df, 0xa72f, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
28 // NXP SW auxiliary environmental reverb
29 {0x4a387fc0, 0x8ab3, 0x11df, 0x8bad, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
30 // NXP SW auxiliary preset reverb
31 {0xf29a1400, 0xa3bb, 0x11df, 0x8ddc, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
32 };
33
34 constexpr size_t kNumEffectUuids = std::size(kEffectUuids);
35
isAuxMode(const effect_uuid_t * uuid)36 static bool isAuxMode(const effect_uuid_t* uuid) {
37 // Update this, if the order of effects in kEffectUuids is updated
38 return (uuid == &kEffectUuids[2] || uuid == &kEffectUuids[3]);
39 }
40
41 constexpr int kPresets[] = {
42 REVERB_PRESET_NONE, REVERB_PRESET_SMALLROOM, REVERB_PRESET_MEDIUMROOM,
43 REVERB_PRESET_LARGEROOM, REVERB_PRESET_MEDIUMHALL, REVERB_PRESET_LARGEHALL,
44 REVERB_PRESET_PLATE,
45 };
46
47 constexpr size_t kNumPresets = std::size(kPresets);
48
49 typedef std::tuple<int, int, int, int, int, int> SingleEffectTestParam;
50 class SingleEffectTest : public ::testing::TestWithParam<SingleEffectTestParam> {
51 public:
SingleEffectTest()52 SingleEffectTest()
53 : mSampleRate(EffectTestHelper::kSampleRates[std::get<1>(GetParam())]),
54 mFrameCount(EffectTestHelper::kFrameCounts[std::get<2>(GetParam())]),
55 mLoopCount(EffectTestHelper::kLoopCounts[std::get<3>(GetParam())]),
56 mTotalFrameCount(mFrameCount * mLoopCount),
57 mUuid(&kEffectUuids[std::get<4>(GetParam())]),
58 mInChMask(isAuxMode(mUuid) ? AUDIO_CHANNEL_OUT_MONO
59 : EffectTestHelper::kChMasks[std::get<0>(GetParam())]),
60 mInChannelCount(audio_channel_count_from_out_mask(mInChMask)),
61 mOutChMask(EffectTestHelper::kChMasks[std::get<0>(GetParam())]),
62 mOutChannelCount(audio_channel_count_from_out_mask(mOutChMask)),
63 mPreset(kPresets[std::get<5>(GetParam())]) {}
64
65 const size_t mSampleRate;
66 const size_t mFrameCount;
67 const size_t mLoopCount;
68 const size_t mTotalFrameCount;
69 const effect_uuid_t* mUuid;
70 const size_t mInChMask;
71 const size_t mInChannelCount;
72 const size_t mOutChMask;
73 const size_t mOutChannelCount;
74 const size_t mPreset;
75 };
76
77 // Tests applying a single effect
TEST_P(SingleEffectTest,SimpleProcess)78 TEST_P(SingleEffectTest, SimpleProcess) {
79 SCOPED_TRACE(testing::Message() << "outChMask: " << mOutChMask << " sampleRate: " << mSampleRate
80 << " frameCount: " << mFrameCount
81 << " loopCount: " << mLoopCount << " preset: " << mPreset);
82
83 EffectTestHelper effect(mUuid, mInChMask, mOutChMask, mSampleRate, mFrameCount, mLoopCount);
84
85 ASSERT_NO_FATAL_FAILURE(effect.createEffect());
86 ASSERT_NO_FATAL_FAILURE(effect.setConfig());
87 ASSERT_NO_FATAL_FAILURE(effect.setParam(REVERB_PARAM_PRESET, mPreset));
88
89 // Initialize input buffer with deterministic pseudo-random values
90 std::vector<float> input(mTotalFrameCount * mInChannelCount);
91 std::vector<float> output(mTotalFrameCount * mOutChannelCount);
92 std::minstd_rand gen(mOutChMask);
93 std::uniform_real_distribution<> dis(-1.0f, 1.0f);
94 for (auto& in : input) {
95 in = dis(gen);
96 }
97 ASSERT_NO_FATAL_FAILURE(effect.process(input.data(), output.data()));
98 ASSERT_NO_FATAL_FAILURE(effect.releaseEffect());
99 }
100
101 INSTANTIATE_TEST_SUITE_P(
102 EffectReverbTestAll, SingleEffectTest,
103 ::testing::Combine(::testing::Range(0, (int)EffectTestHelper::kNumChMasks),
104 ::testing::Range(0, (int)EffectTestHelper::kNumSampleRates),
105 ::testing::Range(0, (int)EffectTestHelper::kNumFrameCounts),
106 ::testing::Range(0, (int)EffectTestHelper::kNumLoopCounts),
107 ::testing::Range(0, (int)kNumEffectUuids),
108 ::testing::Range(0, (int)kNumPresets)));
109
110 typedef std::tuple<int, int, int, int, int> SingleEffectComparisonTestParam;
111 class SingleEffectComparisonTest
112 : public ::testing::TestWithParam<SingleEffectComparisonTestParam> {
113 public:
SingleEffectComparisonTest()114 SingleEffectComparisonTest()
115 : mSampleRate(EffectTestHelper::kSampleRates[std::get<0>(GetParam())]),
116 mFrameCount(EffectTestHelper::kFrameCounts[std::get<1>(GetParam())]),
117 mLoopCount(EffectTestHelper::kLoopCounts[std::get<2>(GetParam())]),
118 mTotalFrameCount(mFrameCount * mLoopCount),
119 mUuid(&kEffectUuids[std::get<3>(GetParam())]),
120 mPreset(kPresets[std::get<4>(GetParam())]) {}
121
122 const size_t mSampleRate;
123 const size_t mFrameCount;
124 const size_t mLoopCount;
125 const size_t mTotalFrameCount;
126 const effect_uuid_t* mUuid;
127 const size_t mPreset;
128 };
129
130 // Compares first two channels in multi-channel output to stereo output when same effect is applied
TEST_P(SingleEffectComparisonTest,SimpleProcess)131 TEST_P(SingleEffectComparisonTest, SimpleProcess) {
132 SCOPED_TRACE(testing::Message()
133 << " sampleRate: " << mSampleRate << " frameCount: " << mFrameCount
134 << " loopCount: " << mLoopCount << " preset: " << mPreset);
135
136 // Initialize mono input buffer with deterministic pseudo-random values
137 std::vector<float> monoInput(mTotalFrameCount);
138
139 std::minstd_rand gen(mSampleRate);
140 std::uniform_real_distribution<> dis(-1.0f, 1.0f);
141 for (auto& in : monoInput) {
142 in = dis(gen);
143 }
144
145 // Generate stereo by repeating mono channel data
146 std::vector<float> stereoInput(mTotalFrameCount * FCC_2);
147 adjust_channels(monoInput.data(), FCC_1, stereoInput.data(), FCC_2, sizeof(float),
148 mTotalFrameCount * sizeof(float) * FCC_1);
149
150 // Apply effect on stereo channels
151 EffectTestHelper stereoEffect(
152 mUuid, isAuxMode(mUuid) ? AUDIO_CHANNEL_OUT_MONO : AUDIO_CHANNEL_OUT_STEREO,
153 AUDIO_CHANNEL_OUT_STEREO, mSampleRate, mFrameCount, mLoopCount);
154
155 ASSERT_NO_FATAL_FAILURE(stereoEffect.createEffect());
156 ASSERT_NO_FATAL_FAILURE(stereoEffect.setConfig());
157 ASSERT_NO_FATAL_FAILURE(stereoEffect.setParam(REVERB_PARAM_PRESET, mPreset));
158
159 std::vector<float> stereoOutput(mTotalFrameCount * FCC_2);
160 ASSERT_NO_FATAL_FAILURE(stereoEffect.process(
161 (isAuxMode(mUuid) ? monoInput.data() : stereoInput.data()), stereoOutput.data()));
162 ASSERT_NO_FATAL_FAILURE(stereoEffect.releaseEffect());
163
164 // Average of both channels data is stored for mono comparison
165 std::vector<float> monoOutput(mTotalFrameCount);
166 From2iToMono_Float((const float*)stereoOutput.data(), monoOutput.data(), mTotalFrameCount);
167
168 // Convert stereo float data to stereo int16_t to be used as reference
169 std::vector<int16_t> stereoRefI16(mTotalFrameCount * FCC_2);
170 memcpy_to_i16_from_float(stereoRefI16.data(), stereoOutput.data(), mTotalFrameCount * FCC_2);
171
172 // mono int16_t to be used as refernece for mono comparison
173 std::vector<int16_t> monoRefI16(mTotalFrameCount);
174 memcpy_to_i16_from_float(monoRefI16.data(), monoOutput.data(), mTotalFrameCount);
175
176 for (size_t outChMask : EffectTestHelper::kChMasks) {
177 size_t outChannelCount = audio_channel_count_from_out_mask(outChMask);
178 size_t inChMask = isAuxMode(mUuid) ? AUDIO_CHANNEL_OUT_MONO : outChMask;
179
180 EffectTestHelper testEffect(mUuid, inChMask, outChMask, mSampleRate, mFrameCount,
181 mLoopCount);
182
183 ASSERT_NO_FATAL_FAILURE(testEffect.createEffect());
184 ASSERT_NO_FATAL_FAILURE(testEffect.setConfig());
185 ASSERT_NO_FATAL_FAILURE(testEffect.setParam(REVERB_PARAM_PRESET, mPreset));
186
187 std::vector<float> testInput(mTotalFrameCount * outChannelCount);
188
189 // Repeat mono channel data to all the channels
190 // adjust_channels() zero fills channels > 2, hence can't be used here
191 for (size_t i = 0; i < mTotalFrameCount; ++i) {
192 auto* fp = &testInput[i * outChannelCount];
193 std::fill(fp, fp + outChannelCount, monoInput[i]);
194 }
195
196 std::vector<float> testOutput(mTotalFrameCount * outChannelCount);
197 ASSERT_NO_FATAL_FAILURE(testEffect.process(
198 (isAuxMode(mUuid) ? monoInput.data() : testInput.data()), testOutput.data()));
199 ASSERT_NO_FATAL_FAILURE(testEffect.releaseEffect());
200
201 if (outChannelCount == FCC_1) {
202 // Convert the test data to int16_t
203 std::vector<int16_t> monoTestI16(mTotalFrameCount);
204 memcpy_to_i16_from_float(monoTestI16.data(), testOutput.data(), mTotalFrameCount);
205
206 ASSERT_EQ(0, memcmp(monoRefI16.data(), monoTestI16.data(), mTotalFrameCount * FCC_2))
207 << "Mono channel do not match with reference output \n";
208 } else {
209 // Extract first two channels
210 std::vector<float> stereoTestOutput(mTotalFrameCount * FCC_2);
211 adjust_channels(testOutput.data(), outChannelCount, stereoTestOutput.data(), FCC_2,
212 sizeof(float), mTotalFrameCount * sizeof(float) * outChannelCount);
213
214 // Convert the test data to int16_t
215 std::vector<int16_t> stereoTestI16(mTotalFrameCount * FCC_2);
216 memcpy_to_i16_from_float(stereoTestI16.data(), stereoTestOutput.data(),
217 mTotalFrameCount * FCC_2);
218
219 ASSERT_EQ(0,
220 memcmp(stereoRefI16.data(), stereoTestI16.data(), mTotalFrameCount * FCC_2))
221 << "First two channels do not match with stereo output \n";
222 }
223 }
224 }
225
226 INSTANTIATE_TEST_SUITE_P(
227 EffectReverbTestAll, SingleEffectComparisonTest,
228 ::testing::Combine(::testing::Range(0, (int)EffectTestHelper::kNumSampleRates),
229 ::testing::Range(0, (int)EffectTestHelper::kNumFrameCounts),
230 ::testing::Range(0, (int)EffectTestHelper::kNumLoopCounts),
231 ::testing::Range(0, (int)kNumEffectUuids),
232 ::testing::Range(0, (int)kNumPresets)));
233
main(int argc,char ** argv)234 int main(int argc, char** argv) {
235 ::testing::InitGoogleTest(&argc, argv);
236 int status = RUN_ALL_TESTS();
237 ALOGV("Test result = %d\n", status);
238 return status;
239 }
240