• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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