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
10 #include "base/memory/aligned_memory.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringize_macros.h"
14 #include "media/base/vector_math.h"
15 #include "media/base/vector_math_testing.h"
16 #include "testing/gtest/include/gtest/gtest.h"
22 // Default test values.
23 static const float kScale
= 0.5;
24 static const float kInputFillValue
= 1.0;
25 static const float kOutputFillValue
= 3.0;
26 static const int kVectorSize
= 8192;
28 class VectorMathTest
: public testing::Test
{
32 // Initialize input and output vectors.
33 input_vector_
.reset(static_cast<float*>(base::AlignedAlloc(
34 sizeof(float) * kVectorSize
, vector_math::kRequiredAlignment
)));
35 output_vector_
.reset(static_cast<float*>(base::AlignedAlloc(
36 sizeof(float) * kVectorSize
, vector_math::kRequiredAlignment
)));
39 void FillTestVectors(float input
, float output
) {
40 // Setup input and output vectors.
41 fill(input_vector_
.get(), input_vector_
.get() + kVectorSize
, input
);
42 fill(output_vector_
.get(), output_vector_
.get() + kVectorSize
, output
);
45 void VerifyOutput(float value
) {
46 for (int i
= 0; i
< kVectorSize
; ++i
)
47 ASSERT_FLOAT_EQ(output_vector_
[i
], value
);
51 scoped_ptr
<float[], base::AlignedFreeDeleter
> input_vector_
;
52 scoped_ptr
<float[], base::AlignedFreeDeleter
> output_vector_
;
54 DISALLOW_COPY_AND_ASSIGN(VectorMathTest
);
57 // Ensure each optimized vector_math::FMAC() method returns the same value.
58 TEST_F(VectorMathTest
, FMAC
) {
59 static const float kResult
= kInputFillValue
* kScale
+ kOutputFillValue
;
63 FillTestVectors(kInputFillValue
, kOutputFillValue
);
65 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
66 VerifyOutput(kResult
);
70 SCOPED_TRACE("FMAC_C");
71 FillTestVectors(kInputFillValue
, kOutputFillValue
);
73 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
74 VerifyOutput(kResult
);
77 #if defined(ARCH_CPU_X86_FAMILY)
79 ASSERT_TRUE(base::CPU().has_sse());
80 SCOPED_TRACE("FMAC_SSE");
81 FillTestVectors(kInputFillValue
, kOutputFillValue
);
82 vector_math::FMAC_SSE(
83 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
84 VerifyOutput(kResult
);
88 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
90 SCOPED_TRACE("FMAC_NEON");
91 FillTestVectors(kInputFillValue
, kOutputFillValue
);
92 vector_math::FMAC_NEON(
93 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
94 VerifyOutput(kResult
);
99 // Ensure each optimized vector_math::FMUL() method returns the same value.
100 TEST_F(VectorMathTest
, FMUL
) {
101 static const float kResult
= kInputFillValue
* kScale
;
104 SCOPED_TRACE("FMUL");
105 FillTestVectors(kInputFillValue
, kOutputFillValue
);
107 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
108 VerifyOutput(kResult
);
112 SCOPED_TRACE("FMUL_C");
113 FillTestVectors(kInputFillValue
, kOutputFillValue
);
115 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
116 VerifyOutput(kResult
);
119 #if defined(ARCH_CPU_X86_FAMILY)
121 ASSERT_TRUE(base::CPU().has_sse());
122 SCOPED_TRACE("FMUL_SSE");
123 FillTestVectors(kInputFillValue
, kOutputFillValue
);
124 vector_math::FMUL_SSE(
125 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
126 VerifyOutput(kResult
);
130 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
132 SCOPED_TRACE("FMUL_NEON");
133 FillTestVectors(kInputFillValue
, kOutputFillValue
);
134 vector_math::FMUL_NEON(
135 input_vector_
.get(), kScale
, kVectorSize
, output_vector_
.get());
136 VerifyOutput(kResult
);
141 TEST_F(VectorMathTest
, Crossfade
) {
142 FillTestVectors(0, 1);
143 vector_math::Crossfade(
144 input_vector_
.get(), kVectorSize
, output_vector_
.get());
145 for (int i
= 0; i
< kVectorSize
; ++i
) {
146 ASSERT_FLOAT_EQ(i
/ static_cast<float>(kVectorSize
), output_vector_
[i
])
151 class EWMATestScenario
{
153 EWMATestScenario(float initial_value
, const float src
[], int len
,
154 float smoothing_factor
)
155 : initial_value_(initial_value
),
156 data_(static_cast<float*>(
158 base::AlignedAlloc(len
* sizeof(float),
159 vector_math::kRequiredAlignment
))),
161 smoothing_factor_(smoothing_factor
),
162 expected_final_avg_(initial_value
),
163 expected_max_(0.0f
) {
165 memcpy(data_
.get(), src
, len
* sizeof(float));
168 // Copy constructor and assignment operator for ::testing::Values(...).
169 EWMATestScenario(const EWMATestScenario
& other
) { *this = other
; }
170 EWMATestScenario
& operator=(const EWMATestScenario
& other
) {
171 this->initial_value_
= other
.initial_value_
;
172 this->smoothing_factor_
= other
.smoothing_factor_
;
173 if (other
.data_len_
== 0) {
176 this->data_
.reset(static_cast<float*>(
177 base::AlignedAlloc(other
.data_len_
* sizeof(float),
178 vector_math::kRequiredAlignment
)));
179 memcpy(this->data_
.get(), other
.data_
.get(),
180 other
.data_len_
* sizeof(float));
182 this->data_len_
= other
.data_len_
;
183 this->expected_final_avg_
= other
.expected_final_avg_
;
184 this->expected_max_
= other
.expected_max_
;
188 EWMATestScenario
ScaledBy(float scale
) const {
189 EWMATestScenario
result(*this);
190 float* p
= result
.data_
.get();
191 float* const p_end
= p
+ result
.data_len_
;
192 for (; p
< p_end
; ++p
)
197 EWMATestScenario
WithImpulse(float value
, int offset
) const {
198 EWMATestScenario
result(*this);
199 result
.data_
.get()[offset
] = value
;
203 EWMATestScenario
HasExpectedResult(float final_avg_value
,
204 float max_value
) const {
205 EWMATestScenario
result(*this);
206 result
.expected_final_avg_
= final_avg_value
;
207 result
.expected_max_
= max_value
;
211 void RunTest() const {
213 SCOPED_TRACE("EWMAAndMaxPower");
214 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower(
215 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
216 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
217 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
221 SCOPED_TRACE("EWMAAndMaxPower_C");
222 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_C(
223 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
224 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
225 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
228 #if defined(ARCH_CPU_X86_FAMILY)
230 ASSERT_TRUE(base::CPU().has_sse());
231 SCOPED_TRACE("EWMAAndMaxPower_SSE");
232 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_SSE(
233 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
234 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
235 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
239 #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
241 SCOPED_TRACE("EWMAAndMaxPower_NEON");
242 const std::pair
<float, float>& result
= vector_math::EWMAAndMaxPower_NEON(
243 initial_value_
, data_
.get(), data_len_
, smoothing_factor_
);
244 EXPECT_NEAR(expected_final_avg_
, result
.first
, 0.0000001f
);
245 EXPECT_NEAR(expected_max_
, result
.second
, 0.0000001f
);
251 float initial_value_
;
252 scoped_ptr
<float, base::AlignedFreeDeleter
> data_
;
254 float smoothing_factor_
;
255 float expected_final_avg_
;
259 typedef testing::TestWithParam
<EWMATestScenario
> VectorMathEWMAAndMaxPowerTest
;
261 TEST_P(VectorMathEWMAAndMaxPowerTest
, Correctness
) {
262 GetParam().RunTest();
265 static const float kZeros
[] = { // 32 zeros
266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
270 static const float kOnes
[] = { // 32 ones
271 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
272 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
275 static const float kCheckerboard
[] = { // 32 alternating 0, 1
276 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
277 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
280 static const float kInverseCheckerboard
[] = { // 32 alternating 1, 0
281 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
282 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
285 INSTANTIATE_TEST_CASE_P(
286 Scenarios
, VectorMathEWMAAndMaxPowerTest
,
288 // Zero-length input: Result should equal initial value.
289 EWMATestScenario(0.0f
, NULL
, 0, 0.0f
).HasExpectedResult(0.0f
, 0.0f
),
290 EWMATestScenario(1.0f
, NULL
, 0, 0.0f
).HasExpectedResult(1.0f
, 0.0f
),
292 // Smoothing factor of zero: Samples have no effect on result.
293 EWMATestScenario(0.0f
, kOnes
, 32, 0.0f
).HasExpectedResult(0.0f
, 1.0f
),
294 EWMATestScenario(1.0f
, kZeros
, 32, 0.0f
).HasExpectedResult(1.0f
, 0.0f
),
296 // Smothing factor of one: Result = last sample squared.
297 EWMATestScenario(0.0f
, kCheckerboard
, 32, 1.0f
)
299 .HasExpectedResult(4.0f
, 4.0f
),
300 EWMATestScenario(1.0f
, kInverseCheckerboard
, 32, 1.0f
)
302 .HasExpectedResult(0.0f
, 4.0f
),
304 // Smoothing factor of 1/4, muted signal.
305 EWMATestScenario(1.0f
, kZeros
, 1, 0.25f
)
306 .HasExpectedResult(powf(0.75, 1.0f
), 0.0f
),
307 EWMATestScenario(1.0f
, kZeros
, 2, 0.25f
)
308 .HasExpectedResult(powf(0.75, 2.0f
), 0.0f
),
309 EWMATestScenario(1.0f
, kZeros
, 3, 0.25f
)
310 .HasExpectedResult(powf(0.75, 3.0f
), 0.0f
),
311 EWMATestScenario(1.0f
, kZeros
, 12, 0.25f
)
312 .HasExpectedResult(powf(0.75, 12.0f
), 0.0f
),
313 EWMATestScenario(1.0f
, kZeros
, 13, 0.25f
)
314 .HasExpectedResult(powf(0.75, 13.0f
), 0.0f
),
315 EWMATestScenario(1.0f
, kZeros
, 14, 0.25f
)
316 .HasExpectedResult(powf(0.75, 14.0f
), 0.0f
),
317 EWMATestScenario(1.0f
, kZeros
, 15, 0.25f
)
318 .HasExpectedResult(powf(0.75, 15.0f
), 0.0f
),
320 // Smoothing factor of 1/4, constant full-amplitude signal.
321 EWMATestScenario(0.0f
, kOnes
, 1, 0.25f
).HasExpectedResult(0.25f
, 1.0f
),
322 EWMATestScenario(0.0f
, kOnes
, 2, 0.25f
)
323 .HasExpectedResult(0.4375f
, 1.0f
),
324 EWMATestScenario(0.0f
, kOnes
, 3, 0.25f
)
325 .HasExpectedResult(0.578125f
, 1.0f
),
326 EWMATestScenario(0.0f
, kOnes
, 12, 0.25f
)
327 .HasExpectedResult(0.96832365f
, 1.0f
),
328 EWMATestScenario(0.0f
, kOnes
, 13, 0.25f
)
329 .HasExpectedResult(0.97624274f
, 1.0f
),
330 EWMATestScenario(0.0f
, kOnes
, 14, 0.25f
)
331 .HasExpectedResult(0.98218205f
, 1.0f
),
332 EWMATestScenario(0.0f
, kOnes
, 15, 0.25f
)
333 .HasExpectedResult(0.98663654f
, 1.0f
),
335 // Smoothing factor of 1/4, checkerboard signal.
336 EWMATestScenario(0.0f
, kCheckerboard
, 1, 0.25f
)
337 .HasExpectedResult(0.0f
, 0.0f
),
338 EWMATestScenario(0.0f
, kCheckerboard
, 2, 0.25f
)
339 .HasExpectedResult(0.25f
, 1.0f
),
340 EWMATestScenario(0.0f
, kCheckerboard
, 3, 0.25f
)
341 .HasExpectedResult(0.1875f
, 1.0f
),
342 EWMATestScenario(0.0f
, kCheckerboard
, 12, 0.25f
)
343 .HasExpectedResult(0.55332780f
, 1.0f
),
344 EWMATestScenario(0.0f
, kCheckerboard
, 13, 0.25f
)
345 .HasExpectedResult(0.41499585f
, 1.0f
),
346 EWMATestScenario(0.0f
, kCheckerboard
, 14, 0.25f
)
347 .HasExpectedResult(0.56124689f
, 1.0f
),
348 EWMATestScenario(0.0f
, kCheckerboard
, 15, 0.25f
)
349 .HasExpectedResult(0.42093517f
, 1.0f
),
351 // Smoothing factor of 1/4, inverse checkerboard signal.
352 EWMATestScenario(0.0f
, kInverseCheckerboard
, 1, 0.25f
)
353 .HasExpectedResult(0.25f
, 1.0f
),
354 EWMATestScenario(0.0f
, kInverseCheckerboard
, 2, 0.25f
)
355 .HasExpectedResult(0.1875f
, 1.0f
),
356 EWMATestScenario(0.0f
, kInverseCheckerboard
, 3, 0.25f
)
357 .HasExpectedResult(0.390625f
, 1.0f
),
358 EWMATestScenario(0.0f
, kInverseCheckerboard
, 12, 0.25f
)
359 .HasExpectedResult(0.41499585f
, 1.0f
),
360 EWMATestScenario(0.0f
, kInverseCheckerboard
, 13, 0.25f
)
361 .HasExpectedResult(0.56124689f
, 1.0f
),
362 EWMATestScenario(0.0f
, kInverseCheckerboard
, 14, 0.25f
)
363 .HasExpectedResult(0.42093517f
, 1.0f
),
364 EWMATestScenario(0.0f
, kInverseCheckerboard
, 15, 0.25f
)
365 .HasExpectedResult(0.56570137f
, 1.0f
),
367 // Smoothing factor of 1/4, impluse signal.
368 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
369 .WithImpulse(2.0f
, 0)
370 .HasExpectedResult(0.562500f
, 4.0f
),
371 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
372 .WithImpulse(2.0f
, 1)
373 .HasExpectedResult(0.75f
, 4.0f
),
374 EWMATestScenario(0.0f
, kZeros
, 3, 0.25f
)
375 .WithImpulse(2.0f
, 2)
376 .HasExpectedResult(1.0f
, 4.0f
),
377 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
378 .WithImpulse(2.0f
, 0)
379 .HasExpectedResult(0.00013394f
, 4.0f
),
380 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
381 .WithImpulse(2.0f
, 1)
382 .HasExpectedResult(0.00017858f
, 4.0f
),
383 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
384 .WithImpulse(2.0f
, 2)
385 .HasExpectedResult(0.00023811f
, 4.0f
),
386 EWMATestScenario(0.0f
, kZeros
, 32, 0.25f
)
387 .WithImpulse(2.0f
, 3)
388 .HasExpectedResult(0.00031748f
, 4.0f
)