1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // MSVC++ requires this to be set before any other includes to get M_PI.
6 #define _USE_MATH_DEFINES
9 #include "base/memory/aligned_memory.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringize_macros.h"
13 #include "media/base/vector_math.h"
14 #include "media/base/vector_math_testing.h"
15 #include "testing/gtest/include/gtest/gtest.h"
21 // Default test values.
22 static const float kScale
= 0.5;
23 static const float kInputFillValue
= 1.0;
24 static const float kOutputFillValue
= 3.0;
25 static const int kVectorSize
= 8192;
27 class VectorMathTest
: public testing::Test
{
31 // Initialize input and output vectors.
32 input_vector_
.reset(static_cast<float*>(base::AlignedAlloc(
33 sizeof(float) * kVectorSize
, vector_math::kRequiredAlignment
)));
34 output_vector_
.reset(static_cast<float*>(base::AlignedAlloc(
35 sizeof(float) * kVectorSize
, vector_math::kRequiredAlignment
)));
38 void FillTestVectors(float input
, float output
) {
39 // Setup input and output vectors.
40 fill(input_vector_
.get(), input_vector_
.get() + kVectorSize
, input
);
41 fill(output_vector_
.get(), output_vector_
.get() + kVectorSize
, output
);
44 void VerifyOutput(float value
) {
45 for (int i
= 0; i
< kVectorSize
; ++i
)
46 ASSERT_FLOAT_EQ(output_vector_
[i
], value
);
50 scoped_ptr
<float[], base::AlignedFreeDeleter
> input_vector_
;
51 scoped_ptr
<float[], base::AlignedFreeDeleter
> output_vector_
;
53 DISALLOW_COPY_AND_ASSIGN(VectorMathTest
);
56 // Ensure each optimized vector_math::FMAC() method returns the same value.
57 TEST_F(VectorMathTest
, FMAC
) {
58 static const float kResult
= kInputFillValue
* kScale
+ kOutputFillValue
;
62 FillTestVectors(kInputFillValue
, kOutputFillValue
);
64 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
65 VerifyOutput(kResult
);
69 SCOPED_TRACE("FMAC_C");
70 FillTestVectors(kInputFillValue
, kOutputFillValue
);
72 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
73 VerifyOutput(kResult
);
76 #if defined(ARCH_CPU_X86_FAMILY)
78 SCOPED_TRACE("FMAC_SSE");
79 FillTestVectors(kInputFillValue
, kOutputFillValue
);
80 vector_math::FMAC_SSE(
81 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
82 VerifyOutput(kResult
);
86 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
88 SCOPED_TRACE("FMAC_NEON");
89 FillTestVectors(kInputFillValue
, kOutputFillValue
);
90 vector_math::FMAC_NEON(
91 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
92 VerifyOutput(kResult
);
97 // Ensure each optimized vector_math::FMUL() method returns the same value.
98 TEST_F(VectorMathTest
, FMUL
) {
99 static const float kResult
= kInputFillValue
* kScale
;
102 SCOPED_TRACE("FMUL");
103 FillTestVectors(kInputFillValue
, kOutputFillValue
);
105 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
106 VerifyOutput(kResult
);
110 SCOPED_TRACE("FMUL_C");
111 FillTestVectors(kInputFillValue
, kOutputFillValue
);
113 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
114 VerifyOutput(kResult
);
117 #if defined(ARCH_CPU_X86_FAMILY)
119 SCOPED_TRACE("FMUL_SSE");
120 FillTestVectors(kInputFillValue
, kOutputFillValue
);
121 vector_math::FMUL_SSE(
122 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
123 VerifyOutput(kResult
);
127 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
129 SCOPED_TRACE("FMUL_NEON");
130 FillTestVectors(kInputFillValue
, kOutputFillValue
);
131 vector_math::FMUL_NEON(
132 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
133 VerifyOutput(kResult
);
138 TEST_F(VectorMathTest
, Crossfade
) {
139 FillTestVectors(0, 1);
140 vector_math::Crossfade(
141 input_vector_
.get(), kVectorSize
, output_vector_
.get());
142 for (int i
= 0; i
< kVectorSize
; ++i
) {
143 ASSERT_FLOAT_EQ(i
/ static_cast<float>(kVectorSize
), output_vector_
[i
])
148 class EWMATestScenario
{
150 EWMATestScenario(float initial_value
, const float src
[], int len
,
151 float smoothing_factor
)
152 : initial_value_(initial_value
),
153 data_(static_cast<float*>(
155 base::AlignedAlloc(len
* sizeof(float),
156 vector_math::kRequiredAlignment
))),
158 smoothing_factor_(smoothing_factor
),
159 expected_final_avg_(initial_value
),
160 expected_max_(0.0f
) {
162 memcpy(data_
.get(), src
, len
* sizeof(float));
165 // Copy constructor and assignment operator for ::testing::Values(...).
166 EWMATestScenario(const EWMATestScenario
& other
) { *this = other
; }
167 EWMATestScenario
& operator=(const EWMATestScenario
& other
) {
168 this->initial_value_
= other
.initial_value_
;
169 this->smoothing_factor_
= other
.smoothing_factor_
;
170 if (other
.data_len_
== 0) {
173 this->data_
.reset(static_cast<float*>(
174 base::AlignedAlloc(other
.data_len_
* sizeof(float),
175 vector_math::kRequiredAlignment
)));
176 memcpy(this->data_
.get(), other
.data_
.get(),
177 other
.data_len_
* sizeof(float));
179 this->data_len_
= other
.data_len_
;
180 this->expected_final_avg_
= other
.expected_final_avg_
;
181 this->expected_max_
= other
.expected_max_
;
185 EWMATestScenario
ScaledBy(float scale
) const {
186 EWMATestScenario
result(*this);
187 float* p
= result
.data_
.get();
188 float* const p_end
= p
+ result
.data_len_
;
189 for (; p
< p_end
; ++p
)
194 EWMATestScenario
WithImpulse(float value
, int offset
) const {
195 EWMATestScenario
result(*this);
196 result
.data_
.get()[offset
] = value
;
200 EWMATestScenario
HasExpectedResult(float final_avg_value
,
201 float max_value
) const {
202 EWMATestScenario
result(*this);
203 result
.expected_final_avg_
= final_avg_value
;
204 result
.expected_max_
= max_value
;
208 void RunTest() const {
210 SCOPED_TRACE("EWMAAndMaxPower");
211 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower(
212 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
213 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
214 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
218 SCOPED_TRACE("EWMAAndMaxPower_C");
219 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_C(
220 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
221 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
222 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
225 #if defined(ARCH_CPU_X86_FAMILY)
227 SCOPED_TRACE("EWMAAndMaxPower_SSE");
228 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_SSE(
229 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
230 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
231 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
235 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
237 SCOPED_TRACE("EWMAAndMaxPower_NEON");
238 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_NEON(
239 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
240 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
241 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
247 float initial_value_
;
248 scoped_ptr
<float, base::AlignedFreeDeleter
> data_
;
250 float smoothing_factor_
;
251 float expected_final_avg_
;
255 typedef testing::TestWithParam
<EWMATestScenario
> VectorMathEWMAAndMaxPowerTest
;
257 TEST_P(VectorMathEWMAAndMaxPowerTest
, Correctness
) {
258 GetParam().RunTest();
261 static const float kZeros
[] = { // 32 zeros
262 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
266 static const float kOnes
[] = { // 32 ones
267 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
268 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
271 static const float kCheckerboard
[] = { // 32 alternating 0, 1
272 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
273 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
276 static const float kInverseCheckerboard
[] = { // 32 alternating 1, 0
277 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
278 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
281 INSTANTIATE_TEST_CASE_P(
282 Scenarios
, VectorMathEWMAAndMaxPowerTest
,
284 // Zero-length input: Result should equal initial value.
285 EWMATestScenario(0.0f
, NULL
, 0, 0.0f
).HasExpectedResult(0.0f
, 0.0f
),
286 EWMATestScenario(1.0f
, NULL
, 0, 0.0f
).HasExpectedResult(1.0f
, 0.0f
),
288 // Smoothing factor of zero: Samples have no effect on result.
289 EWMATestScenario(0.0f
, kOnes
, 32, 0.0f
).HasExpectedResult(0.0f
, 1.0f
),
290 EWMATestScenario(1.0f
, kZeros
, 32, 0.0f
).HasExpectedResult(1.0f
, 0.0f
),
292 // Smothing factor of one: Result = last sample squared.
293 EWMATestScenario(0.0f
, kCheckerboard
, 32, 1.0f
)
295 .HasExpectedResult(4.0f
, 4.0f
),
296 EWMATestScenario(1.0f
, kInverseCheckerboard
, 32, 1.0f
)
298 .HasExpectedResult(0.0f
, 4.0f
),
300 // Smoothing factor of 1/4, muted signal.
301 EWMATestScenario(1.0f
, kZeros
, 1, 0.25f
)
302 .HasExpectedResult(powf(0.75, 1.0f
), 0.0f
),
303 EWMATestScenario(1.0f
, kZeros
, 2, 0.25f
)
304 .HasExpectedResult(powf(0.75, 2.0f
), 0.0f
),
305 EWMATestScenario(1.0f
, kZeros
, 3, 0.25f
)
306 .HasExpectedResult(powf(0.75, 3.0f
), 0.0f
),
307 EWMATestScenario(1.0f
, kZeros
, 12, 0.25f
)
308 .HasExpectedResult(powf(0.75, 12.0f
), 0.0f
),
309 EWMATestScenario(1.0f
, kZeros
, 13, 0.25f
)
310 .HasExpectedResult(powf(0.75, 13.0f
), 0.0f
),
311 EWMATestScenario(1.0f
, kZeros
, 14, 0.25f
)
312 .HasExpectedResult(powf(0.75, 14.0f
), 0.0f
),
313 EWMATestScenario(1.0f
, kZeros
, 15, 0.25f
)
314 .HasExpectedResult(powf(0.75, 15.0f
), 0.0f
),
316 // Smoothing factor of 1/4, constant full-amplitude signal.
317 EWMATestScenario(0.0f
, kOnes
, 1, 0.25f
).HasExpectedResult(0.25f
, 1.0f
),
318 EWMATestScenario(0.0f
, kOnes
, 2, 0.25f
)
319 .HasExpectedResult(0.4375f
, 1.0f
),
320 EWMATestScenario(0.0f
, kOnes
, 3, 0.25f
)
321 .HasExpectedResult(0.578125f
, 1.0f
),
322 EWMATestScenario(0.0f
, kOnes
, 12, 0.25f
)
323 .HasExpectedResult(0.96832365f
, 1.0f
),
324 EWMATestScenario(0.0f
, kOnes
, 13, 0.25f
)
325 .HasExpectedResult(0.97624274f
, 1.0f
),
326 EWMATestScenario(0.0f
, kOnes
, 14, 0.25f
)
327 .HasExpectedResult(0.98218205f
, 1.0f
),
328 EWMATestScenario(0.0f
, kOnes
, 15, 0.25f
)
329 .HasExpectedResult(0.98663654f
, 1.0f
),
331 // Smoothing factor of 1/4, checkerboard signal.
332 EWMATestScenario(0.0f
, kCheckerboard
, 1, 0.25f
)
333 .HasExpectedResult(0.0f
, 0.0f
),
334 EWMATestScenario(0.0f
, kCheckerboard
, 2, 0.25f
)
335 .HasExpectedResult(0.25f
, 1.0f
),
336 EWMATestScenario(0.0f
, kCheckerboard
, 3, 0.25f
)
337 .HasExpectedResult(0.1875f
, 1.0f
),
338 EWMATestScenario(0.0f
, kCheckerboard
, 12, 0.25f
)
339 .HasExpectedResult(0.55332780f
, 1.0f
),
340 EWMATestScenario(0.0f
, kCheckerboard
, 13, 0.25f
)
341 .HasExpectedResult(0.41499585f
, 1.0f
),
342 EWMATestScenario(0.0f
, kCheckerboard
, 14, 0.25f
)
343 .HasExpectedResult(0.56124689f
, 1.0f
),
344 EWMATestScenario(0.0f
, kCheckerboard
, 15, 0.25f
)
345 .HasExpectedResult(0.42093517f
, 1.0f
),
347 // Smoothing factor of 1/4, inverse checkerboard signal.
348 EWMATestScenario(0.0f
, kInverseCheckerboard
, 1, 0.25f
)
349 .HasExpectedResult(0.25f
, 1.0f
),
350 EWMATestScenario(0.0f
, kInverseCheckerboard
, 2, 0.25f
)
351 .HasExpectedResult(0.1875f
, 1.0f
),
352 EWMATestScenario(0.0f
, kInverseCheckerboard
, 3, 0.25f
)
353 .HasExpectedResult(0.390625f
, 1.0f
),
354 EWMATestScenario(0.0f
, kInverseCheckerboard
, 12, 0.25f
)
355 .HasExpectedResult(0.41499585f
, 1.0f
),
356 EWMATestScenario(0.0f
, kInverseCheckerboard
, 13, 0.25f
)
357 .HasExpectedResult(0.56124689f
, 1.0f
),
358 EWMATestScenario(0.0f
, kInverseCheckerboard
, 14, 0.25f
)
359 .HasExpectedResult(0.42093517f
, 1.0f
),
360 EWMATestScenario(0.0f
, kInverseCheckerboard
, 15, 0.25f
)
361 .HasExpectedResult(0.56570137f
, 1.0f
),
363 // Smoothing factor of 1/4, impluse signal.
364 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
365 .WithImpulse(2.0f
, 0)
366 .HasExpectedResult(0.562500f
, 4.0f
),
367 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
368 .WithImpulse(2.0f
, 1)
369 .HasExpectedResult(0.75f
, 4.0f
),
370 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
371 .WithImpulse(2.0f
, 2)
372 .HasExpectedResult(1.0f
, 4.0f
),
373 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
374 .WithImpulse(2.0f
, 0)
375 .HasExpectedResult(0.00013394f
, 4.0f
),
376 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
377 .WithImpulse(2.0f
, 1)
378 .HasExpectedResult(0.00017858f
, 4.0f
),
379 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
380 .WithImpulse(2.0f
, 2)
381 .HasExpectedResult(0.00023811f
, 4.0f
),
382 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
383 .WithImpulse(2.0f
, 3)
384 .HasExpectedResult(0.00031748f
, 4.0f
)