TestDynamicResampler.cpp (23173B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "DynamicResampler.h" 7 #include "gtest/gtest.h" 8 9 using namespace mozilla; 10 11 TEST(TestDynamicResampler, SameRates_Float1) 12 { 13 const uint32_t in_frames = 100; 14 const uint32_t out_frames = 100; 15 uint32_t channels = 2; 16 uint32_t in_rate = 44100; 17 uint32_t out_rate = 44100; 18 19 DynamicResampler dr(in_rate, out_rate); 20 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 21 EXPECT_EQ(dr.GetInRate(), in_rate); 22 EXPECT_EQ(dr.GetChannels(), channels); 23 24 // float in_ch1[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0}; 25 // float in_ch2[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0}; 26 float in_ch1[in_frames] = {}; 27 float in_ch2[in_frames] = {}; 28 AutoTArray<const float*, 2> in_buffer; 29 in_buffer.AppendElements(channels); 30 in_buffer[0] = in_ch1; 31 in_buffer[1] = in_ch2; 32 33 float out_ch1[out_frames] = {}; 34 float out_ch2[out_frames] = {}; 35 36 // Warm up with zeros 37 dr.AppendInput(in_buffer, in_frames); 38 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 39 EXPECT_FALSE(hasUnderrun); 40 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 41 EXPECT_FALSE(hasUnderrun); 42 for (uint32_t i = 0; i < out_frames; ++i) { 43 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]); 44 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]); 45 } 46 47 // Continue with non zero 48 for (uint32_t i = 0; i < in_frames; ++i) { 49 in_ch1[i] = in_ch2[i] = 0.01f * i; 50 } 51 dr.AppendInput(in_buffer, in_frames); 52 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 53 EXPECT_FALSE(hasUnderrun); 54 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 55 EXPECT_FALSE(hasUnderrun); 56 for (uint32_t i = 0; i < out_frames; ++i) { 57 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]); 58 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]); 59 } 60 61 // No more frames in the input buffer 62 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 63 EXPECT_TRUE(hasUnderrun); 64 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 65 EXPECT_TRUE(hasUnderrun); 66 } 67 68 TEST(TestDynamicResampler, SameRates_Short1) 69 { 70 uint32_t in_frames = 2; 71 uint32_t out_frames = 2; 72 uint32_t channels = 2; 73 uint32_t in_rate = 44100; 74 uint32_t out_rate = 44100; 75 76 DynamicResampler dr(in_rate, out_rate); 77 dr.SetSampleFormat(AUDIO_FORMAT_S16); 78 EXPECT_EQ(dr.GetInRate(), in_rate); 79 EXPECT_EQ(dr.GetChannels(), channels); 80 81 short in_ch1[] = {1, 2, 3}; 82 short in_ch2[] = {4, 5, 6}; 83 AutoTArray<const short*, 2> in_buffer; 84 in_buffer.AppendElements(channels); 85 in_buffer[0] = in_ch1; 86 in_buffer[1] = in_ch2; 87 88 short out_ch1[3] = {}; 89 short out_ch2[3] = {}; 90 91 dr.AppendInput(in_buffer, in_frames); 92 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 93 EXPECT_FALSE(hasUnderrun); 94 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 95 EXPECT_FALSE(hasUnderrun); 96 for (uint32_t i = 0; i < out_frames; ++i) { 97 EXPECT_EQ(in_ch1[i], out_ch1[i]); 98 EXPECT_EQ(in_ch2[i], out_ch2[i]); 99 } 100 101 // No more frames in the input buffer 102 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 103 EXPECT_TRUE(hasUnderrun); 104 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 105 EXPECT_TRUE(hasUnderrun); 106 } 107 108 TEST(TestDynamicResampler, SameRates_Float2) 109 { 110 uint32_t in_frames = 3; 111 uint32_t out_frames = 2; 112 uint32_t channels = 2; 113 uint32_t in_rate = 44100; 114 uint32_t out_rate = 44100; 115 116 DynamicResampler dr(in_rate, out_rate); 117 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 118 119 float in_ch1[] = {0.1, 0.2, 0.3}; 120 float in_ch2[] = {0.4, 0.5, 0.6}; 121 AutoTArray<const float*, 2> in_buffer; 122 in_buffer.AppendElements(channels); 123 in_buffer[0] = in_ch1; 124 in_buffer[1] = in_ch2; 125 126 float out_ch1[3] = {}; 127 float out_ch2[3] = {}; 128 129 dr.AppendInput(in_buffer, in_frames); 130 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 131 EXPECT_FALSE(hasUnderrun); 132 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 133 EXPECT_FALSE(hasUnderrun); 134 for (uint32_t i = 0; i < out_frames; ++i) { 135 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]); 136 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]); 137 } 138 139 out_frames = 1; 140 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 141 EXPECT_FALSE(hasUnderrun); 142 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 143 EXPECT_FALSE(hasUnderrun); 144 for (uint32_t i = 0; i < out_frames; ++i) { 145 EXPECT_FLOAT_EQ(in_ch1[i + 2], out_ch1[i]); 146 EXPECT_FLOAT_EQ(in_ch2[i + 2], out_ch2[i]); 147 } 148 149 // No more frames, the input buffer has drained 150 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 151 EXPECT_TRUE(hasUnderrun); 152 dr.Resample(out_ch2, out_frames, 1); 153 EXPECT_TRUE(hasUnderrun); 154 } 155 156 TEST(TestDynamicResampler, SameRates_Short2) 157 { 158 uint32_t in_frames = 3; 159 uint32_t out_frames = 2; 160 uint32_t channels = 2; 161 uint32_t in_rate = 44100; 162 uint32_t out_rate = 44100; 163 164 DynamicResampler dr(in_rate, out_rate); 165 dr.SetSampleFormat(AUDIO_FORMAT_S16); 166 167 short in_ch1[] = {1, 2, 3}; 168 short in_ch2[] = {4, 5, 6}; 169 AutoTArray<const short*, 2> in_buffer; 170 in_buffer.AppendElements(channels); 171 in_buffer[0] = in_ch1; 172 in_buffer[1] = in_ch2; 173 174 short out_ch1[3] = {}; 175 short out_ch2[3] = {}; 176 177 dr.AppendInput(in_buffer, in_frames); 178 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 179 EXPECT_FALSE(hasUnderrun); 180 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 181 EXPECT_FALSE(hasUnderrun); 182 for (uint32_t i = 0; i < out_frames; ++i) { 183 EXPECT_EQ(in_ch1[i], out_ch1[i]); 184 EXPECT_EQ(in_ch2[i], out_ch2[i]); 185 } 186 187 out_frames = 1; 188 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 189 EXPECT_FALSE(hasUnderrun); 190 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 191 EXPECT_FALSE(hasUnderrun); 192 for (uint32_t i = 0; i < out_frames; ++i) { 193 EXPECT_EQ(in_ch1[i + 2], out_ch1[i]); 194 EXPECT_EQ(in_ch2[i + 2], out_ch2[i]); 195 } 196 197 // No more frames, the input buffer has drained 198 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 199 EXPECT_TRUE(hasUnderrun); 200 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 201 EXPECT_TRUE(hasUnderrun); 202 } 203 204 TEST(TestDynamicResampler, SameRates_Float3) 205 { 206 uint32_t in_frames = 2; 207 uint32_t out_frames = 3; 208 uint32_t channels = 2; 209 uint32_t in_rate = 44100; 210 uint32_t out_rate = 44100; 211 212 DynamicResampler dr(in_rate, out_rate); 213 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 214 215 float in_ch1[] = {0.1, 0.2, 0.3}; 216 float in_ch2[] = {0.4, 0.5, 0.6}; 217 AutoTArray<const float*, 2> in_buffer; 218 in_buffer.AppendElements(channels); 219 in_buffer[0] = in_ch1; 220 in_buffer[1] = in_ch2; 221 222 float out_ch1[3] = {}; 223 float out_ch2[3] = {}; 224 225 // Not enough frames in the input buffer 226 dr.AppendInput(in_buffer, in_frames); 227 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 228 EXPECT_TRUE(hasUnderrun); 229 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 230 EXPECT_TRUE(hasUnderrun); 231 232 // Add one frame 233 in_buffer[0] = in_ch1 + 2; 234 in_buffer[1] = in_ch2 + 2; 235 dr.AppendInput(in_buffer, 1); 236 out_frames = 1; 237 hasUnderrun = dr.Resample(out_ch1 + 2, out_frames, 0); 238 EXPECT_FALSE(hasUnderrun); 239 hasUnderrun = dr.Resample(out_ch2 + 2, out_frames, 1); 240 EXPECT_FALSE(hasUnderrun); 241 for (uint32_t i = 0; i < 3; ++i) { 242 EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]); 243 EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]); 244 } 245 } 246 247 TEST(TestDynamicResampler, SameRates_Short3) 248 { 249 uint32_t in_frames = 2; 250 uint32_t out_frames = 3; 251 uint32_t channels = 2; 252 uint32_t in_rate = 44100; 253 uint32_t out_rate = 44100; 254 255 DynamicResampler dr(in_rate, out_rate); 256 dr.SetSampleFormat(AUDIO_FORMAT_S16); 257 258 short in_ch1[] = {1, 2, 3}; 259 short in_ch2[] = {4, 5, 6}; 260 AutoTArray<const short*, 2> in_buffer; 261 in_buffer.AppendElements(channels); 262 in_buffer[0] = in_ch1; 263 in_buffer[1] = in_ch2; 264 265 short out_ch1[3] = {}; 266 short out_ch2[3] = {}; 267 268 // Not enough frames in the input buffer 269 dr.AppendInput(in_buffer, in_frames); 270 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 271 EXPECT_TRUE(hasUnderrun); 272 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 273 EXPECT_TRUE(hasUnderrun); 274 275 // Add one frame 276 in_buffer[0] = in_ch1 + 2; 277 in_buffer[1] = in_ch2 + 2; 278 dr.AppendInput(in_buffer, 1); 279 out_frames = 1; 280 hasUnderrun = dr.Resample(out_ch1 + 2, out_frames, 0); 281 EXPECT_FALSE(hasUnderrun); 282 hasUnderrun = dr.Resample(out_ch2 + 2, out_frames, 1); 283 EXPECT_FALSE(hasUnderrun); 284 for (uint32_t i = 0; i < 3; ++i) { 285 EXPECT_EQ(in_ch1[i], out_ch1[i]); 286 EXPECT_EQ(in_ch2[i], out_ch2[i]); 287 } 288 } 289 290 TEST(TestDynamicResampler, UpdateOutRate_Float) 291 { 292 uint32_t in_frames = 10; 293 uint32_t out_frames = 40; 294 uint32_t channels = 2; 295 uint32_t in_rate = 24000; 296 uint32_t out_rate = 48000; 297 298 uint32_t pre_buffer = 20; 299 300 DynamicResampler dr(in_rate, out_rate); 301 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 302 EXPECT_EQ(dr.GetInRate(), in_rate); 303 EXPECT_EQ(dr.GetChannels(), channels); 304 305 float in_ch1[10] = {}; 306 float in_ch2[10] = {}; 307 for (uint32_t i = 0; i < in_frames; ++i) { 308 in_ch1[i] = in_ch2[i] = 0.01f * i; 309 } 310 AutoTArray<const float*, 2> in_buffer; 311 in_buffer.AppendElements(channels); 312 in_buffer[0] = in_ch1; 313 in_buffer[1] = in_ch2; 314 315 float out_ch1[40] = {}; 316 float out_ch2[40] = {}; 317 318 dr.AppendInputSilence(pre_buffer - in_frames); 319 dr.AppendInput(in_buffer, in_frames); 320 out_frames = 20u; 321 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 322 EXPECT_FALSE(hasUnderrun); 323 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 324 EXPECT_FALSE(hasUnderrun); 325 for (uint32_t i = 0; i < out_frames; ++i) { 326 // Half the input pre-buffer (10) is silence, and half the output (20). 327 EXPECT_FLOAT_EQ(out_ch1[i], 0.0); 328 EXPECT_FLOAT_EQ(out_ch2[i], 0.0); 329 } 330 331 // Update in rate 332 in_rate = 26122; 333 dr.UpdateResampler(in_rate, channels); 334 EXPECT_EQ(dr.GetInRate(), in_rate); 335 EXPECT_EQ(dr.GetChannels(), channels); 336 out_frames = in_frames * out_rate / in_rate; 337 EXPECT_EQ(out_frames, 18u); 338 // Even if we provide no input if we have enough buffered input, we can create 339 // output 340 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 341 EXPECT_FALSE(hasUnderrun); 342 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 343 EXPECT_FALSE(hasUnderrun); 344 } 345 346 TEST(TestDynamicResampler, UpdateOutRate_Short) 347 { 348 uint32_t in_frames = 10; 349 uint32_t out_frames = 40; 350 uint32_t channels = 2; 351 uint32_t in_rate = 24000; 352 uint32_t out_rate = 48000; 353 354 uint32_t pre_buffer = 20; 355 356 DynamicResampler dr(in_rate, out_rate); 357 dr.SetSampleFormat(AUDIO_FORMAT_S16); 358 EXPECT_EQ(dr.GetInRate(), in_rate); 359 EXPECT_EQ(dr.GetChannels(), channels); 360 361 short in_ch1[10] = {}; 362 short in_ch2[10] = {}; 363 for (uint32_t i = 0; i < in_frames; ++i) { 364 in_ch1[i] = in_ch2[i] = i; 365 } 366 AutoTArray<const short*, 2> in_buffer; 367 in_buffer.AppendElements(channels); 368 in_buffer[0] = in_ch1; 369 in_buffer[1] = in_ch2; 370 371 short out_ch1[40] = {}; 372 short out_ch2[40] = {}; 373 374 dr.AppendInputSilence(pre_buffer - in_frames); 375 dr.AppendInput(in_buffer, in_frames); 376 out_frames = 20u; 377 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 378 EXPECT_FALSE(hasUnderrun); 379 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 380 EXPECT_FALSE(hasUnderrun); 381 for (uint32_t i = 0; i < out_frames; ++i) { 382 // Half the input pre-buffer (10) is silence, and half the output (20). 383 EXPECT_EQ(out_ch1[i], 0.0); 384 EXPECT_EQ(out_ch2[i], 0.0); 385 } 386 387 // Update in rate 388 in_rate = 26122; 389 dr.UpdateResampler(in_rate, channels); 390 EXPECT_EQ(dr.GetInRate(), in_rate); 391 EXPECT_EQ(dr.GetChannels(), channels); 392 out_frames = in_frames * out_rate / in_rate; 393 EXPECT_EQ(out_frames, 18u); 394 // Even if we provide no input if we have enough buffered input, we can create 395 // output 396 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 397 EXPECT_FALSE(hasUnderrun); 398 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 399 EXPECT_FALSE(hasUnderrun); 400 } 401 402 TEST(TestDynamicResampler, BigRangeInRates_Float) 403 { 404 uint32_t in_frames = 10; 405 uint32_t out_frames = 10; 406 uint32_t channels = 2; 407 uint32_t in_rate = 44100; 408 uint32_t out_rate = 44100; 409 410 DynamicResampler dr(in_rate, out_rate); 411 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 412 413 const uint32_t in_capacity = 40; 414 float in_ch1[in_capacity] = {}; 415 float in_ch2[in_capacity] = {}; 416 for (uint32_t i = 0; i < in_capacity; ++i) { 417 in_ch1[i] = in_ch2[i] = 0.01f * i; 418 } 419 AutoTArray<const float*, 2> in_buffer; 420 in_buffer.AppendElements(channels); 421 in_buffer[0] = in_ch1; 422 in_buffer[1] = in_ch2; 423 424 const uint32_t out_capacity = 1000; 425 float out_ch1[out_capacity] = {}; 426 float out_ch2[out_capacity] = {}; 427 428 // Downsampling at a high enough ratio happens to have enough excess 429 // in_frames from rounding in the out_frames calculation to cover the 430 // skipped input latency when switching from zero-latency 44100->44100 to a 431 // non-1:1 ratio. 432 for (uint32_t rate = 100000; rate >= 10000; rate -= 2) { 433 in_rate = rate; 434 dr.UpdateResampler(in_rate, channels); 435 EXPECT_EQ(dr.GetInRate(), in_rate); 436 EXPECT_EQ(dr.GetChannels(), channels); 437 in_frames = 20; // more than we need 438 out_frames = in_frames * out_rate / in_rate; 439 for (uint32_t y = 0; y < 2; ++y) { 440 dr.AppendInput(in_buffer, in_frames); 441 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 442 EXPECT_FALSE(hasUnderrun); 443 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 444 EXPECT_FALSE(hasUnderrun); 445 } 446 } 447 } 448 449 TEST(TestDynamicResampler, DownsamplingToCopying) 450 { 451 uint32_t channel_count = 1; 452 // Start with downsampling 453 uint32_t in_rate = 48001; 454 uint32_t out_rate = 48000; 455 456 DynamicResampler dr(in_rate, out_rate); 457 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 458 dr.UpdateResampler(in_rate, channel_count); 459 460 const uint32_t in_frame_count = 100; 461 float in_frames[in_frame_count]; 462 float increment = 1.f / in_frame_count; 463 for (uint32_t i = 0; i < in_frame_count; ++i) { 464 in_frames[i] = static_cast<float>(i) * increment; 465 } 466 const float* in_channels[] = {in_frames}; 467 dr.AppendInput(in_channels, in_frame_count); 468 469 const uint32_t block_size = 30; 470 const uint32_t out_frame_count = 2 * block_size; 471 float out_frames[out_frame_count]; 472 bool hasUnderrun = dr.Resample(out_frames, block_size, 0); 473 EXPECT_FALSE(hasUnderrun); 474 // Use out_rate for the input rate so that the DynamicResampler switches 475 // from resampling to copying of frames. 476 dr.UpdateResampler(out_rate, channel_count); 477 hasUnderrun = dr.Resample(out_frames + block_size, block_size, 0); 478 EXPECT_FALSE(hasUnderrun); 479 480 // The abrupt change in slope from zero to increment is resampled to some 481 // oscillations around the point of change. 482 constexpr float tolerance = 0.1f; 483 bool latencyHasPassed = false; 484 EXPECT_NEAR(out_frames[0], 0.f, tolerance); 485 for (uint32_t i = 1; i < out_frame_count; ++i) { 486 if (!latencyHasPassed) { 487 // Before the latency passes, samples may be approximately zero. 488 EXPECT_GT(out_frames[i], -tolerance) << "for i=" << i; 489 if (out_frames[i] > tolerance) { 490 latencyHasPassed = true; 491 EXPECT_LT(out_frames[i], increment + tolerance) << "for i=" << i; 492 } 493 continue; 494 } 495 EXPECT_NEAR(out_frames[i], out_frames[i - 1] + increment, tolerance); 496 } 497 } 498 499 TEST(TestDynamicResampler, BigRangeInRates_Short) 500 { 501 uint32_t in_frames = 10; 502 uint32_t out_frames = 10; 503 uint32_t channels = 2; 504 uint32_t in_rate = 44100; 505 uint32_t out_rate = 44100; 506 507 DynamicResampler dr(in_rate, out_rate); 508 dr.SetSampleFormat(AUDIO_FORMAT_S16); 509 510 const uint32_t in_capacity = 40; 511 short in_ch1[in_capacity] = {}; 512 short in_ch2[in_capacity] = {}; 513 for (uint32_t i = 0; i < in_capacity; ++i) { 514 in_ch1[i] = in_ch2[i] = i; 515 } 516 AutoTArray<const short*, 2> in_buffer; 517 in_buffer.AppendElements(channels); 518 in_buffer[0] = in_ch1; 519 in_buffer[1] = in_ch2; 520 521 const uint32_t out_capacity = 1000; 522 short out_ch1[out_capacity] = {}; 523 short out_ch2[out_capacity] = {}; 524 525 for (uint32_t rate = 100000; rate >= 10000; rate -= 2) { 526 in_rate = rate; 527 dr.UpdateResampler(in_rate, channels); 528 in_frames = 20; // more than we need 529 out_frames = in_frames * out_rate / in_rate; 530 for (uint32_t y = 0; y < 2; ++y) { 531 dr.AppendInput(in_buffer, in_frames); 532 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 533 EXPECT_FALSE(hasUnderrun); 534 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 535 EXPECT_FALSE(hasUnderrun); 536 } 537 } 538 } 539 540 TEST(TestDynamicResampler, UpdateChannels_Float) 541 { 542 uint32_t in_frames = 10; 543 uint32_t out_frames = 10; 544 uint32_t channels = 2; 545 uint32_t in_rate = 44100; 546 uint32_t out_rate = 48000; 547 548 DynamicResampler dr(in_rate, out_rate); 549 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 550 551 float in_ch1[10] = {}; 552 float in_ch2[10] = {}; 553 for (uint32_t i = 0; i < in_frames; ++i) { 554 in_ch1[i] = in_ch2[i] = 0.01f * i; 555 } 556 AutoTArray<const float*, 2> in_buffer; 557 in_buffer.AppendElements(channels); 558 in_buffer[0] = in_ch1; 559 in_buffer[1] = in_ch2; 560 561 float out_ch1[10] = {}; 562 float out_ch2[10] = {}; 563 564 dr.AppendInput(in_buffer, in_frames); 565 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 566 EXPECT_FALSE(hasUnderrun); 567 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 568 EXPECT_FALSE(hasUnderrun); 569 570 // Add 3rd channel 571 dr.UpdateResampler(in_rate, 3); 572 EXPECT_EQ(dr.GetInRate(), in_rate); 573 EXPECT_EQ(dr.GetChannels(), 3u); 574 575 float in_ch3[10] = {}; 576 for (uint32_t i = 0; i < in_frames; ++i) { 577 in_ch3[i] = 0.01f * i; 578 } 579 in_buffer.AppendElement(); 580 in_buffer[2] = in_ch3; 581 float out_ch3[10] = {}; 582 583 dr.AppendInput(in_buffer, in_frames); 584 585 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 586 EXPECT_FALSE(hasUnderrun); 587 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 588 EXPECT_FALSE(hasUnderrun); 589 hasUnderrun = dr.Resample(out_ch3, out_frames, 2); 590 EXPECT_FALSE(hasUnderrun); 591 592 float in_ch4[10] = {}; 593 for (uint32_t i = 0; i < in_frames; ++i) { 594 in_ch3[i] = 0.01f * i; 595 } 596 in_buffer.AppendElement(); 597 in_buffer[3] = in_ch4; 598 float out_ch4[10] = {}; 599 600 dr.UpdateResampler(in_rate, 4); 601 EXPECT_EQ(dr.GetInRate(), in_rate); 602 EXPECT_EQ(dr.GetChannels(), 4u); 603 dr.AppendInput(in_buffer, in_frames); 604 605 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 606 EXPECT_FALSE(hasUnderrun); 607 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 608 EXPECT_FALSE(hasUnderrun); 609 hasUnderrun = dr.Resample(out_ch3, out_frames, 2); 610 EXPECT_FALSE(hasUnderrun); 611 hasUnderrun = dr.Resample(out_ch4, out_frames, 3); 612 EXPECT_FALSE(hasUnderrun); 613 } 614 615 TEST(TestDynamicResampler, UpdateChannels_Short) 616 { 617 uint32_t in_frames = 10; 618 uint32_t out_frames = 10; 619 uint32_t channels = 2; 620 uint32_t in_rate = 44100; 621 uint32_t out_rate = 48000; 622 623 DynamicResampler dr(in_rate, out_rate); 624 dr.SetSampleFormat(AUDIO_FORMAT_S16); 625 626 short in_ch1[10] = {}; 627 short in_ch2[10] = {}; 628 for (uint32_t i = 0; i < in_frames; ++i) { 629 in_ch1[i] = in_ch2[i] = i; 630 } 631 AutoTArray<const short*, 2> in_buffer; 632 in_buffer.AppendElements(channels); 633 in_buffer[0] = in_ch1; 634 in_buffer[1] = in_ch2; 635 636 short out_ch1[10] = {}; 637 short out_ch2[10] = {}; 638 639 dr.AppendInput(in_buffer, in_frames); 640 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 641 EXPECT_FALSE(hasUnderrun); 642 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 643 EXPECT_FALSE(hasUnderrun); 644 645 // Add 3rd channel 646 dr.UpdateResampler(in_rate, 3); 647 EXPECT_EQ(dr.GetInRate(), in_rate); 648 EXPECT_EQ(dr.GetChannels(), 3u); 649 650 short in_ch3[10] = {}; 651 for (uint32_t i = 0; i < in_frames; ++i) { 652 in_ch3[i] = i; 653 } 654 in_buffer.AppendElement(); 655 in_buffer[2] = in_ch3; 656 short out_ch3[10] = {}; 657 658 dr.AppendInput(in_buffer, in_frames); 659 660 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 661 EXPECT_FALSE(hasUnderrun); 662 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 663 EXPECT_FALSE(hasUnderrun); 664 hasUnderrun = dr.Resample(out_ch3, out_frames, 2); 665 EXPECT_FALSE(hasUnderrun); 666 667 // Check update with AudioSegment 668 short in_ch4[10] = {}; 669 for (uint32_t i = 0; i < in_frames; ++i) { 670 in_ch3[i] = i; 671 } 672 in_buffer.AppendElement(); 673 in_buffer[3] = in_ch4; 674 short out_ch4[10] = {}; 675 676 dr.UpdateResampler(in_rate, 4); 677 EXPECT_EQ(dr.GetInRate(), in_rate); 678 EXPECT_EQ(dr.GetChannels(), 4u); 679 dr.AppendInput(in_buffer, in_frames); 680 681 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 682 EXPECT_FALSE(hasUnderrun); 683 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 684 EXPECT_FALSE(hasUnderrun); 685 hasUnderrun = dr.Resample(out_ch3, out_frames, 2); 686 EXPECT_FALSE(hasUnderrun); 687 hasUnderrun = dr.Resample(out_ch4, out_frames, 3); 688 EXPECT_FALSE(hasUnderrun); 689 } 690 691 TEST(TestDynamicResampler, Underrun) 692 { 693 const uint32_t in_frames = 100; 694 const uint32_t out_frames = 200; 695 uint32_t channels = 2; 696 uint32_t in_rate = 48000; 697 uint32_t out_rate = 48000; 698 699 DynamicResampler dr(in_rate, out_rate); 700 dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32); 701 EXPECT_EQ(dr.GetInRate(), in_rate); 702 EXPECT_EQ(dr.GetChannels(), channels); 703 704 float in_ch1[in_frames] = {}; 705 float in_ch2[in_frames] = {}; 706 AutoTArray<const float*, 2> in_buffer; 707 in_buffer.AppendElements(channels); 708 in_buffer[0] = in_ch1; 709 in_buffer[1] = in_ch2; 710 711 float out_ch1[out_frames] = {}; 712 float out_ch2[out_frames] = {}; 713 714 for (uint32_t i = 0; i < in_frames; ++i) { 715 in_ch1[i] = 0.01f * i; 716 in_ch2[i] = -0.01f * i; 717 } 718 dr.AppendInput(in_buffer, in_frames); 719 bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 720 EXPECT_TRUE(hasUnderrun); 721 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 722 EXPECT_TRUE(hasUnderrun); 723 for (uint32_t i = 0; i < in_frames; ++i) { 724 EXPECT_EQ(out_ch1[i], in_ch1[i]); 725 EXPECT_EQ(out_ch2[i], in_ch2[i]); 726 } 727 for (uint32_t i = in_frames; i < out_frames; ++i) { 728 EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i; 729 EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i; 730 } 731 732 // No more frames in the input buffer 733 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 734 EXPECT_TRUE(hasUnderrun); 735 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 736 EXPECT_TRUE(hasUnderrun); 737 for (uint32_t i = 0; i < out_frames; ++i) { 738 EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i; 739 EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i; 740 } 741 742 // Now try with resampling. 743 dr.UpdateResampler(in_rate * 2, channels); 744 dr.AppendInput(in_buffer, in_frames); 745 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 746 EXPECT_TRUE(hasUnderrun); 747 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 748 EXPECT_TRUE(hasUnderrun); 749 // There is some buffering in the resampler, which is why the below is not 750 // exact. 751 for (uint32_t i = 0; i < 50; ++i) { 752 EXPECT_GT(out_ch1[i], 0.0f) << "for i=" << i; 753 EXPECT_LT(out_ch2[i], 0.0f) << "for i=" << i; 754 } 755 for (uint32_t i = 50; i < 54; ++i) { 756 EXPECT_NE(out_ch1[i], 0.0f) << "for i=" << i; 757 EXPECT_NE(out_ch2[i], 0.0f) << "for i=" << i; 758 } 759 for (uint32_t i = 54; i < out_frames; ++i) { 760 EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i; 761 EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i; 762 } 763 764 // No more frames in the input buffer 765 hasUnderrun = dr.Resample(out_ch1, out_frames, 0); 766 EXPECT_TRUE(hasUnderrun); 767 hasUnderrun = dr.Resample(out_ch2, out_frames, 1); 768 EXPECT_TRUE(hasUnderrun); 769 for (uint32_t i = 0; i < out_frames; ++i) { 770 EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i; 771 EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i; 772 } 773 }