1/*
2 *  Copyright (c) 2013 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 "webrtc/modules/audio_processing/transient/moving_moments.h"
12
13#include "testing/gtest/include/gtest/gtest.h"
14#include "webrtc/base/scoped_ptr.h"
15
16namespace webrtc {
17
18static const float kTolerance = 0.0001f;
19
20class MovingMomentsTest : public ::testing::Test {
21 protected:
22  static const size_t kMovingMomentsBufferLength = 5;
23  static const size_t kMaxOutputLength = 20;  // Valid for this tests only.
24
25  virtual void SetUp();
26  // Calls CalculateMoments and verifies that it produces the expected
27  // outputs.
28  void CalculateMomentsAndVerify(const float* input, size_t input_length,
29                                 const float* expected_mean,
30                                 const float* expected_mean_squares);
31
32  rtc::scoped_ptr<MovingMoments> moving_moments_;
33  float output_mean_[kMaxOutputLength];
34  float output_mean_squares_[kMaxOutputLength];
35};
36
37const size_t MovingMomentsTest::kMaxOutputLength;
38
39void MovingMomentsTest::SetUp() {
40  moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
41}
42
43void MovingMomentsTest::CalculateMomentsAndVerify(
44    const float* input, size_t input_length,
45    const float* expected_mean,
46    const float* expected_mean_squares) {
47  ASSERT_LE(input_length, kMaxOutputLength);
48
49  moving_moments_->CalculateMoments(input,
50                                    input_length,
51                                    output_mean_,
52                                    output_mean_squares_);
53
54  for (size_t i = 1; i < input_length; ++i) {
55    EXPECT_NEAR(expected_mean[i], output_mean_[i], kTolerance);
56    EXPECT_NEAR(expected_mean_squares[i], output_mean_squares_[i], kTolerance);
57  }
58}
59
60TEST_F(MovingMomentsTest, CorrectMomentsOfAnAllZerosBuffer) {
61  const float kInput[] = {0.f, 0.f, 0.f, 0.f, 0.f};
62  const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
63
64  const float expected_mean[kInputLength] = {0.f, 0.f, 0.f, 0.f, 0.f};
65  const float expected_mean_squares[kInputLength] = {0.f, 0.f, 0.f, 0.f, 0.f};
66
67  CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
68                            expected_mean_squares);
69}
70
71TEST_F(MovingMomentsTest, CorrectMomentsOfAConstantBuffer) {
72  const float kInput[] = {5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f};
73  const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
74
75  const float expected_mean[kInputLength] =
76      {1.f, 2.f, 3.f, 4.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f};
77  const float expected_mean_squares[kInputLength] =
78      {5.f, 10.f, 15.f, 20.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f};
79
80  CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
81                            expected_mean_squares);
82}
83
84TEST_F(MovingMomentsTest, CorrectMomentsOfAnIncreasingBuffer) {
85  const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f};
86  const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
87
88  const float expected_mean[kInputLength] =
89      {0.2f, 0.6f, 1.2f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f};
90  const float expected_mean_squares[kInputLength] =
91      {0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
92
93  CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
94                            expected_mean_squares);
95}
96
97TEST_F(MovingMomentsTest, CorrectMomentsOfADecreasingBuffer) {
98  const float kInput[] =
99      {-1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f, -8.f, -9.f};
100  const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
101
102  const float expected_mean[kInputLength] =
103      {-0.2f, -0.6f, -1.2f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f};
104  const float expected_mean_squares[kInputLength] =
105      {0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
106
107  CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
108                            expected_mean_squares);
109}
110
111TEST_F(MovingMomentsTest, CorrectMomentsOfAZeroMeanSequence) {
112  const size_t kMovingMomentsBufferLength = 4;
113  moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
114  const float kInput[] =
115      {1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f};
116  const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
117
118  const float expected_mean[kInputLength] =
119      {0.25f, 0.f, 0.25f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
120  const float expected_mean_squares[kInputLength] =
121      {0.25f, 0.5f, 0.75f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
122
123  CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
124                            expected_mean_squares);
125}
126
127TEST_F(MovingMomentsTest, CorrectMomentsOfAnArbitraryBuffer) {
128  const float kInput[] =
129      {0.2f, 0.3f, 0.5f, 0.7f, 0.11f, 0.13f, 0.17f, 0.19f, 0.23f};
130  const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
131
132  const float expected_mean[kInputLength] =
133      {0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
134  const float expected_mean_squares[kInputLength] =
135      {0.008f, 0.026f, 0.076f, 0.174f, 0.1764f, 0.1718f, 0.1596f, 0.1168f,
136      0.0294f};
137
138  CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
139                            expected_mean_squares);
140}
141
142TEST_F(MovingMomentsTest, MutipleCalculateMomentsCalls) {
143  const float kInputFirstCall[] =
144      {0.2f, 0.3f, 0.5f, 0.7f, 0.11f, 0.13f, 0.17f, 0.19f, 0.23f};
145  const size_t kInputFirstCallLength = sizeof(kInputFirstCall) /
146                                    sizeof(kInputFirstCall[0]);
147  const float kInputSecondCall[] = {0.29f, 0.31f};
148  const size_t kInputSecondCallLength = sizeof(kInputSecondCall) /
149                                     sizeof(kInputSecondCall[0]);
150  const float kInputThirdCall[] = {0.37f, 0.41f, 0.43f, 0.47f};
151  const size_t kInputThirdCallLength = sizeof(kInputThirdCall) /
152                                    sizeof(kInputThirdCall[0]);
153
154  const float expected_mean_first_call[kInputFirstCallLength] =
155      {0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
156  const float expected_mean_squares_first_call[kInputFirstCallLength] =
157      {0.008f, 0.026f, 0.076f, 0.174f, 0.1764f, 0.1718f, 0.1596f, 0.1168f,
158      0.0294f};
159
160  const float expected_mean_second_call[kInputSecondCallLength] =
161      {0.202f, 0.238f};
162  const float expected_mean_squares_second_call[kInputSecondCallLength] =
163      {0.0438f, 0.0596f};
164
165  const float expected_mean_third_call[kInputThirdCallLength] =
166      {0.278f, 0.322f, 0.362f, 0.398f};
167  const float expected_mean_squares_third_call[kInputThirdCallLength] =
168      {0.0812f, 0.1076f, 0.134f, 0.1614f};
169
170  CalculateMomentsAndVerify(kInputFirstCall, kInputFirstCallLength,
171      expected_mean_first_call, expected_mean_squares_first_call);
172
173  CalculateMomentsAndVerify(kInputSecondCall, kInputSecondCallLength,
174      expected_mean_second_call, expected_mean_squares_second_call);
175
176  CalculateMomentsAndVerify(kInputThirdCall, kInputThirdCallLength,
177      expected_mean_third_call, expected_mean_squares_third_call);
178}
179
180TEST_F(MovingMomentsTest,
181       VerifySampleBasedVsBlockBasedCalculation) {
182  const float kInput[] =
183      {0.2f, 0.3f, 0.5f, 0.7f, 0.11f, 0.13f, 0.17f, 0.19f, 0.23f};
184  const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
185
186  float output_mean_block_based[kInputLength];
187  float output_mean_squares_block_based[kInputLength];
188
189  float output_mean_sample_based;
190  float output_mean_squares_sample_based;
191
192  moving_moments_->CalculateMoments(
193      kInput, kInputLength, output_mean_block_based,
194      output_mean_squares_block_based);
195  moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
196  for (size_t i = 0; i < kInputLength; ++i) {
197    moving_moments_->CalculateMoments(
198        &kInput[i], 1, &output_mean_sample_based,
199        &output_mean_squares_sample_based);
200    EXPECT_FLOAT_EQ(output_mean_block_based[i], output_mean_sample_based);
201    EXPECT_FLOAT_EQ(output_mean_squares_block_based[i],
202                     output_mean_squares_sample_based);
203  }
204}
205
206}  // namespace webrtc
207