• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "dsp/core/dynamic_range_compression.h"
18 #include <audio_effects/effect_loudnessenhancer.h>
19 #include <audio_utils/dsp_utils.h>
20 #include <gtest/gtest.h>
21 #include <log/log.h>
22 #include <system/audio_effects/audio_effects_test.h>
23 
24 using status_t = int32_t;
25 extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
26 effect_uuid_t loudness_uuid = {0xfa415329, 0x2034, 0x4bea, 0xb5dc,
27     {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}};
28 
29 using namespace android::audio_utils;
30 using namespace android::effect::utils;
31 
32 /*
33 Android 16:
34 expectedEnergydB: -24.771212  energyIndB: -24.739433
35 gaindB: 0.000000  measureddB: 0.000000  energyIndB: -24.739433  energyOutdB: -24.739433
36 gaindB: 1.000000  measureddB: 1.000004  energyIndB: -24.739433  energyOutdB: -23.739429
37 gaindB: 2.000000  measureddB: 2.000002  energyIndB: -24.739433  energyOutdB: -22.739431
38 gaindB: 5.000000  measureddB: 5.000006  energyIndB: -24.739433  energyOutdB: -19.739428
39 gaindB: 10.000000  measureddB: 10.000004  energyIndB: -24.739433  energyOutdB: -14.739429
40 gaindB: 20.000000  measureddB: 13.513464  energyIndB: -24.739433  energyOutdB: -11.225969
41 gaindB: 50.000000  measureddB: 18.649250  energyIndB: -24.739433  energyOutdB: -6.090182
42 gaindB: 100.000000  measureddB: 22.874735  energyIndB: -24.739433  energyOutdB: -1.864698
43  */
44 
45 static constexpr audio_channel_mask_t kOutputChannelMasks[] = {
46 AUDIO_CHANNEL_OUT_STEREO,
47 AUDIO_CHANNEL_OUT_5POINT1,
48 AUDIO_CHANNEL_OUT_7POINT1,
49 AUDIO_CHANNEL_OUT_7POINT1POINT4,
50 AUDIO_CHANNEL_OUT_9POINT1POINT6,
51 };
52 
53 using LoudnessEnhancerGainParam = std::tuple<int /* channel mask */>;
54 
55 enum {
56     GAIN_CHANNEL_MASK_POSITION = 0,
57     //GAIN_ACCUMULATE_POSITION = 1,
58 };
59 
60 class LoudnessEnhancerGainTest : public ::testing::TestWithParam<LoudnessEnhancerGainParam> {
61 public:
62 
testGain(audio_channel_mask_t channelMask)63     void testGain(audio_channel_mask_t channelMask) {
64         effect_handle_t handle;
65         ASSERT_EQ(0, AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
66                 &loudness_uuid, 0 /* sessionId */, 0 /* ioId */, &handle));
67 
68         constexpr size_t frameCount = 1024;
69         constexpr uint32_t sampleRate = 48000;
70         const size_t channelCount = audio_channel_count_from_out_mask(channelMask);
71         if (channelCount > FCC_LIMIT) return;
72         constexpr float amplitude = 0.1;
73         const size_t sampleCount = channelCount * frameCount;
74         std::vector<float> originalData(sampleCount);
75         initUniformDistribution(originalData, -amplitude, amplitude);
76         std::vector<float> outData(sampleCount);
77 
78         ASSERT_EQ(0, effect_set_config(handle, sampleRate, channelMask));
79         ASSERT_EQ(0, effect_enable(handle));
80 
81         // expected energy in dB for a uniform distribution from -amplitude to amplitude.
82         const float expectedEnergydB = energyOfUniformDistribution(-amplitude, amplitude);
83         const float energyIndB = energy(originalData);
84         ALOGD("%s: expectedEnergydB: %f  energyIndB: %f", __func__, expectedEnergydB, energyIndB);
85         EXPECT_NEAR(energyIndB, expectedEnergydB, 0.1);  // within 0.1dB.
86         float lastMeasuredGaindB = 0;
87         for (int gainmB : { 0, 100, 200, 500, 1'000, 2'000, 5'000, 10'000 }) {  // millibel Power
88             ASSERT_EQ(0, effect_set_param(
89                     handle, LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB, gainmB));
90 
91             auto inData = originalData;
92             audio_buffer_t inBuffer{ .frameCount = frameCount, .f32 = inData.data() };
93             audio_buffer_t outBuffer{ .frameCount = frameCount, .f32 = outData.data() };
94             ASSERT_EQ(0, effect_process(handle, &inBuffer, &outBuffer));
95             const float energyOutdB = energy(inData);
96             const float gaindB = gainmB * 1e-2;
97             const float measuredGaindB = energyOutdB - energyIndB;
98 
99             // Log our gain and power levels
100             ALOGD("%s: gaindB: %f  measureddB: %f  energyIndB: %f  energyOutdB: %f",
101                   __func__, gaindB, measuredGaindB, energyIndB, energyOutdB);
102 
103             // Gain curve testing (move to VTS)?
104             if (gaindB == 0) {
105                 EXPECT_EQ(energyIndB, energyOutdB);
106             } else if (energyIndB + gaindB < -10.f) {
107                 // less than -10dB from overflow, signal does not saturate.
108                 EXPECT_NEAR(gaindB, measuredGaindB, 0.1);
109             } else {  // effective gain saturates.
110                 EXPECT_LT(measuredGaindB, gaindB);       // less than the desired gain.
111                 EXPECT_GT(measuredGaindB, lastMeasuredGaindB);  // more than the previous gain.
112             }
113             lastMeasuredGaindB = measuredGaindB;
114         }
115         ASSERT_EQ(0, AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(handle));
116     }
117 };
118 
119 /**
120  * The Gain test checks that gain that does not saturate the input signal
121  * will be applied as expected.  Gain that would cause the input signal to
122  * exceed the nominal limit is reduced.
123  */
124 
TEST_P(LoudnessEnhancerGainTest,gain)125 TEST_P(LoudnessEnhancerGainTest, gain) {
126     testGain(kOutputChannelMasks[std::get<GAIN_CHANNEL_MASK_POSITION>(GetParam())]);
127 }
128 
129 INSTANTIATE_TEST_SUITE_P(
130         LoudnessEnhancerTestAll, LoudnessEnhancerGainTest,
131         ::testing::Combine(
132                 ::testing::Range(0, (int)std::size(kOutputChannelMasks))),
__anonaf3e4e910202(const testing::TestParamInfo<LoudnessEnhancerGainTest::ParamType>& info) 133         [](const testing::TestParamInfo<LoudnessEnhancerGainTest::ParamType>& info) {
134             const int index = std::get<GAIN_CHANNEL_MASK_POSITION>(info.param);
135             const audio_channel_mask_t channelMask = kOutputChannelMasks[index];
136             const std::string name =
137                     std::string(audio_channel_out_mask_to_string(channelMask)) +
138                     std::to_string(index);
139             return name;
140         });
141