| /* |
| * Copyright (c) 2018 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/agc2/rnn_vad/spectral_features.h" |
| |
| #include <algorithm> |
| |
| #include "modules/audio_processing/agc2/rnn_vad/test_utils.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/numerics/safe_compare.h" |
| // TODO(bugs.webrtc.org/8948): Add when the issue is fixed. |
| // #include "test/fpe_observer.h" |
| #include "test/gtest.h" |
| |
| namespace webrtc { |
| namespace rnn_vad { |
| namespace { |
| |
| constexpr int kTestFeatureVectorSize = kNumBands + 3 * kNumLowerBands + 1; |
| |
| // Writes non-zero sample values. |
| void WriteTestData(rtc::ArrayView<float> samples) { |
| for (int i = 0; rtc::SafeLt(i, samples.size()); ++i) { |
| samples[i] = i % 100; |
| } |
| } |
| |
| rtc::ArrayView<float, kNumBands - kNumLowerBands> GetHigherBandsSpectrum( |
| std::array<float, kTestFeatureVectorSize>* feature_vector) { |
| return {feature_vector->data() + kNumLowerBands, kNumBands - kNumLowerBands}; |
| } |
| |
| rtc::ArrayView<float, kNumLowerBands> GetAverage( |
| std::array<float, kTestFeatureVectorSize>* feature_vector) { |
| return {feature_vector->data(), kNumLowerBands}; |
| } |
| |
| rtc::ArrayView<float, kNumLowerBands> GetFirstDerivative( |
| std::array<float, kTestFeatureVectorSize>* feature_vector) { |
| return {feature_vector->data() + kNumBands, kNumLowerBands}; |
| } |
| |
| rtc::ArrayView<float, kNumLowerBands> GetSecondDerivative( |
| std::array<float, kTestFeatureVectorSize>* feature_vector) { |
| return {feature_vector->data() + kNumBands + kNumLowerBands, kNumLowerBands}; |
| } |
| |
| rtc::ArrayView<float, kNumLowerBands> GetCepstralCrossCorrelation( |
| std::array<float, kTestFeatureVectorSize>* feature_vector) { |
| return {feature_vector->data() + kNumBands + 2 * kNumLowerBands, |
| kNumLowerBands}; |
| } |
| |
| float* GetCepstralVariability( |
| std::array<float, kTestFeatureVectorSize>* feature_vector) { |
| return feature_vector->data() + kNumBands + 3 * kNumLowerBands; |
| } |
| |
| constexpr float kInitialFeatureVal = -9999.f; |
| |
| // Checks that silence is detected when the input signal is 0 and that the |
| // feature vector is written only if the input signal is not tagged as silence. |
| TEST(RnnVadTest, SpectralFeaturesWithAndWithoutSilence) { |
| // Initialize. |
| SpectralFeaturesExtractor sfe; |
| std::array<float, kFrameSize20ms24kHz> samples; |
| rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples); |
| bool is_silence; |
| std::array<float, kTestFeatureVectorSize> feature_vector; |
| |
| // Write an initial value in the feature vector to detect changes. |
| std::fill(feature_vector.begin(), feature_vector.end(), kInitialFeatureVal); |
| |
| // TODO(bugs.webrtc.org/8948): Add when the issue is fixed. |
| // FloatingPointExceptionObserver fpe_observer; |
| |
| // With silence. |
| std::fill(samples.begin(), samples.end(), 0.f); |
| is_silence = sfe.CheckSilenceComputeFeatures( |
| samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector), |
| GetAverage(&feature_vector), GetFirstDerivative(&feature_vector), |
| GetSecondDerivative(&feature_vector), |
| GetCepstralCrossCorrelation(&feature_vector), |
| GetCepstralVariability(&feature_vector)); |
| // Silence is expected, the output won't be overwritten. |
| EXPECT_TRUE(is_silence); |
| EXPECT_TRUE(std::all_of(feature_vector.begin(), feature_vector.end(), |
| [](float x) { return x == kInitialFeatureVal; })); |
| |
| // With no silence. |
| WriteTestData(samples); |
| is_silence = sfe.CheckSilenceComputeFeatures( |
| samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector), |
| GetAverage(&feature_vector), GetFirstDerivative(&feature_vector), |
| GetSecondDerivative(&feature_vector), |
| GetCepstralCrossCorrelation(&feature_vector), |
| GetCepstralVariability(&feature_vector)); |
| // Silence is not expected, the output will be overwritten. |
| EXPECT_FALSE(is_silence); |
| EXPECT_FALSE(std::all_of(feature_vector.begin(), feature_vector.end(), |
| [](float x) { return x == kInitialFeatureVal; })); |
| } |
| |
| // Feeds a constant input signal and checks that: |
| // - the cepstral coefficients average does not change; |
| // - the derivatives are zero; |
| // - the cepstral variability score does not change. |
| TEST(RnnVadTest, CepstralFeaturesConstantAverageZeroDerivative) { |
| // Initialize. |
| SpectralFeaturesExtractor sfe; |
| std::array<float, kFrameSize20ms24kHz> samples; |
| rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples); |
| WriteTestData(samples); |
| bool is_silence; |
| |
| // Fill the spectral features with test data. |
| std::array<float, kTestFeatureVectorSize> feature_vector; |
| for (int i = 0; i < kCepstralCoeffsHistorySize; ++i) { |
| is_silence = sfe.CheckSilenceComputeFeatures( |
| samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector), |
| GetAverage(&feature_vector), GetFirstDerivative(&feature_vector), |
| GetSecondDerivative(&feature_vector), |
| GetCepstralCrossCorrelation(&feature_vector), |
| GetCepstralVariability(&feature_vector)); |
| } |
| |
| // Feed the test data one last time but using a different output vector. |
| std::array<float, kTestFeatureVectorSize> feature_vector_last; |
| is_silence = sfe.CheckSilenceComputeFeatures( |
| samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector_last), |
| GetAverage(&feature_vector_last), |
| GetFirstDerivative(&feature_vector_last), |
| GetSecondDerivative(&feature_vector_last), |
| GetCepstralCrossCorrelation(&feature_vector_last), |
| GetCepstralVariability(&feature_vector_last)); |
| |
| // Average is unchanged. |
| ExpectEqualFloatArray({feature_vector.data(), kNumLowerBands}, |
| {feature_vector_last.data(), kNumLowerBands}); |
| // First and second derivatives are zero. |
| constexpr std::array<float, kNumLowerBands> zeros{}; |
| ExpectEqualFloatArray( |
| {feature_vector_last.data() + kNumBands, kNumLowerBands}, zeros); |
| ExpectEqualFloatArray( |
| {feature_vector_last.data() + kNumBands + kNumLowerBands, kNumLowerBands}, |
| zeros); |
| // Variability is unchanged. |
| EXPECT_FLOAT_EQ(feature_vector[kNumBands + 3 * kNumLowerBands], |
| feature_vector_last[kNumBands + 3 * kNumLowerBands]); |
| } |
| |
| } // namespace |
| } // namespace rnn_vad |
| } // namespace webrtc |