1 /*
2 * Copyright (c) 2018 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/agc2/rnn_vad/spectral_features.h"
12
13 #include <algorithm>
14
15 #include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
16 #include "rtc_base/checks.h"
17 // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
18 // #include "test/fpe_observer.h"
19 #include "test/gtest.h"
20
21 namespace webrtc {
22 namespace rnn_vad {
23 namespace test {
24 namespace {
25
26 constexpr size_t kTestFeatureVectorSize = kNumBands + 3 * kNumLowerBands + 1;
27
28 // Writes non-zero sample values.
WriteTestData(rtc::ArrayView<float> samples)29 void WriteTestData(rtc::ArrayView<float> samples) {
30 for (size_t i = 0; i < samples.size(); ++i) {
31 samples[i] = i % 100;
32 }
33 }
34
GetHigherBandsSpectrum(std::array<float,kTestFeatureVectorSize> * feature_vector)35 rtc::ArrayView<float, kNumBands - kNumLowerBands> GetHigherBandsSpectrum(
36 std::array<float, kTestFeatureVectorSize>* feature_vector) {
37 return {feature_vector->data() + kNumLowerBands, kNumBands - kNumLowerBands};
38 }
39
GetAverage(std::array<float,kTestFeatureVectorSize> * feature_vector)40 rtc::ArrayView<float, kNumLowerBands> GetAverage(
41 std::array<float, kTestFeatureVectorSize>* feature_vector) {
42 return {feature_vector->data(), kNumLowerBands};
43 }
44
GetFirstDerivative(std::array<float,kTestFeatureVectorSize> * feature_vector)45 rtc::ArrayView<float, kNumLowerBands> GetFirstDerivative(
46 std::array<float, kTestFeatureVectorSize>* feature_vector) {
47 return {feature_vector->data() + kNumBands, kNumLowerBands};
48 }
49
GetSecondDerivative(std::array<float,kTestFeatureVectorSize> * feature_vector)50 rtc::ArrayView<float, kNumLowerBands> GetSecondDerivative(
51 std::array<float, kTestFeatureVectorSize>* feature_vector) {
52 return {feature_vector->data() + kNumBands + kNumLowerBands, kNumLowerBands};
53 }
54
GetCepstralCrossCorrelation(std::array<float,kTestFeatureVectorSize> * feature_vector)55 rtc::ArrayView<float, kNumLowerBands> GetCepstralCrossCorrelation(
56 std::array<float, kTestFeatureVectorSize>* feature_vector) {
57 return {feature_vector->data() + kNumBands + 2 * kNumLowerBands,
58 kNumLowerBands};
59 }
60
GetCepstralVariability(std::array<float,kTestFeatureVectorSize> * feature_vector)61 float* GetCepstralVariability(
62 std::array<float, kTestFeatureVectorSize>* feature_vector) {
63 return feature_vector->data() + kNumBands + 3 * kNumLowerBands;
64 }
65
66 constexpr float kInitialFeatureVal = -9999.f;
67
68 } // namespace
69
70 // Checks that silence is detected when the input signal is 0 and that the
71 // feature vector is written only if the input signal is not tagged as silence.
TEST(RnnVadTest,SpectralFeaturesWithAndWithoutSilence)72 TEST(RnnVadTest, SpectralFeaturesWithAndWithoutSilence) {
73 // Initialize.
74 SpectralFeaturesExtractor sfe;
75 std::array<float, kFrameSize20ms24kHz> samples;
76 rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples);
77 bool is_silence;
78 std::array<float, kTestFeatureVectorSize> feature_vector;
79
80 // Write an initial value in the feature vector to detect changes.
81 std::fill(feature_vector.begin(), feature_vector.end(), kInitialFeatureVal);
82
83 // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
84 // FloatingPointExceptionObserver fpe_observer;
85
86 // With silence.
87 std::fill(samples.begin(), samples.end(), 0.f);
88 is_silence = sfe.CheckSilenceComputeFeatures(
89 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector),
90 GetAverage(&feature_vector), GetFirstDerivative(&feature_vector),
91 GetSecondDerivative(&feature_vector),
92 GetCepstralCrossCorrelation(&feature_vector),
93 GetCepstralVariability(&feature_vector));
94 // Silence is expected, the output won't be overwritten.
95 EXPECT_TRUE(is_silence);
96 EXPECT_TRUE(std::all_of(feature_vector.begin(), feature_vector.end(),
97 [](float x) { return x == kInitialFeatureVal; }));
98
99 // With no silence.
100 WriteTestData(samples);
101 is_silence = sfe.CheckSilenceComputeFeatures(
102 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector),
103 GetAverage(&feature_vector), GetFirstDerivative(&feature_vector),
104 GetSecondDerivative(&feature_vector),
105 GetCepstralCrossCorrelation(&feature_vector),
106 GetCepstralVariability(&feature_vector));
107 // Silence is not expected, the output will be overwritten.
108 EXPECT_FALSE(is_silence);
109 EXPECT_FALSE(std::all_of(feature_vector.begin(), feature_vector.end(),
110 [](float x) { return x == kInitialFeatureVal; }));
111 }
112
113 // Feeds a constant input signal and checks that:
114 // - the cepstral coefficients average does not change;
115 // - the derivatives are zero;
116 // - the cepstral variability score does not change.
TEST(RnnVadTest,CepstralFeaturesConstantAverageZeroDerivative)117 TEST(RnnVadTest, CepstralFeaturesConstantAverageZeroDerivative) {
118 // Initialize.
119 SpectralFeaturesExtractor sfe;
120 std::array<float, kFrameSize20ms24kHz> samples;
121 rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples);
122 WriteTestData(samples);
123 bool is_silence;
124
125 // Fill the spectral features with test data.
126 std::array<float, kTestFeatureVectorSize> feature_vector;
127 for (size_t i = 0; i < kCepstralCoeffsHistorySize; ++i) {
128 is_silence = sfe.CheckSilenceComputeFeatures(
129 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector),
130 GetAverage(&feature_vector), GetFirstDerivative(&feature_vector),
131 GetSecondDerivative(&feature_vector),
132 GetCepstralCrossCorrelation(&feature_vector),
133 GetCepstralVariability(&feature_vector));
134 }
135
136 // Feed the test data one last time but using a different output vector.
137 std::array<float, kTestFeatureVectorSize> feature_vector_last;
138 is_silence = sfe.CheckSilenceComputeFeatures(
139 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector_last),
140 GetAverage(&feature_vector_last),
141 GetFirstDerivative(&feature_vector_last),
142 GetSecondDerivative(&feature_vector_last),
143 GetCepstralCrossCorrelation(&feature_vector_last),
144 GetCepstralVariability(&feature_vector_last));
145
146 // Average is unchanged.
147 ExpectEqualFloatArray({feature_vector.data(), kNumLowerBands},
148 {feature_vector_last.data(), kNumLowerBands});
149 // First and second derivatives are zero.
150 constexpr std::array<float, kNumLowerBands> zeros{};
151 ExpectEqualFloatArray(
152 {feature_vector_last.data() + kNumBands, kNumLowerBands}, zeros);
153 ExpectEqualFloatArray(
154 {feature_vector_last.data() + kNumBands + kNumLowerBands, kNumLowerBands},
155 zeros);
156 // Variability is unchanged.
157 EXPECT_FLOAT_EQ(feature_vector[kNumBands + 3 * kNumLowerBands],
158 feature_vector_last[kNumBands + 3 * kNumLowerBands]);
159 }
160
161 } // namespace test
162 } // namespace rnn_vad
163 } // namespace webrtc
164