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