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

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: Fixes for try server failure. Created 7 years, 3 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
« no previous file with comments | « media/filters/audio_renderer_algorithm.cc ('k') | media/filters/wsola_internals.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <algorithm> // For std::min().
11 #include <cmath> 12 #include <cmath>
13 #include <vector>
12 14
13 #include "base/bind.h" 15 #include "base/bind.h"
14 #include "base/callback.h" 16 #include "base/callback.h"
17 #include "base/memory/scoped_ptr.h"
15 #include "media/base/audio_buffer.h" 18 #include "media/base/audio_buffer.h"
16 #include "media/base/audio_bus.h" 19 #include "media/base/audio_bus.h"
17 #include "media/base/buffers.h" 20 #include "media/base/buffers.h"
18 #include "media/base/channel_layout.h" 21 #include "media/base/channel_layout.h"
19 #include "media/base/test_helpers.h" 22 #include "media/base/test_helpers.h"
20 #include "media/filters/audio_renderer_algorithm.h" 23 #include "media/filters/audio_renderer_algorithm.h"
24 #include "media/filters/wsola_internals.h"
21 #include "testing/gtest/include/gtest/gtest.h" 25 #include "testing/gtest/include/gtest/gtest.h"
22 26
23 namespace media { 27 namespace media {
24 28
25 static const int kFrameSize = 250; 29 static const int kFrameSize = 250;
26 static const int kSamplesPerSecond = 3000; 30 static const int kSamplesPerSecond = 3000;
27 static const SampleFormat kSampleFormat = kSampleFormatS16; 31 static const SampleFormat kSampleFormat = kSampleFormatS16;
32 static const int kOutputDurationInSec = 10;
33
34 static void FillWithSquarePulseTrain(
35 int half_pulse_width, int offset, int num_samples, float* data) {
36 ASSERT_GE(offset, 0);
37 ASSERT_LE(offset, num_samples);
38
39 // Fill backward from |offset| - 1 toward zero, starting with -1, alternating
40 // between -1 and 1 every |pulse_width| samples.
41 float pulse = -1.0f;
42 for (int n = offset - 1, k = 0; n >= 0; --n, ++k) {
43 if (k >= half_pulse_width) {
44 pulse = -pulse;
45 k = 0;
46 }
47 data[n] = pulse;
48 }
49
50 // Fill forward from |offset| towards the end, starting with 1, alternating
51 // between 1 and -1 every |pulse_width| samples.
52 pulse = 1.0f;
53 for (int n = offset, k = 0; n < num_samples; ++n, ++k) {
54 if (k >= half_pulse_width) {
55 pulse = -pulse;
56 k = 0;
57 }
58 data[n] = pulse;
59 }
60 }
61
62 static void FillWithSquarePulseTrain(
63 int half_pulse_width, int offset, int channel, AudioBus* audio_bus) {
64 FillWithSquarePulseTrain(half_pulse_width, offset, audio_bus->frames(),
65 audio_bus->channel(channel));
66 }
28 67
29 class AudioRendererAlgorithmTest : public testing::Test { 68 class AudioRendererAlgorithmTest : public testing::Test {
30 public: 69 public:
31 AudioRendererAlgorithmTest() 70 AudioRendererAlgorithmTest()
32 : frames_enqueued_(0), 71 : frames_enqueued_(0),
33 channels_(0), 72 channels_(0),
34 sample_format_(kUnknownSampleFormat), 73 sample_format_(kUnknownSampleFormat),
35 bytes_per_sample_(0) { 74 bytes_per_sample_(0) {
36 } 75 }
37 76
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 int initial_frames_buffered) { 150 int initial_frames_buffered) {
112 int frame_delta = frames_enqueued_ - initial_frames_enqueued; 151 int frame_delta = frames_enqueued_ - initial_frames_enqueued;
113 int buffered_delta = algorithm_.frames_buffered() - initial_frames_buffered; 152 int buffered_delta = algorithm_.frames_buffered() - initial_frames_buffered;
114 int consumed = frame_delta - buffered_delta; 153 int consumed = frame_delta - buffered_delta;
115 CHECK_GE(consumed, 0); 154 CHECK_GE(consumed, 0);
116 return consumed; 155 return consumed;
117 } 156 }
118 157
119 void TestPlaybackRate(double playback_rate) { 158 void TestPlaybackRate(double playback_rate) {
120 const int kDefaultBufferSize = algorithm_.samples_per_second() / 100; 159 const int kDefaultBufferSize = algorithm_.samples_per_second() / 100;
121 const int kDefaultFramesRequested = 2 * algorithm_.samples_per_second(); 160 const int kDefaultFramesRequested = kOutputDurationInSec *
161 algorithm_.samples_per_second();
122 162
123 TestPlaybackRate( 163 TestPlaybackRate(
124 playback_rate, kDefaultBufferSize, kDefaultFramesRequested); 164 playback_rate, kDefaultBufferSize, kDefaultFramesRequested);
125 } 165 }
126 166
127 void TestPlaybackRate(double playback_rate, 167 void TestPlaybackRate(double playback_rate,
128 int buffer_size_in_frames, 168 int buffer_size_in_frames,
129 int total_frames_requested) { 169 int total_frames_requested) {
130 int initial_frames_enqueued = frames_enqueued_; 170 int initial_frames_enqueued = frames_enqueued_;
131 int initial_frames_buffered = algorithm_.frames_buffered(); 171 int initial_frames_buffered = algorithm_.frames_buffered();
132 algorithm_.SetPlaybackRate(static_cast<float>(playback_rate)); 172 algorithm_.SetPlaybackRate(static_cast<float>(playback_rate));
133 173
134 scoped_ptr<AudioBus> bus = 174 scoped_ptr<AudioBus> bus =
135 AudioBus::Create(channels_, buffer_size_in_frames); 175 AudioBus::Create(channels_, buffer_size_in_frames);
136 if (playback_rate == 0.0) { 176 if (playback_rate == 0.0) {
137 int frames_written = 177 int frames_written =
138 algorithm_.FillBuffer(bus.get(), buffer_size_in_frames); 178 algorithm_.FillBuffer(bus.get(), buffer_size_in_frames);
139 EXPECT_EQ(0, frames_written); 179 EXPECT_EQ(0, frames_written);
140 return; 180 return;
141 } 181 }
142 182
143 int frames_remaining = total_frames_requested; 183 int frames_remaining = total_frames_requested;
184 bool first_fill_buffer = true;
144 while (frames_remaining > 0) { 185 while (frames_remaining > 0) {
145 int frames_requested = std::min(buffer_size_in_frames, frames_remaining); 186 int frames_requested = std::min(buffer_size_in_frames, frames_remaining);
146 int frames_written = algorithm_.FillBuffer(bus.get(), frames_requested); 187 int frames_written = algorithm_.FillBuffer(bus.get(), frames_requested);
147 ASSERT_GT(frames_written, 0) << "Requested: " << frames_requested 188 ASSERT_GT(frames_written, 0) << "Requested: " << frames_requested
148 << ", playing at " << playback_rate; 189 << ", playing at " << playback_rate;
149 CheckFakeData(bus.get(), frames_written); 190
191 // Do not check data if it is first pull out and only one frame written.
192 // The very first frame out of WSOLA is always zero because of
193 // overlap-and-add window, which is zero for the first sample. Therefore,
194 // if at very first buffer-fill only one frame is written, that is zero
195 // which might cause exception in CheckFakeData().
196 if (!first_fill_buffer || frames_written > 1)
197 CheckFakeData(bus.get(), frames_written);
198 first_fill_buffer = false;
150 frames_remaining -= frames_written; 199 frames_remaining -= frames_written;
151 200
152 FillAlgorithmQueue(); 201 FillAlgorithmQueue();
153 } 202 }
154 203
155 int frames_consumed = 204 int frames_consumed =
156 ComputeConsumedFrames(initial_frames_enqueued, initial_frames_buffered); 205 ComputeConsumedFrames(initial_frames_enqueued, initial_frames_buffered);
157 206
158 // If playing back at normal speed, we should always get back the same 207 // If playing back at normal speed, we should always get back the same
159 // number of bytes requested. 208 // number of bytes requested.
160 if (playback_rate == 1.0) { 209 if (playback_rate == 1.0) {
161 EXPECT_EQ(total_frames_requested, frames_consumed); 210 EXPECT_EQ(total_frames_requested, frames_consumed);
162 return; 211 return;
163 } 212 }
164 213
165 // Otherwise, allow |kMaxAcceptableDelta| difference between the target and 214 // Otherwise, allow |kMaxAcceptableDelta| difference between the target and
166 // actual playback rate. 215 // actual playback rate.
167 // When |kSamplesPerSecond| and |total_frames_requested| are reasonably 216 // When |kSamplesPerSecond| and |total_frames_requested| are reasonably
168 // large, one can expect less than a 1% difference in most cases. In our 217 // large, one can expect less than a 1% difference in most cases. In our
169 // current implementation, sped up playback is less accurate than slowed 218 // current implementation, sped up playback is less accurate than slowed
170 // down playback, and for playback_rate > 1, playback rate generally gets 219 // down playback, and for playback_rate > 1, playback rate generally gets
171 // less and less accurate the farther it drifts from 1 (though this is 220 // less and less accurate the farther it drifts from 1 (though this is
172 // nonlinear). 221 // nonlinear).
173 double actual_playback_rate = 222 double actual_playback_rate =
174 1.0 * frames_consumed / total_frames_requested; 223 1.0 * frames_consumed / total_frames_requested;
175 EXPECT_NEAR(playback_rate, actual_playback_rate, playback_rate / 100.0); 224 EXPECT_NEAR(playback_rate, actual_playback_rate, playback_rate / 100.0);
176 } 225 }
177 226
227 void WsolaTest(float playback_rate) {
228 const int kSampleRateHz = 48000;
229 const media::ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
230 const int kBytesPerSample = 2;
231 const int kNumFrames = kSampleRateHz / 100; // 10 milliseconds.
232
233 channels_ = ChannelLayoutToChannelCount(kChannelLayout);
234 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
235 kSampleRateHz, kBytesPerSample * 8, kNumFrames);
236 algorithm_.Initialize(playback_rate, params);
237
238 // A pulse is 6 milliseconds (even number of samples).
239 const int kPulseWidthSamples = 6 * kSampleRateHz / 1000;
240 const int kHalfPulseWidthSamples = kPulseWidthSamples / 2;
241
242 // For the ease of implementation get 1 frame every call to FillBuffer().
243 scoped_ptr<AudioBus> output = AudioBus::Create(channels_, 1);
244
245 // Input buffer to inject pulses.
246 scoped_refptr<AudioBuffer> input = AudioBuffer::CreateBuffer(
247 kSampleFormatPlanarF32, channels_, kPulseWidthSamples);
248
249 const std::vector<uint8*>& channel_data = input->channel_data();
250
251 // Fill |input| channels.
252 FillWithSquarePulseTrain(kHalfPulseWidthSamples, 0, kPulseWidthSamples,
253 reinterpret_cast<float*>(channel_data[0]));
254 FillWithSquarePulseTrain(kHalfPulseWidthSamples, kHalfPulseWidthSamples,
255 kPulseWidthSamples,
256 reinterpret_cast<float*>(channel_data[1]));
257
258 // A buffer for the output until a complete pulse is created. Then
259 // reference pulse is compared with this buffer.
260 scoped_ptr<AudioBus> pulse_buffer = AudioBus::Create(
261 channels_, kPulseWidthSamples);
262
263 const float kTolerance = 0.000001f;
264 // Equivalent of 4 seconds.
265 const int kNumRequestedPulses = kSampleRateHz * 4 / kPulseWidthSamples;
266 for (int n = 0; n < kNumRequestedPulses; ++n) {
267 int num_buffered_frames = 0;
268 while (num_buffered_frames < kPulseWidthSamples) {
269 int num_samples = algorithm_.FillBuffer(output.get(), 1);
270 ASSERT_LE(num_samples, 1);
271 if (num_samples > 0) {
272 output->CopyPartialFramesTo(0, num_samples, num_buffered_frames,
273 pulse_buffer.get());
274 num_buffered_frames++;
275 } else {
276 algorithm_.EnqueueBuffer(input);
277 }
278 }
279
280 // Pulses in the first half of WSOLA AOL frame are not constructed
281 // perfectly. Do not check them.
282 if (n > 3) {
283 for (int m = 0; m < channels_; ++m) {
284 const float* pulse_ch = pulse_buffer->channel(m);
285
286 // Because of overlap-and-add we might have round off error.
287 for (int k = 0; k < kPulseWidthSamples; ++k) {
288 ASSERT_NEAR(reinterpret_cast<float*>(channel_data[m])[k],
289 pulse_ch[k], kTolerance) << " loop " << n
290 << " channel/sample " << m << "/" << k;
291 }
292 }
293 }
294
295 // Zero out the buffer to be sure the next comparison is relevant.
296 pulse_buffer->Zero();
297 }
298 }
299
178 protected: 300 protected:
179 AudioRendererAlgorithm algorithm_; 301 AudioRendererAlgorithm algorithm_;
180 int frames_enqueued_; 302 int frames_enqueued_;
181 int channels_; 303 int channels_;
182 SampleFormat sample_format_; 304 SampleFormat sample_format_;
183 int bytes_per_sample_; 305 int bytes_per_sample_;
184 }; 306 };
185 307
186 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NormalRate) { 308 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NormalRate) {
187 Initialize(); 309 Initialize();
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 TestPlaybackRate(2.1); 385 TestPlaybackRate(2.1);
264 TestPlaybackRate(0.9); 386 TestPlaybackRate(0.9);
265 TestPlaybackRate(0.6); 387 TestPlaybackRate(0.6);
266 TestPlaybackRate(1.4); 388 TestPlaybackRate(1.4);
267 TestPlaybackRate(0.3); 389 TestPlaybackRate(0.3);
268 } 390 }
269 391
270 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) { 392 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) {
271 Initialize(); 393 Initialize();
272 static const int kBufferSizeInFrames = 1; 394 static const int kBufferSizeInFrames = 1;
273 static const int kFramesRequested = 2 * kSamplesPerSecond; 395 static const int kFramesRequested = kOutputDurationInSec * kSamplesPerSecond;
274 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested); 396 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested);
275 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested); 397 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested);
276 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested); 398 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested);
277 } 399 }
278 400
279 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) { 401 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) {
280 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100); 402 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100);
281 TestPlaybackRate(1.0); 403 TestPlaybackRate(1.0);
282 TestPlaybackRate(0.5); 404 TestPlaybackRate(0.5);
283 TestPlaybackRate(1.5); 405 TestPlaybackRate(1.5);
284 } 406 }
285 407
286 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) { 408 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) {
287 Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond); 409 Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond);
288 TestPlaybackRate(1.0); 410 TestPlaybackRate(1.0);
289 TestPlaybackRate(0.5); 411 TestPlaybackRate(0.5);
290 TestPlaybackRate(1.5); 412 TestPlaybackRate(1.5);
291 } 413 }
292 414
293 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) { 415 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) {
294 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond); 416 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond);
295 TestPlaybackRate(1.0); 417 TestPlaybackRate(1.0);
296 TestPlaybackRate(0.5); 418 TestPlaybackRate(0.5);
297 TestPlaybackRate(1.5); 419 TestPlaybackRate(1.5);
298 } 420 }
299 421
422 TEST_F(AudioRendererAlgorithmTest, DotProduct) {
423 const int kChannels = 3;
424 const int kFrames = 20;
425 const int kHalfPulseWidth = 2;
426
427 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
428 scoped_ptr<AudioBus> b = AudioBus::Create(kChannels, kFrames);
429
430 scoped_ptr<float[]> dot_prod(new float[kChannels]);
431
432 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, a.get());
433 FillWithSquarePulseTrain(kHalfPulseWidth, 1, 1, a.get());
434 FillWithSquarePulseTrain(kHalfPulseWidth, 2, 2, a.get());
435
436 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, b.get());
437 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 1, b.get());
438 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 2, b.get());
439
440 internal::MultiChannelDotProduct(a.get(), 0, b.get(), 0, kFrames,
441 dot_prod.get());
442
443 EXPECT_FLOAT_EQ(kFrames, dot_prod[0]);
444 EXPECT_FLOAT_EQ(0, dot_prod[1]);
445 EXPECT_FLOAT_EQ(-kFrames, dot_prod[2]);
446
447 internal::MultiChannelDotProduct(a.get(), 4, b.get(), 8, kFrames / 2,
448 dot_prod.get());
449
450 EXPECT_FLOAT_EQ(kFrames / 2, dot_prod[0]);
451 EXPECT_FLOAT_EQ(0, dot_prod[1]);
452 EXPECT_FLOAT_EQ(-kFrames / 2, dot_prod[2]);
453 }
454
455 TEST_F(AudioRendererAlgorithmTest, MovingBlockEnergy) {
456 const int kChannels = 2;
457 const int kFrames = 20;
458 const int kFramesPerBlock = 3;
459 const int kNumBlocks = kFrames - (kFramesPerBlock - 1);
460 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
461 scoped_ptr<float[]> energies(new float[kChannels * kNumBlocks]);
462 float* ch_left = a->channel(0);
463 float* ch_right = a->channel(1);
464
465 // Fill up both channels.
466 for (int n = 0; n < kFrames; ++n) {
467 ch_left[n] = n;
468 ch_right[n] = kFrames - 1 - n;
469 }
470
471 internal::MultiChannelMovingBlockEnergies(a.get(), kFramesPerBlock,
472 energies.get());
473
474 // Check if the energy of candidate blocks of each channel computed correctly.
475 for (int n = 0; n < kNumBlocks; ++n) {
476 float expected_energy = 0;
477 for (int k = 0; k < kFramesPerBlock; ++k)
478 expected_energy += ch_left[n + k] * ch_left[n + k];
479
480 // Left (first) channel.
481 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n]);
482
483 expected_energy = 0;
484 for (int k = 0; k < kFramesPerBlock; ++k)
485 expected_energy += ch_right[n + k] * ch_right[n + k];
486
487 // Second (right) channel.
488 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n + 1]);
489 }
490 }
491
492 TEST_F(AudioRendererAlgorithmTest, FullAndDecimatedSearch) {
493 const int kFramesInSearchRegion = 12;
494 const int kChannels = 2;
495 float ch_0[] = {
496 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f };
497 float ch_1[] = {
498 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 1.0f, 0.1f, 0.0f, 0.0f };
499 ASSERT_EQ(sizeof(ch_0), sizeof(ch_1));
500 ASSERT_EQ(static_cast<size_t>(kFramesInSearchRegion),
501 sizeof(ch_0) / sizeof(*ch_0));
502 scoped_ptr<AudioBus> search_region = AudioBus::Create(kChannels,
503 kFramesInSearchRegion);
504 float* ch = search_region->channel(0);
505 memcpy(ch, ch_0, sizeof(float) * kFramesInSearchRegion);
506 ch = search_region->channel(1);
507 memcpy(ch, ch_1, sizeof(float) * kFramesInSearchRegion);
508
509 const int kFramePerBlock = 4;
510 float target_0[] = { 1.0f, 1.0f, 1.0f, 0.0f };
511 float target_1[] = { 0.0f, 1.0f, 0.1f, 1.0f };
512 ASSERT_EQ(sizeof(target_0), sizeof(target_1));
513 ASSERT_EQ(static_cast<size_t>(kFramePerBlock),
514 sizeof(target_0) / sizeof(*target_0));
515
516 scoped_ptr<AudioBus> target = AudioBus::Create(kChannels,
517 kFramePerBlock);
518 ch = target->channel(0);
519 memcpy(ch, target_0, sizeof(float) * kFramePerBlock);
520 ch = target->channel(1);
521 memcpy(ch, target_1, sizeof(float) * kFramePerBlock);
522
523 scoped_ptr<float[]> energy_target(new float[kChannels]);
524
525 internal::MultiChannelDotProduct(target.get(), 0, target.get(), 0,
526 kFramePerBlock, energy_target.get());
527
528 ASSERT_EQ(3.f, energy_target[0]);
529 ASSERT_EQ(2.01f, energy_target[1]);
530
531 const int kNumCandidBlocks = kFramesInSearchRegion - (kFramePerBlock - 1);
532 scoped_ptr<float[]> energy_candid_blocks(new float[kNumCandidBlocks *
533 kChannels]);
534
535 internal::MultiChannelMovingBlockEnergies(
536 search_region.get(), kFramePerBlock, energy_candid_blocks.get());
537
538 // Check the energy of the candidate blocks of the first channel.
539 ASSERT_FLOAT_EQ(0, energy_candid_blocks[0]);
540 ASSERT_FLOAT_EQ(0, energy_candid_blocks[2]);
541 ASSERT_FLOAT_EQ(1, energy_candid_blocks[4]);
542 ASSERT_FLOAT_EQ(2, energy_candid_blocks[6]);
543 ASSERT_FLOAT_EQ(3, energy_candid_blocks[8]);
544 ASSERT_FLOAT_EQ(3, energy_candid_blocks[10]);
545 ASSERT_FLOAT_EQ(2, energy_candid_blocks[12]);
546 ASSERT_FLOAT_EQ(1, energy_candid_blocks[14]);
547 ASSERT_FLOAT_EQ(0, energy_candid_blocks[16]);
548
549 // Check the energy of the candidate blocks of the second channel.
550 ASSERT_FLOAT_EQ(0, energy_candid_blocks[1]);
551 ASSERT_FLOAT_EQ(0, energy_candid_blocks[3]);
552 ASSERT_FLOAT_EQ(0, energy_candid_blocks[5]);
553 ASSERT_FLOAT_EQ(0, energy_candid_blocks[7]);
554 ASSERT_FLOAT_EQ(0.01f, energy_candid_blocks[9]);
555 ASSERT_FLOAT_EQ(1.01f, energy_candid_blocks[11]);
556 ASSERT_FLOAT_EQ(1.02f, energy_candid_blocks[13]);
557 ASSERT_FLOAT_EQ(1.02f, energy_candid_blocks[15]);
558 ASSERT_FLOAT_EQ(1.01f, energy_candid_blocks[17]);
559
560 // An interval which is of no effect.
561 internal::Interval exclude_interval = std::make_pair(-100, -10);
562 EXPECT_EQ(5, internal::FullSearch(
563 0, kNumCandidBlocks - 1, exclude_interval, target.get(),
564 search_region.get(), energy_target.get(), energy_candid_blocks.get()));
565
566 // Exclude the the best match.
567 exclude_interval = std::make_pair(2, 5);
568 EXPECT_EQ(7, internal::FullSearch(
569 0, kNumCandidBlocks - 1, exclude_interval, target.get(),
570 search_region.get(), energy_target.get(), energy_candid_blocks.get()));
571
572 // An interval which is of no effect.
573 exclude_interval = std::make_pair(-100, -10);
574 EXPECT_EQ(4, internal::DecimatedSearch(
575 4, exclude_interval, target.get(), search_region.get(),
576 energy_target.get(), energy_candid_blocks.get()));
577
578 EXPECT_EQ(5, internal::OptimalIndex(search_region.get(), target.get(),
579 exclude_interval));
580 }
581
582 TEST_F(AudioRendererAlgorithmTest, CubicInterpolation) {
583 // Arbitrary coefficients.
584 const float kA = 0.7f;
585 const float kB = 1.2f;
586 const float kC = 0.8f;
587
588 float y_values[3];
589 y_values[0] = kA - kB + kC;
590 y_values[1] = kC;
591 y_values[2] = kA + kB + kC;
592
593 float extremum;
594 float extremum_value;
595
596 internal::CubicInterpolation(y_values, &extremum, &extremum_value);
597
598 float x_star = -kB / (2.f * kA);
599 float y_star = kA * x_star * x_star + kB * x_star + kC;
600
601 EXPECT_FLOAT_EQ(x_star, extremum);
602 EXPECT_FLOAT_EQ(y_star, extremum_value);
603 }
604
605 TEST_F(AudioRendererAlgorithmTest, WsolaSlowdown) {
606 WsolaTest(0.6f);
607 }
608
609 TEST_F(AudioRendererAlgorithmTest, WsolaSpeedup) {
610 WsolaTest(1.6f);
611 }
612
300 } // namespace media 613 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/audio_renderer_algorithm.cc ('k') | media/filters/wsola_internals.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698