| /* | |
| * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "modules/audio_processing/aec3/decimator.h" | |
| #include <algorithm> | |
| #include <array> | |
| #include <cmath> | |
| #include <cstring> | |
| #include <numbers> | |
| #include <numeric> | |
| #include <string> | |
| #include <vector> | |
| #include "api/array_view.h" | |
| #include "modules/audio_processing/aec3/aec3_common.h" | |
| #include "rtc_base/checks.h" | |
| #include "rtc_base/strings/string_builder.h" | |
| #include "test/gtest.h" | |
| namespace webrtc { | |
| namespace { | |
| std::string ProduceDebugText(int sample_rate_hz) { | |
| StringBuilder ss; | |
| ss << "Sample rate: " << sample_rate_hz; | |
| return ss.Release(); | |
| } | |
| constexpr size_t kDownSamplingFactors[] = {4, 8}; | |
| constexpr float kPi = std::numbers::pi_v<float>; | |
| constexpr size_t kNumStartupBlocks = 50; | |
| constexpr size_t kNumBlocks = 1000; | |
| void ProduceDecimatedSinusoidalOutputPower(int sample_rate_hz, | |
| size_t down_sampling_factor, | |
| float sinusoidal_frequency_hz, | |
| float* input_power, | |
| float* output_power) { | |
| float input[kBlockSize * kNumBlocks]; | |
| const size_t sub_block_size = kBlockSize / down_sampling_factor; | |
| // Produce a sinusoid of the specified frequency. | |
| for (size_t k = 0; k < kBlockSize * kNumBlocks; ++k) { | |
| input[k] = 32767.f * std::sin(2.f * kPi * sinusoidal_frequency_hz * k / | |
| sample_rate_hz); | |
| } | |
| Decimator decimator(down_sampling_factor); | |
| std::vector<float> output(sub_block_size * kNumBlocks); | |
| for (size_t k = 0; k < kNumBlocks; ++k) { | |
| std::vector<float> sub_block(sub_block_size); | |
| decimator.Decimate( | |
| ArrayView<const float>(&input[k * kBlockSize], kBlockSize), sub_block); | |
| std::copy(sub_block.begin(), sub_block.end(), | |
| output.begin() + k * sub_block_size); | |
| } | |
| ASSERT_GT(kNumBlocks, kNumStartupBlocks); | |
| ArrayView<const float> input_to_evaluate( | |
| &input[kNumStartupBlocks * kBlockSize], | |
| (kNumBlocks - kNumStartupBlocks) * kBlockSize); | |
| ArrayView<const float> output_to_evaluate( | |
| &output[kNumStartupBlocks * sub_block_size], | |
| (kNumBlocks - kNumStartupBlocks) * sub_block_size); | |
| *input_power = | |
| std::inner_product(input_to_evaluate.begin(), input_to_evaluate.end(), | |
| input_to_evaluate.begin(), 0.f) / | |
| input_to_evaluate.size(); | |
| *output_power = | |
| std::inner_product(output_to_evaluate.begin(), output_to_evaluate.end(), | |
| output_to_evaluate.begin(), 0.f) / | |
| output_to_evaluate.size(); | |
| } | |
| } // namespace | |
| // Verifies that there is little aliasing from upper frequencies in the | |
| // downsampling. | |
| TEST(Decimator, NoLeakageFromUpperFrequencies) { | |
| float input_power; | |
| float output_power; | |
| for (auto rate : {16000, 32000, 48000}) { | |
| for (auto down_sampling_factor : kDownSamplingFactors) { | |
| ProduceDebugText(rate); | |
| ProduceDecimatedSinusoidalOutputPower(rate, down_sampling_factor, | |
| 3.f / 8.f * rate, &input_power, | |
| &output_power); | |
| EXPECT_GT(0.0001f * input_power, output_power); | |
| } | |
| } | |
| } | |
| #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) | |
| // Verifies the check for the input size. | |
| TEST(DecimatorDeathTest, WrongInputSize) { | |
| Decimator decimator(4); | |
| std::vector<float> x(kBlockSize - 1, 0.f); | |
| std::array<float, kBlockSize / 4> x_downsampled; | |
| EXPECT_DEATH(decimator.Decimate(x, x_downsampled), ""); | |
| } | |
| // Verifies the check for non-null output parameter. | |
| TEST(DecimatorDeathTest, NullOutput) { | |
| Decimator decimator(4); | |
| std::vector<float> x(kBlockSize, 0.f); | |
| EXPECT_DEATH(decimator.Decimate(x, nullptr), ""); | |
| } | |
| // Verifies the check for the output size. | |
| TEST(DecimatorDeathTest, WrongOutputSize) { | |
| Decimator decimator(4); | |
| std::vector<float> x(kBlockSize, 0.f); | |
| std::array<float, kBlockSize / 4 - 1> x_downsampled; | |
| EXPECT_DEATH(decimator.Decimate(x, x_downsampled), ""); | |
| } | |
| // Verifies the check for the correct downsampling factor. | |
| TEST(DecimatorDeathTest, CorrectDownSamplingFactor) { | |
| EXPECT_DEATH(Decimator(3), ""); | |
| } | |
| #endif | |
| } // namespace webrtc |