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 #include "rtc_base/numerics/safe_compare.h"
18 // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
19 // #include "test/fpe_observer.h"
20 #include "test/gtest.h"
21
22 namespace webrtc {
23 namespace rnn_vad {
24 namespace {
25
26 constexpr int 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 (int i = 0; rtc::SafeLt(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 // Checks that silence is detected when the input signal is 0 and that the
69 // feature vector is written only if the input signal is not tagged as silence.
TEST(RnnVadTest,SpectralFeaturesWithAndWithoutSilence)70 TEST(RnnVadTest, SpectralFeaturesWithAndWithoutSilence) {
71 // Initialize.
72 SpectralFeaturesExtractor sfe;
73 std::array<float, kFrameSize20ms24kHz> samples;
74 rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples);
75 bool is_silence;
76 std::array<float, kTestFeatureVectorSize> feature_vector;
77
78 // Write an initial value in the feature vector to detect changes.
79 std::fill(feature_vector.begin(), feature_vector.end(), kInitialFeatureVal);
80
81 // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
82 // FloatingPointExceptionObserver fpe_observer;
83
84 // With silence.
85 std::fill(samples.begin(), samples.end(), 0.f);
86 is_silence = sfe.CheckSilenceComputeFeatures(
87 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector),
88 GetAverage(&feature_vector), GetFirstDerivative(&feature_vector),
89 GetSecondDerivative(&feature_vector),
90 GetCepstralCrossCorrelation(&feature_vector),
91 GetCepstralVariability(&feature_vector));
92 // Silence is expected, the output won't be overwritten.
93 EXPECT_TRUE(is_silence);
94 EXPECT_TRUE(std::all_of(feature_vector.begin(), feature_vector.end(),
95 [](float x) { return x == kInitialFeatureVal; }));
96
97 // With no silence.
98 WriteTestData(samples);
99 is_silence = sfe.CheckSilenceComputeFeatures(
100 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector),
101 GetAverage(&feature_vector), GetFirstDerivative(&feature_vector),
102 GetSecondDerivative(&feature_vector),
103 GetCepstralCrossCorrelation(&feature_vector),
104 GetCepstralVariability(&feature_vector));
105 // Silence is not expected, the output will be overwritten.
106 EXPECT_FALSE(is_silence);
107 EXPECT_FALSE(std::all_of(feature_vector.begin(), feature_vector.end(),
108 [](float x) { return x == kInitialFeatureVal; }));
109 }
110
111 // Feeds a constant input signal and checks that:
112 // - the cepstral coefficients average does not change;
113 // - the derivatives are zero;
114 // - the cepstral variability score does not change.
TEST(RnnVadTest,CepstralFeaturesConstantAverageZeroDerivative)115 TEST(RnnVadTest, CepstralFeaturesConstantAverageZeroDerivative) {
116 // Initialize.
117 SpectralFeaturesExtractor sfe;
118 std::array<float, kFrameSize20ms24kHz> samples;
119 rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples);
120 WriteTestData(samples);
121
122 // Fill the spectral features with test data.
123 std::array<float, kTestFeatureVectorSize> feature_vector;
124 for (int i = 0; i < kCepstralCoeffsHistorySize; ++i) {
125 sfe.CheckSilenceComputeFeatures(
126 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector),
127 GetAverage(&feature_vector), GetFirstDerivative(&feature_vector),
128 GetSecondDerivative(&feature_vector),
129 GetCepstralCrossCorrelation(&feature_vector),
130 GetCepstralVariability(&feature_vector));
131 }
132
133 // Feed the test data one last time but using a different output vector.
134 std::array<float, kTestFeatureVectorSize> feature_vector_last;
135 sfe.CheckSilenceComputeFeatures(
136 samples_view, samples_view, GetHigherBandsSpectrum(&feature_vector_last),
137 GetAverage(&feature_vector_last),
138 GetFirstDerivative(&feature_vector_last),
139 GetSecondDerivative(&feature_vector_last),
140 GetCepstralCrossCorrelation(&feature_vector_last),
141 GetCepstralVariability(&feature_vector_last));
142
143 // Average is unchanged.
144 ExpectEqualFloatArray({feature_vector.data(), kNumLowerBands},
145 {feature_vector_last.data(), kNumLowerBands});
146 // First and second derivatives are zero.
147 constexpr std::array<float, kNumLowerBands> zeros{};
148 ExpectEqualFloatArray(
149 {feature_vector_last.data() + kNumBands, kNumLowerBands}, zeros);
150 ExpectEqualFloatArray(
151 {feature_vector_last.data() + kNumBands + kNumLowerBands, kNumLowerBands},
152 zeros);
153 // Variability is unchanged.
154 EXPECT_FLOAT_EQ(feature_vector[kNumBands + 3 * kNumLowerBands],
155 feature_vector_last[kNumBands + 3 * kNumLowerBands]);
156 }
157
158 } // namespace
159 } // namespace rnn_vad
160 } // namespace webrtc
161