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. 4 // 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 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 9 // expectation that FillBuffer() will fill as much as it can but no more. 10 11 #include <algorithm> // For std::min(). 12 #include <cmath> 13 #include <vector> 14 15 #include "base/bind.h" 16 #include "base/callback.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "media/base/audio_buffer.h" 19 #include "media/base/audio_bus.h" 20 #include "media/base/buffers.h" 21 #include "media/base/channel_layout.h" 22 #include "media/base/test_helpers.h" 23 #include "media/filters/audio_renderer_algorithm.h" 24 #include "media/filters/wsola_internals.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 27 namespace media { 28 29 const int kFrameSize = 250; 30 const int kSamplesPerSecond = 3000; 31 const int kOutputDurationInSec = 10; 32 33 static void FillWithSquarePulseTrain( 34 int half_pulse_width, int offset, int num_samples, float* data) { 35 ASSERT_GE(offset, 0); 36 ASSERT_LE(offset, num_samples); 37 38 // Fill backward from |offset| - 1 toward zero, starting with -1, alternating 39 // between -1 and 1 every |pulse_width| samples. 40 float pulse = -1.0f; 41 for (int n = offset - 1, k = 0; n >= 0; --n, ++k) { 42 if (k >= half_pulse_width) { 43 pulse = -pulse; 44 k = 0; 45 } 46 data[n] = pulse; 47 } 48 49 // Fill forward from |offset| towards the end, starting with 1, alternating 50 // between 1 and -1 every |pulse_width| samples. 51 pulse = 1.0f; 52 for (int n = offset, k = 0; n < num_samples; ++n, ++k) { 53 if (k >= half_pulse_width) { 54 pulse = -pulse; 55 k = 0; 56 } 57 data[n] = pulse; 58 } 59 } 60 61 static void FillWithSquarePulseTrain( 62 int half_pulse_width, int offset, int channel, AudioBus* audio_bus) { 63 FillWithSquarePulseTrain(half_pulse_width, offset, audio_bus->frames(), 64 audio_bus->channel(channel)); 65 } 66 67 class AudioRendererAlgorithmTest : public testing::Test { 68 public: 69 AudioRendererAlgorithmTest() 70 : frames_enqueued_(0), 71 channels_(0), 72 channel_layout_(CHANNEL_LAYOUT_NONE), 73 sample_format_(kUnknownSampleFormat), 74 samples_per_second_(0), 75 bytes_per_sample_(0) { 76 } 77 78 virtual ~AudioRendererAlgorithmTest() {} 79 80 void Initialize() { 81 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 3000); 82 } 83 84 void Initialize(ChannelLayout channel_layout, 85 SampleFormat sample_format, 86 int samples_per_second) { 87 channels_ = ChannelLayoutToChannelCount(channel_layout); 88 samples_per_second_ = samples_per_second; 89 channel_layout_ = channel_layout; 90 sample_format_ = sample_format; 91 bytes_per_sample_ = SampleFormatToBytesPerChannel(sample_format); 92 AudioParameters params(media::AudioParameters::AUDIO_PCM_LINEAR, 93 channel_layout, 94 samples_per_second, 95 bytes_per_sample_ * 8, 96 samples_per_second / 100); 97 algorithm_.Initialize(1, params); 98 FillAlgorithmQueue(); 99 } 100 101 void FillAlgorithmQueue() { 102 // The value of the data is meaningless; we just want non-zero data to 103 // differentiate it from muted data. 104 scoped_refptr<AudioBuffer> buffer; 105 while (!algorithm_.IsQueueFull()) { 106 switch (sample_format_) { 107 case kSampleFormatU8: 108 buffer = MakeAudioBuffer<uint8>( 109 sample_format_, 110 channel_layout_, 111 ChannelLayoutToChannelCount(channel_layout_), 112 samples_per_second_, 113 1, 114 1, 115 kFrameSize, 116 kNoTimestamp()); 117 break; 118 case kSampleFormatS16: 119 buffer = MakeAudioBuffer<int16>( 120 sample_format_, 121 channel_layout_, 122 ChannelLayoutToChannelCount(channel_layout_), 123 samples_per_second_, 124 1, 125 1, 126 kFrameSize, 127 kNoTimestamp()); 128 break; 129 case kSampleFormatS32: 130 buffer = MakeAudioBuffer<int32>( 131 sample_format_, 132 channel_layout_, 133 ChannelLayoutToChannelCount(channel_layout_), 134 samples_per_second_, 135 1, 136 1, 137 kFrameSize, 138 kNoTimestamp()); 139 break; 140 default: 141 NOTREACHED() << "Unrecognized format " << sample_format_; 142 } 143 algorithm_.EnqueueBuffer(buffer); 144 frames_enqueued_ += kFrameSize; 145 } 146 } 147 148 void CheckFakeData(AudioBus* audio_data, int frames_written) { 149 // Check each channel individually. 150 for (int ch = 0; ch < channels_; ++ch) { 151 bool all_zero = true; 152 for (int i = 0; i < frames_written && all_zero; ++i) 153 all_zero = audio_data->channel(ch)[i] == 0.0f; 154 ASSERT_EQ(algorithm_.is_muted(), all_zero) << " for channel " << ch; 155 } 156 } 157 158 int ComputeConsumedFrames(int initial_frames_enqueued, 159 int initial_frames_buffered) { 160 int frame_delta = frames_enqueued_ - initial_frames_enqueued; 161 int buffered_delta = algorithm_.frames_buffered() - initial_frames_buffered; 162 int consumed = frame_delta - buffered_delta; 163 CHECK_GE(consumed, 0); 164 return consumed; 165 } 166 167 void TestPlaybackRate(double playback_rate) { 168 const int kDefaultBufferSize = algorithm_.samples_per_second() / 100; 169 const int kDefaultFramesRequested = kOutputDurationInSec * 170 algorithm_.samples_per_second(); 171 172 TestPlaybackRate( 173 playback_rate, kDefaultBufferSize, kDefaultFramesRequested); 174 } 175 176 void TestPlaybackRate(double playback_rate, 177 int buffer_size_in_frames, 178 int total_frames_requested) { 179 int initial_frames_enqueued = frames_enqueued_; 180 int initial_frames_buffered = algorithm_.frames_buffered(); 181 algorithm_.SetPlaybackRate(static_cast<float>(playback_rate)); 182 183 scoped_ptr<AudioBus> bus = 184 AudioBus::Create(channels_, buffer_size_in_frames); 185 if (playback_rate == 0.0) { 186 int frames_written = 187 algorithm_.FillBuffer(bus.get(), buffer_size_in_frames); 188 EXPECT_EQ(0, frames_written); 189 return; 190 } 191 192 int frames_remaining = total_frames_requested; 193 bool first_fill_buffer = true; 194 while (frames_remaining > 0) { 195 int frames_requested = std::min(buffer_size_in_frames, frames_remaining); 196 int frames_written = algorithm_.FillBuffer(bus.get(), frames_requested); 197 ASSERT_GT(frames_written, 0) << "Requested: " << frames_requested 198 << ", playing at " << playback_rate; 199 200 // Do not check data if it is first pull out and only one frame written. 201 // The very first frame out of WSOLA is always zero because of 202 // overlap-and-add window, which is zero for the first sample. Therefore, 203 // if at very first buffer-fill only one frame is written, that is zero 204 // which might cause exception in CheckFakeData(). 205 if (!first_fill_buffer || frames_written > 1) 206 CheckFakeData(bus.get(), frames_written); 207 first_fill_buffer = false; 208 frames_remaining -= frames_written; 209 210 FillAlgorithmQueue(); 211 } 212 213 int frames_consumed = 214 ComputeConsumedFrames(initial_frames_enqueued, initial_frames_buffered); 215 216 // If playing back at normal speed, we should always get back the same 217 // number of bytes requested. 218 if (playback_rate == 1.0) { 219 EXPECT_EQ(total_frames_requested, frames_consumed); 220 return; 221 } 222 223 // Otherwise, allow |kMaxAcceptableDelta| difference between the target and 224 // actual playback rate. 225 // When |kSamplesPerSecond| and |total_frames_requested| are reasonably 226 // large, one can expect less than a 1% difference in most cases. In our 227 // current implementation, sped up playback is less accurate than slowed 228 // down playback, and for playback_rate > 1, playback rate generally gets 229 // less and less accurate the farther it drifts from 1 (though this is 230 // nonlinear). 231 double actual_playback_rate = 232 1.0 * frames_consumed / total_frames_requested; 233 EXPECT_NEAR(playback_rate, actual_playback_rate, playback_rate / 100.0); 234 } 235 236 void WsolaTest(float playback_rate) { 237 const int kSampleRateHz = 48000; 238 const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; 239 const int kBytesPerSample = 2; 240 const int kNumFrames = kSampleRateHz / 100; // 10 milliseconds. 241 242 channels_ = ChannelLayoutToChannelCount(kChannelLayout); 243 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 244 kSampleRateHz, kBytesPerSample * 8, kNumFrames); 245 algorithm_.Initialize(playback_rate, params); 246 247 // A pulse is 6 milliseconds (even number of samples). 248 const int kPulseWidthSamples = 6 * kSampleRateHz / 1000; 249 const int kHalfPulseWidthSamples = kPulseWidthSamples / 2; 250 251 // For the ease of implementation get 1 frame every call to FillBuffer(). 252 scoped_ptr<AudioBus> output = AudioBus::Create(channels_, 1); 253 254 // Input buffer to inject pulses. 255 scoped_refptr<AudioBuffer> input = 256 AudioBuffer::CreateBuffer(kSampleFormatPlanarF32, 257 kChannelLayout, 258 channels_, 259 kSampleRateHz, 260 kPulseWidthSamples); 261 262 const std::vector<uint8*>& channel_data = input->channel_data(); 263 264 // Fill |input| channels. 265 FillWithSquarePulseTrain(kHalfPulseWidthSamples, 0, kPulseWidthSamples, 266 reinterpret_cast<float*>(channel_data[0])); 267 FillWithSquarePulseTrain(kHalfPulseWidthSamples, kHalfPulseWidthSamples, 268 kPulseWidthSamples, 269 reinterpret_cast<float*>(channel_data[1])); 270 271 // A buffer for the output until a complete pulse is created. Then 272 // reference pulse is compared with this buffer. 273 scoped_ptr<AudioBus> pulse_buffer = AudioBus::Create( 274 channels_, kPulseWidthSamples); 275 276 const float kTolerance = 0.000001f; 277 // Equivalent of 4 seconds. 278 const int kNumRequestedPulses = kSampleRateHz * 4 / kPulseWidthSamples; 279 for (int n = 0; n < kNumRequestedPulses; ++n) { 280 int num_buffered_frames = 0; 281 while (num_buffered_frames < kPulseWidthSamples) { 282 int num_samples = algorithm_.FillBuffer(output.get(), 1); 283 ASSERT_LE(num_samples, 1); 284 if (num_samples > 0) { 285 output->CopyPartialFramesTo(0, num_samples, num_buffered_frames, 286 pulse_buffer.get()); 287 num_buffered_frames++; 288 } else { 289 algorithm_.EnqueueBuffer(input); 290 } 291 } 292 293 // Pulses in the first half of WSOLA AOL frame are not constructed 294 // perfectly. Do not check them. 295 if (n > 3) { 296 for (int m = 0; m < channels_; ++m) { 297 const float* pulse_ch = pulse_buffer->channel(m); 298 299 // Because of overlap-and-add we might have round off error. 300 for (int k = 0; k < kPulseWidthSamples; ++k) { 301 ASSERT_NEAR(reinterpret_cast<float*>(channel_data[m])[k], 302 pulse_ch[k], kTolerance) << " loop " << n 303 << " channel/sample " << m << "/" << k; 304 } 305 } 306 } 307 308 // Zero out the buffer to be sure the next comparison is relevant. 309 pulse_buffer->Zero(); 310 } 311 } 312 313 protected: 314 AudioRendererAlgorithm algorithm_; 315 int frames_enqueued_; 316 int channels_; 317 ChannelLayout channel_layout_; 318 SampleFormat sample_format_; 319 int samples_per_second_; 320 int bytes_per_sample_; 321 }; 322 323 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NormalRate) { 324 Initialize(); 325 TestPlaybackRate(1.0); 326 } 327 328 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NearlyNormalFasterRate) { 329 Initialize(); 330 TestPlaybackRate(1.0001); 331 } 332 333 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NearlyNormalSlowerRate) { 334 Initialize(); 335 TestPlaybackRate(0.9999); 336 } 337 338 TEST_F(AudioRendererAlgorithmTest, FillBuffer_OneAndAQuarterRate) { 339 Initialize(); 340 TestPlaybackRate(1.25); 341 } 342 343 TEST_F(AudioRendererAlgorithmTest, FillBuffer_OneAndAHalfRate) { 344 Initialize(); 345 TestPlaybackRate(1.5); 346 } 347 348 TEST_F(AudioRendererAlgorithmTest, FillBuffer_DoubleRate) { 349 Initialize(); 350 TestPlaybackRate(2.0); 351 } 352 353 TEST_F(AudioRendererAlgorithmTest, FillBuffer_EightTimesRate) { 354 Initialize(); 355 TestPlaybackRate(8.0); 356 } 357 358 TEST_F(AudioRendererAlgorithmTest, FillBuffer_ThreeQuartersRate) { 359 Initialize(); 360 TestPlaybackRate(0.75); 361 } 362 363 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HalfRate) { 364 Initialize(); 365 TestPlaybackRate(0.5); 366 } 367 368 TEST_F(AudioRendererAlgorithmTest, FillBuffer_QuarterRate) { 369 Initialize(); 370 TestPlaybackRate(0.25); 371 } 372 373 TEST_F(AudioRendererAlgorithmTest, FillBuffer_Pause) { 374 Initialize(); 375 TestPlaybackRate(0.0); 376 } 377 378 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SlowDown) { 379 Initialize(); 380 TestPlaybackRate(4.5); 381 TestPlaybackRate(3.0); 382 TestPlaybackRate(2.0); 383 TestPlaybackRate(1.0); 384 TestPlaybackRate(0.5); 385 TestPlaybackRate(0.25); 386 } 387 388 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SpeedUp) { 389 Initialize(); 390 TestPlaybackRate(0.25); 391 TestPlaybackRate(0.5); 392 TestPlaybackRate(1.0); 393 TestPlaybackRate(2.0); 394 TestPlaybackRate(3.0); 395 TestPlaybackRate(4.5); 396 } 397 398 TEST_F(AudioRendererAlgorithmTest, FillBuffer_JumpAroundSpeeds) { 399 Initialize(); 400 TestPlaybackRate(2.1); 401 TestPlaybackRate(0.9); 402 TestPlaybackRate(0.6); 403 TestPlaybackRate(1.4); 404 TestPlaybackRate(0.3); 405 } 406 407 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) { 408 Initialize(); 409 static const int kBufferSizeInFrames = 1; 410 static const int kFramesRequested = kOutputDurationInSec * kSamplesPerSecond; 411 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested); 412 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested); 413 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested); 414 } 415 416 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) { 417 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100); 418 TestPlaybackRate(1.0); 419 TestPlaybackRate(0.5); 420 TestPlaybackRate(1.5); 421 } 422 423 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) { 424 Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond); 425 TestPlaybackRate(1.0); 426 TestPlaybackRate(0.5); 427 TestPlaybackRate(1.5); 428 } 429 430 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) { 431 Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond); 432 TestPlaybackRate(1.0); 433 TestPlaybackRate(0.5); 434 TestPlaybackRate(1.5); 435 } 436 437 TEST_F(AudioRendererAlgorithmTest, DotProduct) { 438 const int kChannels = 3; 439 const int kFrames = 20; 440 const int kHalfPulseWidth = 2; 441 442 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames); 443 scoped_ptr<AudioBus> b = AudioBus::Create(kChannels, kFrames); 444 445 scoped_ptr<float[]> dot_prod(new float[kChannels]); 446 447 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, a.get()); 448 FillWithSquarePulseTrain(kHalfPulseWidth, 1, 1, a.get()); 449 FillWithSquarePulseTrain(kHalfPulseWidth, 2, 2, a.get()); 450 451 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, b.get()); 452 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 1, b.get()); 453 FillWithSquarePulseTrain(kHalfPulseWidth, 0, 2, b.get()); 454 455 internal::MultiChannelDotProduct(a.get(), 0, b.get(), 0, kFrames, 456 dot_prod.get()); 457 458 EXPECT_FLOAT_EQ(kFrames, dot_prod[0]); 459 EXPECT_FLOAT_EQ(0, dot_prod[1]); 460 EXPECT_FLOAT_EQ(-kFrames, dot_prod[2]); 461 462 internal::MultiChannelDotProduct(a.get(), 4, b.get(), 8, kFrames / 2, 463 dot_prod.get()); 464 465 EXPECT_FLOAT_EQ(kFrames / 2, dot_prod[0]); 466 EXPECT_FLOAT_EQ(0, dot_prod[1]); 467 EXPECT_FLOAT_EQ(-kFrames / 2, dot_prod[2]); 468 } 469 470 TEST_F(AudioRendererAlgorithmTest, MovingBlockEnergy) { 471 const int kChannels = 2; 472 const int kFrames = 20; 473 const int kFramesPerBlock = 3; 474 const int kNumBlocks = kFrames - (kFramesPerBlock - 1); 475 scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames); 476 scoped_ptr<float[]> energies(new float[kChannels * kNumBlocks]); 477 float* ch_left = a->channel(0); 478 float* ch_right = a->channel(1); 479 480 // Fill up both channels. 481 for (int n = 0; n < kFrames; ++n) { 482 ch_left[n] = n; 483 ch_right[n] = kFrames - 1 - n; 484 } 485 486 internal::MultiChannelMovingBlockEnergies(a.get(), kFramesPerBlock, 487 energies.get()); 488 489 // Check if the energy of candidate blocks of each channel computed correctly. 490 for (int n = 0; n < kNumBlocks; ++n) { 491 float expected_energy = 0; 492 for (int k = 0; k < kFramesPerBlock; ++k) 493 expected_energy += ch_left[n + k] * ch_left[n + k]; 494 495 // Left (first) channel. 496 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n]); 497 498 expected_energy = 0; 499 for (int k = 0; k < kFramesPerBlock; ++k) 500 expected_energy += ch_right[n + k] * ch_right[n + k]; 501 502 // Second (right) channel. 503 EXPECT_FLOAT_EQ(expected_energy, energies[2 * n + 1]); 504 } 505 } 506 507 TEST_F(AudioRendererAlgorithmTest, FullAndDecimatedSearch) { 508 const int kFramesInSearchRegion = 12; 509 const int kChannels = 2; 510 float ch_0[] = { 511 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }; 512 float ch_1[] = { 513 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 1.0f, 0.1f, 0.0f, 0.0f }; 514 ASSERT_EQ(sizeof(ch_0), sizeof(ch_1)); 515 ASSERT_EQ(static_cast<size_t>(kFramesInSearchRegion), 516 sizeof(ch_0) / sizeof(*ch_0)); 517 scoped_ptr<AudioBus> search_region = AudioBus::Create(kChannels, 518 kFramesInSearchRegion); 519 float* ch = search_region->channel(0); 520 memcpy(ch, ch_0, sizeof(float) * kFramesInSearchRegion); 521 ch = search_region->channel(1); 522 memcpy(ch, ch_1, sizeof(float) * kFramesInSearchRegion); 523 524 const int kFramePerBlock = 4; 525 float target_0[] = { 1.0f, 1.0f, 1.0f, 0.0f }; 526 float target_1[] = { 0.0f, 1.0f, 0.1f, 1.0f }; 527 ASSERT_EQ(sizeof(target_0), sizeof(target_1)); 528 ASSERT_EQ(static_cast<size_t>(kFramePerBlock), 529 sizeof(target_0) / sizeof(*target_0)); 530 531 scoped_ptr<AudioBus> target = AudioBus::Create(kChannels, 532 kFramePerBlock); 533 ch = target->channel(0); 534 memcpy(ch, target_0, sizeof(float) * kFramePerBlock); 535 ch = target->channel(1); 536 memcpy(ch, target_1, sizeof(float) * kFramePerBlock); 537 538 scoped_ptr<float[]> energy_target(new float[kChannels]); 539 540 internal::MultiChannelDotProduct(target.get(), 0, target.get(), 0, 541 kFramePerBlock, energy_target.get()); 542 543 ASSERT_EQ(3.f, energy_target[0]); 544 ASSERT_EQ(2.01f, energy_target[1]); 545 546 const int kNumCandidBlocks = kFramesInSearchRegion - (kFramePerBlock - 1); 547 scoped_ptr<float[]> energy_candid_blocks(new float[kNumCandidBlocks * 548 kChannels]); 549 550 internal::MultiChannelMovingBlockEnergies( 551 search_region.get(), kFramePerBlock, energy_candid_blocks.get()); 552 553 // Check the energy of the candidate blocks of the first channel. 554 ASSERT_FLOAT_EQ(0, energy_candid_blocks[0]); 555 ASSERT_FLOAT_EQ(0, energy_candid_blocks[2]); 556 ASSERT_FLOAT_EQ(1, energy_candid_blocks[4]); 557 ASSERT_FLOAT_EQ(2, energy_candid_blocks[6]); 558 ASSERT_FLOAT_EQ(3, energy_candid_blocks[8]); 559 ASSERT_FLOAT_EQ(3, energy_candid_blocks[10]); 560 ASSERT_FLOAT_EQ(2, energy_candid_blocks[12]); 561 ASSERT_FLOAT_EQ(1, energy_candid_blocks[14]); 562 ASSERT_FLOAT_EQ(0, energy_candid_blocks[16]); 563 564 // Check the energy of the candidate blocks of the second channel. 565 ASSERT_FLOAT_EQ(0, energy_candid_blocks[1]); 566 ASSERT_FLOAT_EQ(0, energy_candid_blocks[3]); 567 ASSERT_FLOAT_EQ(0, energy_candid_blocks[5]); 568 ASSERT_FLOAT_EQ(0, energy_candid_blocks[7]); 569 ASSERT_FLOAT_EQ(0.01f, energy_candid_blocks[9]); 570 ASSERT_FLOAT_EQ(1.01f, energy_candid_blocks[11]); 571 ASSERT_FLOAT_EQ(1.02f, energy_candid_blocks[13]); 572 ASSERT_FLOAT_EQ(1.02f, energy_candid_blocks[15]); 573 ASSERT_FLOAT_EQ(1.01f, energy_candid_blocks[17]); 574 575 // An interval which is of no effect. 576 internal::Interval exclude_interval = std::make_pair(-100, -10); 577 EXPECT_EQ(5, internal::FullSearch( 578 0, kNumCandidBlocks - 1, exclude_interval, target.get(), 579 search_region.get(), energy_target.get(), energy_candid_blocks.get())); 580 581 // Exclude the the best match. 582 exclude_interval = std::make_pair(2, 5); 583 EXPECT_EQ(7, internal::FullSearch( 584 0, kNumCandidBlocks - 1, exclude_interval, target.get(), 585 search_region.get(), energy_target.get(), energy_candid_blocks.get())); 586 587 // An interval which is of no effect. 588 exclude_interval = std::make_pair(-100, -10); 589 EXPECT_EQ(4, internal::DecimatedSearch( 590 4, exclude_interval, target.get(), search_region.get(), 591 energy_target.get(), energy_candid_blocks.get())); 592 593 EXPECT_EQ(5, internal::OptimalIndex(search_region.get(), target.get(), 594 exclude_interval)); 595 } 596 597 TEST_F(AudioRendererAlgorithmTest, QuadraticInterpolation) { 598 // Arbitrary coefficients. 599 const float kA = 0.7f; 600 const float kB = 1.2f; 601 const float kC = 0.8f; 602 603 float y_values[3]; 604 y_values[0] = kA - kB + kC; 605 y_values[1] = kC; 606 y_values[2] = kA + kB + kC; 607 608 float extremum; 609 float extremum_value; 610 611 internal::QuadraticInterpolation(y_values, &extremum, &extremum_value); 612 613 float x_star = -kB / (2.f * kA); 614 float y_star = kA * x_star * x_star + kB * x_star + kC; 615 616 EXPECT_FLOAT_EQ(x_star, extremum); 617 EXPECT_FLOAT_EQ(y_star, extremum_value); 618 } 619 620 TEST_F(AudioRendererAlgorithmTest, QuadraticInterpolation_Colinear) { 621 float y_values[3]; 622 y_values[0] = 1.0; 623 y_values[1] = 1.0; 624 y_values[2] = 1.0; 625 626 float extremum; 627 float extremum_value; 628 629 internal::QuadraticInterpolation(y_values, &extremum, &extremum_value); 630 631 EXPECT_FLOAT_EQ(extremum, 0.0); 632 EXPECT_FLOAT_EQ(extremum_value, 1.0); 633 } 634 635 TEST_F(AudioRendererAlgorithmTest, WsolaSlowdown) { 636 WsolaTest(0.6f); 637 } 638 639 TEST_F(AudioRendererAlgorithmTest, WsolaSpeedup) { 640 WsolaTest(1.6f); 641 } 642 643 } // namespace media 644