Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: media/filters/audio_renderer_algorithm_unittest.cc

Issue 19111004: Upgrade AudioRendererAlgorithm to use WSOLA, (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // The format of these tests are to enqueue a known amount of data and then 5 // The format of these tests are to enqueue a known amount of data and then
6 // request the exact amount we expect in order to dequeue the known amount of 6 // request the exact amount we expect in order to dequeue the known amount of
7 // data. This ensures that for any rate we are consuming input data at the 7 // data. This ensures that for any rate we are consuming input data at the
8 // correct rate. We always pass in a very large destination buffer with the 8 // correct rate. We always pass in a very large destination buffer with the
9 // expectation that FillBuffer() will fill as much as it can but no more. 9 // expectation that FillBuffer() will fill as much as it can but no more.
10 10
11 #include <cmath> 11 #include <cmath>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/callback.h" 14 #include "base/callback.h"
15 #include "base/memory/scoped_ptr.h"
15 #include "media/base/audio_buffer.h" 16 #include "media/base/audio_buffer.h"
16 #include "media/base/audio_bus.h" 17 #include "media/base/audio_bus.h"
17 #include "media/base/buffers.h" 18 #include "media/base/buffers.h"
18 #include "media/base/channel_layout.h" 19 #include "media/base/channel_layout.h"
19 #include "media/base/test_helpers.h" 20 #include "media/base/test_helpers.h"
20 #include "media/filters/audio_renderer_algorithm.h" 21 #include "media/filters/audio_renderer_algorithm.h"
22 #include "media/filters/audio_renderer_algorithm_util.h"
21 #include "testing/gtest/include/gtest/gtest.h" 23 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace media { 24 namespace media {
24 25
25 static const int kFrameSize = 250; 26 static const int kFrameSize = 250;
26 static const int kSamplesPerSecond = 3000; 27 static const int kSamplesPerSecond = 3000;
27 static const SampleFormat kSampleFormat = kSampleFormatS16; 28 static const SampleFormat kSampleFormat = kSampleFormatS16;
29 static const int kOutputDurationInSec = 10;
30
31 static void FillWithSquarePuleTrain(
ajm 2013/07/23 18:03:28 Pule -> Pulse
turaj 2013/07/29 22:09:57 Done.
32 int pulse_width, int offset, int channel, AudioBus* audio_bus) {
33 float* ch = audio_bus->channel(channel);
34
35 // Fill backward from |offset| - 1 toward zero, starting with -1, alternating
36 // between -1 and 1 every |pulse_width| samples.
37 int pulse = -1;
38 for (int n = offset - 1, k = 0; n >= 0; --n, ++k) {
39 if (k >= pulse_width) {
40 pulse = -pulse;
41 k = 0;
42 }
43 ch[n] = pulse;
44 }
45
46 // Fill forward from |offset| towards the end, starting with 1, alternating
47 // between 1 and -1 every |pulse_width| samples.
48 pulse = 1;
49 for (int n = offset, k = 0; n < audio_bus->frames(); ++n, ++k) {
50 if (k >= pulse_width) {
51 pulse = -pulse;
52 k = 0;
53 }
54 ch[n] = pulse;
55 }
56 }
57
28 58
29 class AudioRendererAlgorithmTest : public testing::Test { 59 class AudioRendererAlgorithmTest : public testing::Test {
30 public: 60 public:
31 AudioRendererAlgorithmTest() 61 AudioRendererAlgorithmTest()
32 : frames_enqueued_(0), 62 : frames_enqueued_(0),
33 channels_(0), 63 channels_(0),
34 sample_format_(kUnknownSampleFormat), 64 sample_format_(kUnknownSampleFormat),
35 bytes_per_sample_(0) { 65 bytes_per_sample_(0) {
36 } 66 }
37 67
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 int initial_frames_buffered) { 141 int initial_frames_buffered) {
112 int frame_delta = frames_enqueued_ - initial_frames_enqueued; 142 int frame_delta = frames_enqueued_ - initial_frames_enqueued;
113 int buffered_delta = algorithm_.frames_buffered() - initial_frames_buffered; 143 int buffered_delta = algorithm_.frames_buffered() - initial_frames_buffered;
114 int consumed = frame_delta - buffered_delta; 144 int consumed = frame_delta - buffered_delta;
115 CHECK_GE(consumed, 0); 145 CHECK_GE(consumed, 0);
116 return consumed; 146 return consumed;
117 } 147 }
118 148
119 void TestPlaybackRate(double playback_rate) { 149 void TestPlaybackRate(double playback_rate) {
120 const int kDefaultBufferSize = algorithm_.samples_per_second() / 100; 150 const int kDefaultBufferSize = algorithm_.samples_per_second() / 100;
121 const int kDefaultFramesRequested = 2 * algorithm_.samples_per_second(); 151 const int kDefaultFramesRequested = kOutputDurationInSec *
152 algorithm_.samples_per_second();
122 153
123 TestPlaybackRate( 154 TestPlaybackRate(
124 playback_rate, kDefaultBufferSize, kDefaultFramesRequested); 155 playback_rate, kDefaultBufferSize, kDefaultFramesRequested);
125 } 156 }
126 157
127 void TestPlaybackRate(double playback_rate, 158 void TestPlaybackRate(double playback_rate,
128 int buffer_size_in_frames, 159 int buffer_size_in_frames,
129 int total_frames_requested) { 160 int total_frames_requested) {
130 int initial_frames_enqueued = frames_enqueued_; 161 int initial_frames_enqueued = frames_enqueued_;
131 int initial_frames_buffered = algorithm_.frames_buffered(); 162 int initial_frames_buffered = algorithm_.frames_buffered();
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 TestPlaybackRate(2.1); 294 TestPlaybackRate(2.1);
264 TestPlaybackRate(0.9); 295 TestPlaybackRate(0.9);
265 TestPlaybackRate(0.6); 296 TestPlaybackRate(0.6);
266 TestPlaybackRate(1.4); 297 TestPlaybackRate(1.4);
267 TestPlaybackRate(0.3); 298 TestPlaybackRate(0.3);
268 } 299 }
269 300
270 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) { 301 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) {
271 Initialize(); 302 Initialize();
272 static const int kBufferSizeInFrames = 1; 303 static const int kBufferSizeInFrames = 1;
273 static const int kFramesRequested = 2 * kSamplesPerSecond; 304 static const int kFramesRequested = kOutputDurationInSec * kSamplesPerSecond;
274 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested); 305 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested);
275 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested); 306 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested);
276 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested); 307 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested);
277 } 308 }
278 309
279 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) { 310 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) {
280 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100); 311 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100);
281 TestPlaybackRate(1.0); 312 TestPlaybackRate(1.0);
282 TestPlaybackRate(0.5); 313 TestPlaybackRate(0.5);
283 TestPlaybackRate(1.5); 314 TestPlaybackRate(1.5);
284 } 315 }
285 316
286 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) { 317 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) {
287 Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond); 318 Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond);
288 TestPlaybackRate(1.0); 319 TestPlaybackRate(1.0);
289 TestPlaybackRate(0.5); 320 TestPlaybackRate(0.5);
290 TestPlaybackRate(1.5); 321 TestPlaybackRate(1.5);
291 } 322 }
292 323
293 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) { 324 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) {
294 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond); 325 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond);
295 TestPlaybackRate(1.0); 326 TestPlaybackRate(1.0);
296 TestPlaybackRate(0.5); 327 TestPlaybackRate(0.5);
297 TestPlaybackRate(1.5); 328 TestPlaybackRate(1.5);
298 } 329 }
299 330
331 TEST_F(AudioRendererAlgorithmTest, DotProduct) {
332 const int kChannels = 3;
333 const int kFrames = 20;
334 const int kPulseWidth = 2;
335
336 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
337 scoped_ptr<AudioBus> b = AudioBus::Create(kChannels, kFrames);
338
339 scoped_ptr<float[]> dot_prod(new float[kChannels]);
340
341 FillWithSquarePuleTrain(kPulseWidth, 0, 0, a.get());
342 FillWithSquarePuleTrain(kPulseWidth, 1, 1, a.get());
343 FillWithSquarePuleTrain(kPulseWidth, 2, 2, a.get());
344
345 FillWithSquarePuleTrain(kPulseWidth, 0, 0, b.get());
346 FillWithSquarePuleTrain(kPulseWidth, 0, 1, b.get());
347 FillWithSquarePuleTrain(kPulseWidth, 0, 2, b.get());
348
349 MultiChannelDotProduct(a.get(), 0, b.get(), 0, kFrames, dot_prod.get());
350
351 EXPECT_FLOAT_EQ(kFrames, dot_prod[0]);
352 EXPECT_FLOAT_EQ(0, dot_prod[1]);
353 EXPECT_FLOAT_EQ(-kFrames, dot_prod[2]);
354
355 MultiChannelDotProduct(a.get(), 4, b.get(), 8, kFrames / 2, dot_prod.get());
356
357 EXPECT_FLOAT_EQ(kFrames / 2, dot_prod[0]);
358 EXPECT_FLOAT_EQ(0, dot_prod[1]);
359 EXPECT_FLOAT_EQ(-kFrames / 2, dot_prod[2]);
360 }
361
362 TEST_F(AudioRendererAlgorithmTest, MovingWindowEnergy) {
363 const int kChannels = 2;
364 const int kFrames = 20;
365 const int kFramesPerBlock = 3;
366 const int kNumBlocks = kFrames - (kFramesPerBlock - 1);
367 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
368 scoped_ptr<float[]> energies(new float[kChannels * kNumBlocks]);
369 float* ch_left = a->channel(0);
370 float* ch_right = a->channel(1);
371
372 // Fill up both channels.
373 for (int n = 0; n < kFrames; ++n) {
374 ch_left[n] = n;
375 ch_right[n] = kFrames - 1 - n;
376 }
377
378 MultiChannelMovingWindowEnergies(a.get(), kFramesPerBlock, energies.get());
379
380 for (int n = 0; n < kNumBlocks; ++n) {
381 float expected_energy = 0;
382 for (int k = 0; k < kFramesPerBlock; ++k)
383 expected_energy += ch_left[n + k] * ch_left[n + k];
384 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n]);
385
386 expected_energy = 0;
387 for (int k = 0; k < kFramesPerBlock; ++k)
388 expected_energy += ch_right[n + k] * ch_right[n + k];
389 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n + 1]);
390 }
391 }
392
393 TEST_F(AudioRendererAlgorithmTest, PartialAndDecimatedSearch) {
394 const int kFramesInSearchRegion = 12;
395 const int kChannels = 2;
396 float ch_0[] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0};
397 float ch_1[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 1.0, 0.1, 0.0, 0.0};
398 ASSERT_EQ(sizeof(ch_0), sizeof(ch_1));
399 ASSERT_EQ(static_cast<size_t>(kFramesInSearchRegion),
400 sizeof(ch_0) / sizeof(*ch_0));
401 scoped_ptr<AudioBus> search_region = AudioBus::CreateWrapper(kChannels);
402
403 search_region->SetChannelData(0, ch_0);
404 search_region->SetChannelData(1, ch_1);
405 search_region->set_frames(kFramesInSearchRegion);
406 ASSERT_EQ(kFramesInSearchRegion, search_region->frames());
407
408 const int kFramePerBlock = 4;
409 float target_0[] = {1.0, 1.0, 1.0, 0.0};
410 float target_1[] = {0.0, 1.0, 0.1, 1.0};
411 ASSERT_EQ(sizeof(target_0), sizeof(target_1));
412 ASSERT_EQ(static_cast<size_t>(kFramePerBlock),
413 sizeof(target_0) / sizeof(*target_0));
414
415 scoped_ptr<AudioBus> target = AudioBus::CreateWrapper(2);
416 target->SetChannelData(0, target_0);
417 target->SetChannelData(1, target_1);
418 target->set_frames(kFramePerBlock);
419 ASSERT_EQ(kFramePerBlock, target->frames());
420
421 scoped_ptr<float[]> energy_target(new float[kChannels]);
422
423 MultiChannelDotProduct(target.get(), 0, target.get(), 0, kFramePerBlock,
424 energy_target.get());
425
426 ASSERT_EQ(3.f, energy_target[0]);
427 ASSERT_EQ(2.01f, energy_target[1]);
428
429 const int kNumCandidBlocks = kFramesInSearchRegion - (kFramePerBlock - 1);
430 scoped_ptr<float[]> energy_candid_blocks(new float[kNumCandidBlocks *
431 kChannels]);
432
433 MultiChannelMovingWindowEnergies(search_region.get(), kFramePerBlock,
434 energy_candid_blocks.get());
435
436 ASSERT_FLOAT_EQ(0, energy_candid_blocks[0]);
437 ASSERT_FLOAT_EQ(0, energy_candid_blocks[2]);
438 ASSERT_FLOAT_EQ(1, energy_candid_blocks[4]);
439 ASSERT_FLOAT_EQ(2, energy_candid_blocks[6]);
440 ASSERT_FLOAT_EQ(3, energy_candid_blocks[8]);
441 ASSERT_FLOAT_EQ(3, energy_candid_blocks[10]);
442 ASSERT_FLOAT_EQ(2, energy_candid_blocks[12]);
443 ASSERT_FLOAT_EQ(1, energy_candid_blocks[14]);
444 ASSERT_FLOAT_EQ(0, energy_candid_blocks[16]);
445
446 ASSERT_FLOAT_EQ(0, energy_candid_blocks[1]);
447 ASSERT_FLOAT_EQ(0, energy_candid_blocks[3]);
448 ASSERT_FLOAT_EQ(0, energy_candid_blocks[5]);
449 ASSERT_FLOAT_EQ(0, energy_candid_blocks[7]);
450 ASSERT_FLOAT_EQ(0.01, energy_candid_blocks[9]);
451 ASSERT_FLOAT_EQ(1.01, energy_candid_blocks[11]);
452 ASSERT_FLOAT_EQ(1.02, energy_candid_blocks[13]);
453 ASSERT_FLOAT_EQ(1.02, energy_candid_blocks[15]);
454 ASSERT_FLOAT_EQ(1.01, energy_candid_blocks[17]);
455
456 // An interval which is of no effect.
457 interval exclude_interval = std::make_pair(-100, -10);
458 EXPECT_EQ(5, PartialSearch(0, kNumCandidBlocks - 1, exclude_interval,
459 target.get(), search_region.get(),
460 energy_target.get(), energy_candid_blocks.get()));
461
462 // Exclude the the best match.
463 exclude_interval = std::make_pair(2, 5);
464 EXPECT_EQ(7, PartialSearch(0, kNumCandidBlocks - 1, exclude_interval,
465 target.get(), search_region.get(),
466 energy_target.get(), energy_candid_blocks.get()));
467
468 // An interval which is of no effect.
469 exclude_interval = std::make_pair(-100, -10);
470 EXPECT_EQ(4, DecimatedSearch(4, exclude_interval, target.get(),
471 search_region.get(), energy_target.get(),
472 energy_candid_blocks.get()));
473
474 EXPECT_EQ(5, OptimalIndex(search_region.get(), target.get(),
475 exclude_interval));
476 }
477
478 TEST_F(AudioRendererAlgorithmTest, CubicInterpolation) {
479 // Arbitrary coefficients.
480 const float kA = 0.7;
481 const float kB = 1.2;
482 const float kC = 0.8;
483
484 float y_values[3];
485 y_values[0] = kA - kB + kC;
486 y_values[1] = kC;
487 y_values[2] = kA + kB + kC;
488
489 float extremum;
490 float extremum_value;
491
492 CubicInterpol(y_values, &extremum, &extremum_value);
493
494 float x_star = -kB / (2.f * kA);
495 float y_star = kA * x_star * x_star + kB * x_star + kC;
496
497 EXPECT_FLOAT_EQ(x_star, extremum);
498 EXPECT_FLOAT_EQ(y_star, extremum_value);
499 }
500
300 } // namespace media 501 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698