1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_processing/aec3/decimator.h"
12
13 #include <math.h>
14 #include <algorithm>
15 #include <array>
16 #include <numeric>
17 #include <sstream>
18 #include <string>
19 #include <vector>
20
21 #include "modules/audio_processing/aec3/aec3_common.h"
22 #include "test/gtest.h"
23
24 namespace webrtc {
25
26 namespace {
27
ProduceDebugText(int sample_rate_hz)28 std::string ProduceDebugText(int sample_rate_hz) {
29 std::ostringstream ss;
30 ss << "Sample rate: " << sample_rate_hz;
31 return ss.str();
32 }
33
34 constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
35 constexpr float kPi = 3.141592f;
36 constexpr size_t kNumStartupBlocks = 50;
37 constexpr size_t kNumBlocks = 1000;
38
ProduceDecimatedSinusoidalOutputPower(int sample_rate_hz,size_t down_sampling_factor,float sinusoidal_frequency_hz,float * input_power,float * output_power)39 void ProduceDecimatedSinusoidalOutputPower(int sample_rate_hz,
40 size_t down_sampling_factor,
41 float sinusoidal_frequency_hz,
42 float* input_power,
43 float* output_power) {
44 float input[kBlockSize * kNumBlocks];
45 const size_t sub_block_size = kBlockSize / down_sampling_factor;
46
47 // Produce a sinusoid of the specified frequency.
48 for (size_t k = 0; k < kBlockSize * kNumBlocks; ++k) {
49 input[k] =
50 32767.f * sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz);
51 }
52
53 Decimator decimator(down_sampling_factor);
54 std::vector<float> output(sub_block_size * kNumBlocks);
55
56 for (size_t k = 0; k < kNumBlocks; ++k) {
57 std::vector<float> sub_block(sub_block_size);
58
59 decimator.Decimate(
60 rtc::ArrayView<const float>(&input[k * kBlockSize], kBlockSize),
61 sub_block);
62
63 std::copy(sub_block.begin(), sub_block.end(),
64 output.begin() + k * sub_block_size);
65 }
66
67 ASSERT_GT(kNumBlocks, kNumStartupBlocks);
68 rtc::ArrayView<const float> input_to_evaluate(
69 &input[kNumStartupBlocks * kBlockSize],
70 (kNumBlocks - kNumStartupBlocks) * kBlockSize);
71 rtc::ArrayView<const float> output_to_evaluate(
72 &output[kNumStartupBlocks * sub_block_size],
73 (kNumBlocks - kNumStartupBlocks) * sub_block_size);
74 *input_power =
75 std::inner_product(input_to_evaluate.begin(), input_to_evaluate.end(),
76 input_to_evaluate.begin(), 0.f) /
77 input_to_evaluate.size();
78 *output_power =
79 std::inner_product(output_to_evaluate.begin(), output_to_evaluate.end(),
80 output_to_evaluate.begin(), 0.f) /
81 output_to_evaluate.size();
82 }
83
84 } // namespace
85
86 // Verifies that there is little aliasing from upper frequencies in the
87 // downsampling.
TEST(Decimator,NoLeakageFromUpperFrequencies)88 TEST(Decimator, NoLeakageFromUpperFrequencies) {
89 float input_power;
90 float output_power;
91 for (auto rate : {8000, 16000, 32000, 48000}) {
92 for (auto down_sampling_factor : kDownSamplingFactors) {
93 ProduceDebugText(rate);
94 ProduceDecimatedSinusoidalOutputPower(rate, down_sampling_factor,
95 3.f / 8.f * rate, &input_power,
96 &output_power);
97 EXPECT_GT(0.0001f * input_power, output_power);
98 }
99 }
100 }
101
102 // Verifies that the impact of low-frequency content is small during the
103 // downsampling.
TEST(Decimator,NoImpactOnLowerFrequencies)104 TEST(Decimator, NoImpactOnLowerFrequencies) {
105 float input_power;
106 float output_power;
107 for (auto rate : {8000, 16000, 32000, 48000}) {
108 for (auto down_sampling_factor : kDownSamplingFactors) {
109 ProduceDebugText(rate);
110 ProduceDecimatedSinusoidalOutputPower(rate, down_sampling_factor, 200.f,
111 &input_power, &output_power);
112 EXPECT_LT(0.7f * input_power, output_power);
113 }
114 }
115 }
116
117 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
118 // Verifies the check for the input size.
TEST(Decimator,WrongInputSize)119 TEST(Decimator, WrongInputSize) {
120 Decimator decimator(4);
121 std::vector<float> x(std::vector<float>(kBlockSize - 1, 0.f));
122 std::array<float, kBlockSize / 4> x_downsampled;
123 EXPECT_DEATH(decimator.Decimate(x, x_downsampled), "");
124 }
125
126 // Verifies the check for non-null output parameter.
TEST(Decimator,NullOutput)127 TEST(Decimator, NullOutput) {
128 Decimator decimator(4);
129 std::vector<float> x(std::vector<float>(kBlockSize, 0.f));
130 EXPECT_DEATH(decimator.Decimate(x, nullptr), "");
131 }
132
133 // Verifies the check for the output size.
TEST(Decimator,WrongOutputSize)134 TEST(Decimator, WrongOutputSize) {
135 Decimator decimator(4);
136 std::vector<float> x(std::vector<float>(kBlockSize, 0.f));
137 std::array<float, kBlockSize / 4 - 1> x_downsampled;
138 EXPECT_DEATH(decimator.Decimate(x, x_downsampled), "");
139 }
140
141 // Verifies the check for the correct downsampling factor.
TEST(Decimator,CorrectDownSamplingFactor)142 TEST(Decimator, CorrectDownSamplingFactor) {
143 EXPECT_DEATH(Decimator(3), "");
144 }
145
146 #endif
147
148 } // namespace webrtc
149