OLD | NEW |
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 Loading... |
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(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 // large, one can expect less than a 1% difference in most cases. In our | 208 // 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 | 209 // current implementation, sped up playback is less accurate than slowed |
170 // down playback, and for playback_rate > 1, playback rate generally gets | 210 // 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 | 211 // less and less accurate the farther it drifts from 1 (though this is |
172 // nonlinear). | 212 // nonlinear). |
173 double actual_playback_rate = | 213 double actual_playback_rate = |
174 1.0 * frames_consumed / total_frames_requested; | 214 1.0 * frames_consumed / total_frames_requested; |
175 EXPECT_NEAR(playback_rate, actual_playback_rate, playback_rate / 100.0); | 215 EXPECT_NEAR(playback_rate, actual_playback_rate, playback_rate / 100.0); |
176 } | 216 } |
177 | 217 |
| 218 void WsolaTest(float playback_rate) { |
| 219 const int kSampleRateHz = 48000; |
| 220 const media::ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; |
| 221 const int kBytesPerSample = 2; |
| 222 const int kNumFrames = kSampleRateHz / 100; // 10 milliseconds. |
| 223 |
| 224 channels_ = ChannelLayoutToChannelCount(kChannelLayout); |
| 225 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
| 226 kSampleRateHz, kBytesPerSample * 8, kNumFrames); |
| 227 algorithm_.Initialize(playback_rate, params); |
| 228 |
| 229 // A pulse is 6 milliseconds (even number of samples). |
| 230 const int kPulseWidthSamples = 6 * kSampleRateHz / 1000; |
| 231 const int kHalfPulseWidthSamples = kPulseWidthSamples / 2; |
| 232 |
| 233 // For the ease of implementation get 1 frame every call to FillBuffer(). |
| 234 scoped_ptr<AudioBus> output = AudioBus::Create(channels_, 1); |
| 235 |
| 236 // Input buffer to inject pulses. |
| 237 scoped_refptr<AudioBuffer> input = AudioBuffer::CreateBuffer( |
| 238 kSampleFormatPlanarF32, channels_, kPulseWidthSamples); |
| 239 |
| 240 std::vector<uint8_t*> channel_data = input->channel_data(); |
| 241 |
| 242 // Fill |input| channels. |
| 243 FillWithSquarePulseTrain(kHalfPulseWidthSamples, 0, kPulseWidthSamples, |
| 244 reinterpret_cast<float*>(channel_data[0])); |
| 245 FillWithSquarePulseTrain(kHalfPulseWidthSamples, kHalfPulseWidthSamples, |
| 246 kPulseWidthSamples, |
| 247 reinterpret_cast<float*>(channel_data[1])); |
| 248 |
| 249 // A buffer for the output until a complete pulse is created. Then |
| 250 // reference pulse is compared with this buffer. |
| 251 scoped_ptr<AudioBus> pulse_buffer = AudioBus::Create( |
| 252 channels_, kPulseWidthSamples); |
| 253 |
| 254 float kTolerance = 0.0001f; |
| 255 // Equivalent of 4 seconds. |
| 256 const int kNumRequestedPulses = kSampleRateHz * 4 / kPulseWidthSamples; |
| 257 for (int n = 0; n < kNumRequestedPulses; ++n) { |
| 258 int num_buffered_frames = 0; |
| 259 while (num_buffered_frames < kPulseWidthSamples) { |
| 260 int num_samples = algorithm_.FillBuffer(output.get(), 1); |
| 261 ASSERT_LE(num_samples, 1); |
| 262 if (num_samples > 0) { |
| 263 output->CopyPartialFramesTo(0, num_samples, num_buffered_frames, |
| 264 pulse_buffer.get()); |
| 265 num_buffered_frames++; |
| 266 } else { |
| 267 algorithm_.EnqueueBuffer(input); |
| 268 } |
| 269 } |
| 270 |
| 271 // Pulses in the first half of WSOLA AOL frame are not constructed |
| 272 // perfectly. Do not check them. |
| 273 if (n > 3) { |
| 274 for (int m = 0; m < channels_; ++m) { |
| 275 const float* pulse_ch = pulse_buffer->channel(m); |
| 276 |
| 277 // Because of overlap-and-add we might have round off error. |
| 278 for (int k = 0; k < kPulseWidthSamples; ++k) { |
| 279 EXPECT_NEAR(reinterpret_cast<float*>(channel_data[m])[k], |
| 280 pulse_ch[k], kTolerance) << " loop " << n |
| 281 << " channel/sample " << m << "/" << k; |
| 282 } |
| 283 } |
| 284 } |
| 285 |
| 286 // Zero out the buffer to be sure the next comparison is relevant. |
| 287 pulse_buffer->Zero(); |
| 288 } |
| 289 } |
| 290 |
178 protected: | 291 protected: |
179 AudioRendererAlgorithm algorithm_; | 292 AudioRendererAlgorithm algorithm_; |
180 int frames_enqueued_; | 293 int frames_enqueued_; |
181 int channels_; | 294 int channels_; |
182 SampleFormat sample_format_; | 295 SampleFormat sample_format_; |
183 int bytes_per_sample_; | 296 int bytes_per_sample_; |
184 }; | 297 }; |
185 | 298 |
186 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NormalRate) { | 299 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NormalRate) { |
187 Initialize(); | 300 Initialize(); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 TestPlaybackRate(2.1); | 376 TestPlaybackRate(2.1); |
264 TestPlaybackRate(0.9); | 377 TestPlaybackRate(0.9); |
265 TestPlaybackRate(0.6); | 378 TestPlaybackRate(0.6); |
266 TestPlaybackRate(1.4); | 379 TestPlaybackRate(1.4); |
267 TestPlaybackRate(0.3); | 380 TestPlaybackRate(0.3); |
268 } | 381 } |
269 | 382 |
270 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) { | 383 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) { |
271 Initialize(); | 384 Initialize(); |
272 static const int kBufferSizeInFrames = 1; | 385 static const int kBufferSizeInFrames = 1; |
273 static const int kFramesRequested = 2 * kSamplesPerSecond; | 386 static const int kFramesRequested = kOutputDurationInSec * kSamplesPerSecond; |
274 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested); | 387 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested); |
275 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested); | 388 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested); |
276 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested); | 389 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested); |
277 } | 390 } |
278 | 391 |
279 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) { | 392 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) { |
280 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100); | 393 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100); |
281 TestPlaybackRate(1.0); | 394 TestPlaybackRate(1.0); |
282 TestPlaybackRate(0.5); | 395 TestPlaybackRate(0.5); |
283 TestPlaybackRate(1.5); | 396 TestPlaybackRate(1.5); |
284 } | 397 } |
285 | 398 |
286 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) { | 399 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) { |
287 Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond); | 400 Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond); |
288 TestPlaybackRate(1.0); | 401 TestPlaybackRate(1.0); |
289 TestPlaybackRate(0.5); | 402 TestPlaybackRate(0.5); |
290 TestPlaybackRate(1.5); | 403 TestPlaybackRate(1.5); |
291 } | 404 } |
292 | 405 |
293 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) { | 406 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) { |
294 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond); | 407 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond); |
295 TestPlaybackRate(1.0); | 408 TestPlaybackRate(1.0); |
296 TestPlaybackRate(0.5); | 409 TestPlaybackRate(0.5); |
297 TestPlaybackRate(1.5); | 410 TestPlaybackRate(1.5); |
298 } | 411 } |
299 | 412 |
| 413 TEST_F(AudioRendererAlgorithmTest, DotProduct) { |
| 414 const int kChannels = 3; |
| 415 const int kFrames = 20; |
| 416 const int kHalfPulseWidth = 2; |
| 417 |
| 418 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames); |
| 419 scoped_ptr<AudioBus> b = AudioBus::Create(kChannels, kFrames); |
| 420 |
| 421 scoped_ptr<float[]> dot_prod(new float[kChannels]); |
| 422 |
| 423 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, a.get()); |
| 424 FillWithSquarePulseTrain(kHalfPulseWidth, 1, 1, a.get()); |
| 425 FillWithSquarePulseTrain(kHalfPulseWidth, 2, 2, a.get()); |
| 426 |
| 427 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, b.get()); |
| 428 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 1, b.get()); |
| 429 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 2, b.get()); |
| 430 |
| 431 internal::MultiChannelDotProduct(a.get(), 0, b.get(), 0, kFrames, |
| 432 dot_prod.get()); |
| 433 |
| 434 EXPECT_FLOAT_EQ(kFrames, dot_prod[0]); |
| 435 EXPECT_FLOAT_EQ(0, dot_prod[1]); |
| 436 EXPECT_FLOAT_EQ(-kFrames, dot_prod[2]); |
| 437 |
| 438 internal::MultiChannelDotProduct(a.get(), 4, b.get(), 8, kFrames / 2, |
| 439 dot_prod.get()); |
| 440 |
| 441 EXPECT_FLOAT_EQ(kFrames / 2, dot_prod[0]); |
| 442 EXPECT_FLOAT_EQ(0, dot_prod[1]); |
| 443 EXPECT_FLOAT_EQ(-kFrames / 2, dot_prod[2]); |
| 444 } |
| 445 |
| 446 TEST_F(AudioRendererAlgorithmTest, MovingBlockEnergy) { |
| 447 const int kChannels = 2; |
| 448 const int kFrames = 20; |
| 449 const int kFramesPerBlock = 3; |
| 450 const int kNumBlocks = kFrames - (kFramesPerBlock - 1); |
| 451 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames); |
| 452 scoped_ptr<float[]> energies(new float[kChannels * kNumBlocks]); |
| 453 float* ch_left = a->channel(0); |
| 454 float* ch_right = a->channel(1); |
| 455 |
| 456 // Fill up both channels. |
| 457 for (int n = 0; n < kFrames; ++n) { |
| 458 ch_left[n] = n; |
| 459 ch_right[n] = kFrames - 1 - n; |
| 460 } |
| 461 |
| 462 internal::MultiChannelMovingBlockEnergies(a.get(), kFramesPerBlock, |
| 463 energies.get()); |
| 464 |
| 465 // Check if the energy of candidate blocks of each channel computed correctly. |
| 466 for (int n = 0; n < kNumBlocks; ++n) { |
| 467 float expected_energy = 0; |
| 468 for (int k = 0; k < kFramesPerBlock; ++k) |
| 469 expected_energy += ch_left[n + k] * ch_left[n + k]; |
| 470 |
| 471 // Left (first) channel. |
| 472 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n]); |
| 473 |
| 474 expected_energy = 0; |
| 475 for (int k = 0; k < kFramesPerBlock; ++k) |
| 476 expected_energy += ch_right[n + k] * ch_right[n + k]; |
| 477 |
| 478 // Second (right) channel. |
| 479 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n + 1]); |
| 480 } |
| 481 } |
| 482 |
| 483 TEST_F(AudioRendererAlgorithmTest, FullAndDecimatedSearch) { |
| 484 const int kFramesInSearchRegion = 12; |
| 485 const int kChannels = 2; |
| 486 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}; |
| 487 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}; |
| 488 ASSERT_EQ(sizeof(ch_0), sizeof(ch_1)); |
| 489 ASSERT_EQ(static_cast<size_t>(kFramesInSearchRegion), |
| 490 sizeof(ch_0) / sizeof(*ch_0)); |
| 491 scoped_ptr<AudioBus> search_region = AudioBus::CreateWrapper(kChannels); |
| 492 |
| 493 search_region->SetChannelData(0, ch_0); |
| 494 search_region->SetChannelData(1, ch_1); |
| 495 search_region->set_frames(kFramesInSearchRegion); |
| 496 ASSERT_EQ(kFramesInSearchRegion, search_region->frames()); |
| 497 |
| 498 const int kFramePerBlock = 4; |
| 499 float target_0[] = {1.0, 1.0, 1.0, 0.0}; |
| 500 float target_1[] = {0.0, 1.0, 0.1, 1.0}; |
| 501 ASSERT_EQ(sizeof(target_0), sizeof(target_1)); |
| 502 ASSERT_EQ(static_cast<size_t>(kFramePerBlock), |
| 503 sizeof(target_0) / sizeof(*target_0)); |
| 504 |
| 505 scoped_ptr<AudioBus> target = AudioBus::CreateWrapper(2); |
| 506 target->SetChannelData(0, target_0); |
| 507 target->SetChannelData(1, target_1); |
| 508 target->set_frames(kFramePerBlock); |
| 509 ASSERT_EQ(kFramePerBlock, target->frames()); |
| 510 |
| 511 scoped_ptr<float[]> energy_target(new float[kChannels]); |
| 512 |
| 513 internal::MultiChannelDotProduct(target.get(), 0, target.get(), 0, |
| 514 kFramePerBlock, energy_target.get()); |
| 515 |
| 516 ASSERT_EQ(3.f, energy_target[0]); |
| 517 ASSERT_EQ(2.01f, energy_target[1]); |
| 518 |
| 519 const int kNumCandidBlocks = kFramesInSearchRegion - (kFramePerBlock - 1); |
| 520 scoped_ptr<float[]> energy_candid_blocks(new float[kNumCandidBlocks * |
| 521 kChannels]); |
| 522 |
| 523 internal::MultiChannelMovingBlockEnergies( |
| 524 search_region.get(), kFramePerBlock, energy_candid_blocks.get()); |
| 525 |
| 526 // Check the energy of the candidate blocks of the first channel. |
| 527 ASSERT_FLOAT_EQ(0, energy_candid_blocks[0]); |
| 528 ASSERT_FLOAT_EQ(0, energy_candid_blocks[2]); |
| 529 ASSERT_FLOAT_EQ(1, energy_candid_blocks[4]); |
| 530 ASSERT_FLOAT_EQ(2, energy_candid_blocks[6]); |
| 531 ASSERT_FLOAT_EQ(3, energy_candid_blocks[8]); |
| 532 ASSERT_FLOAT_EQ(3, energy_candid_blocks[10]); |
| 533 ASSERT_FLOAT_EQ(2, energy_candid_blocks[12]); |
| 534 ASSERT_FLOAT_EQ(1, energy_candid_blocks[14]); |
| 535 ASSERT_FLOAT_EQ(0, energy_candid_blocks[16]); |
| 536 |
| 537 // Check the energy of the candidate blocks of the second channel. |
| 538 ASSERT_FLOAT_EQ(0, energy_candid_blocks[1]); |
| 539 ASSERT_FLOAT_EQ(0, energy_candid_blocks[3]); |
| 540 ASSERT_FLOAT_EQ(0, energy_candid_blocks[5]); |
| 541 ASSERT_FLOAT_EQ(0, energy_candid_blocks[7]); |
| 542 ASSERT_FLOAT_EQ(0.01, energy_candid_blocks[9]); |
| 543 ASSERT_FLOAT_EQ(1.01, energy_candid_blocks[11]); |
| 544 ASSERT_FLOAT_EQ(1.02, energy_candid_blocks[13]); |
| 545 ASSERT_FLOAT_EQ(1.02, energy_candid_blocks[15]); |
| 546 ASSERT_FLOAT_EQ(1.01, energy_candid_blocks[17]); |
| 547 |
| 548 // An interval which is of no effect. |
| 549 internal::Interval exclude_interval = std::make_pair(-100, -10); |
| 550 EXPECT_EQ(5, internal::FullSearch( |
| 551 0, kNumCandidBlocks - 1, exclude_interval, target.get(), |
| 552 search_region.get(), energy_target.get(), energy_candid_blocks.get())); |
| 553 |
| 554 // Exclude the the best match. |
| 555 exclude_interval = std::make_pair(2, 5); |
| 556 EXPECT_EQ(7, internal::FullSearch( |
| 557 0, kNumCandidBlocks - 1, exclude_interval, target.get(), |
| 558 search_region.get(), energy_target.get(), energy_candid_blocks.get())); |
| 559 |
| 560 // An interval which is of no effect. |
| 561 exclude_interval = std::make_pair(-100, -10); |
| 562 EXPECT_EQ(4, internal::DecimatedSearch( |
| 563 4, exclude_interval, target.get(), search_region.get(), |
| 564 energy_target.get(), energy_candid_blocks.get())); |
| 565 |
| 566 EXPECT_EQ(5, internal::OptimalIndex(search_region.get(), target.get(), |
| 567 exclude_interval)); |
| 568 } |
| 569 |
| 570 TEST_F(AudioRendererAlgorithmTest, CubicInterpolation) { |
| 571 // Arbitrary coefficients. |
| 572 const float kA = 0.7; |
| 573 const float kB = 1.2; |
| 574 const float kC = 0.8; |
| 575 |
| 576 float y_values[3]; |
| 577 y_values[0] = kA - kB + kC; |
| 578 y_values[1] = kC; |
| 579 y_values[2] = kA + kB + kC; |
| 580 |
| 581 float extremum; |
| 582 float extremum_value; |
| 583 |
| 584 internal::CubicInterpolation(y_values, &extremum, &extremum_value); |
| 585 |
| 586 float x_star = -kB / (2.f * kA); |
| 587 float y_star = kA * x_star * x_star + kB * x_star + kC; |
| 588 |
| 589 EXPECT_FLOAT_EQ(x_star, extremum); |
| 590 EXPECT_FLOAT_EQ(y_star, extremum_value); |
| 591 } |
| 592 |
| 593 TEST_F(AudioRendererAlgorithmTest, WsolaSlowdown) { |
| 594 WsolaTest(1.6f); |
| 595 } |
| 596 |
| 597 TEST_F(AudioRendererAlgorithmTest, WsolaSpeedup) { |
| 598 WsolaTest(0.6f); |
| 599 } |
| 600 |
300 } // namespace media | 601 } // namespace media |
OLD | NEW |