1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "audio_utils_primitives_tests" 19 20 #include <math.h> 21 #include <vector> 22 23 #include <gtest/gtest.h> 24 #include <log/log.h> 25 26 #include <audio_utils/primitives.h> 27 #include <audio_utils/format.h> 28 #include <audio_utils/channels.h> 29 30 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 31 32 static const int32_t lim8pos = 255; 33 static const int32_t lim8neg = 0; 34 static const int32_t lim16pos = (1 << 15) - 1; 35 static const int32_t lim16neg = -(1 << 15); 36 static const int32_t lim24pos = (1 << 23) - 1; 37 static const int32_t lim24neg = -(1 << 23); 38 static const int64_t lim32pos = 0x000000007fffffff; 39 static const int64_t lim32neg = 0xffffffff80000000; 40 41 // Use memset here since it is generally the fastest method of clearing data, 42 // but could be changed to std::fill or assignment should those prove faster. 43 template <typename T> 44 static void zeroFill(T &container) { 45 memset(container.data(), 0, container.size() * sizeof(container[0])); 46 } 47 48 inline void testClamp8(float f) 49 { 50 // f is in native u8 scaling to test rounding 51 uint8_t uval = clamp8_from_float((f - 128) / (1 << 7)); 52 53 // test clamping 54 ALOGV("clamp8_from_float(%f) = %u\n", f, uval); 55 if (f > lim8pos) { 56 EXPECT_EQ(lim8pos, uval); 57 } else if (f < lim8neg) { 58 EXPECT_EQ(lim8neg, uval); 59 } 60 61 // if in range, make sure round trip clamp and conversion is correct. 62 if (f < lim8pos - 1. && f > lim8neg + 1.) { 63 uint8_t uval2 = clamp8_from_float(float_from_u8(uval)); 64 int diff = abs(uval - uval2); 65 EXPECT_LE(diff, 1); 66 } 67 } 68 69 inline void testClamp16(float f) 70 { 71 int16_t ival = clamp16_from_float(f / (1 << 15)); 72 73 // test clamping 74 ALOGV("clamp16_from_float(%f) = %d\n", f, ival); 75 if (f > lim16pos) { 76 EXPECT_EQ(lim16pos, ival); 77 } else if (f < lim16neg) { 78 EXPECT_EQ(lim16neg, ival); 79 } 80 81 // if in range, make sure round trip clamp and conversion is correct. 82 if (f < lim16pos - 1. && f > lim16neg + 1.) { 83 int ival2 = clamp16_from_float(float_from_i16(ival)); 84 int diff = abs(ival - ival2); 85 EXPECT_LE(diff, 1); 86 } 87 } 88 89 inline void testClamp24(float f) 90 { 91 int32_t ival = clamp24_from_float(f / (1 << 23)); 92 93 // test clamping 94 ALOGV("clamp24_from_float(%f) = %d\n", f, ival); 95 if (f > lim24pos) { 96 EXPECT_EQ(lim24pos, ival); 97 } else if (f < lim24neg) { 98 EXPECT_EQ(lim24neg, ival); 99 } 100 101 // if in range, make sure round trip clamp and conversion is correct. 102 if (f < lim24pos - 1. && f > lim24neg + 1.) { 103 int ival2 = clamp24_from_float(float_from_q8_23(ival)); 104 int diff = abs(ival - ival2); 105 EXPECT_LE(diff, 1); 106 } 107 } 108 109 template<typename T> 110 void checkMonotone(const T *ary, size_t size) 111 { 112 for (size_t i = 1; i < size; ++i) { 113 EXPECT_LT(ary[i-1], ary[i]); 114 } 115 } 116 117 void checkMonotonep24(uint8_t * pary, size_t size) 118 { 119 size_t frames = size/3; 120 for (size_t i = 1; i < frames; ++i) { 121 EXPECT_LT(i32_from_p24(pary + 3*(i-1)), i32_from_p24(pary + 3*i)); 122 } 123 } 124 125 TEST(audio_utils_primitives, clamp_to_int) { 126 static const float testArray[] = { 127 -NAN, -INFINITY, 128 -1.e20, -32768., 63.9, 129 -3.5, -3.4, -2.5, 2.4, -1.5, -1.4, -0.5, -0.2, 0., 0.2, 0.5, 0.8, 130 1.4, 1.5, 1.8, 2.4, 2.5, 2.6, 3.4, 3.5, 131 32767., 32768., 1.e20, 132 INFINITY, NAN }; 133 134 for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) { 135 testClamp8(testArray[i]); 136 } 137 for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) { 138 testClamp16(testArray[i]); 139 } 140 for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) { 141 testClamp24(testArray[i]); 142 } 143 144 // used for ULP testing (tweaking the lsb of the float) 145 union { 146 int32_t i; 147 float f; 148 } val; 149 int32_t res; 150 151 // check clampq4_27_from_float() 152 val.f = 16.; 153 res = clampq4_27_from_float(val.f); 154 EXPECT_EQ(0x7fffffff, res); 155 val.i--; 156 res = clampq4_27_from_float(val.f); 157 EXPECT_LE(res, 0x7fffffff); 158 EXPECT_GE(res, 0x7fff0000); 159 val.f = -16.; 160 res = clampq4_27_from_float(val.f); 161 EXPECT_EQ((int32_t)0x80000000, res); // negative 162 val.i++; 163 res = clampq4_27_from_float(val.f); 164 EXPECT_GE(res, (int32_t)0x80000000); // negative 165 EXPECT_LE(res, (int32_t)0x80008000); // negative 166 167 // check u4_28_from_float and u4_12_from_float 168 uint32_t ures; 169 uint16_t ures16; 170 val.f = 16.; 171 ures = u4_28_from_float(val.f); 172 EXPECT_EQ(0xffffffff, ures); 173 ures16 = u4_12_from_float(val.f); 174 EXPECT_EQ(0xffff, ures16); 175 176 val.f = -1.; 177 ures = u4_28_from_float(val.f); 178 EXPECT_EQ((uint32_t)0, ures); 179 ures16 = u4_12_from_float(val.f); 180 EXPECT_EQ(0, ures16); 181 182 // check float_from_u4_28 and float_from_u4_12 (roundtrip) 183 for (uint32_t v = 0x100000; v <= 0xff000000; v += 0x100000) { 184 ures = u4_28_from_float(float_from_u4_28(v)); 185 EXPECT_EQ(ures, v); 186 } 187 for (uint32_t v = 0; v <= 0xffff; ++v) { // uint32_t prevents overflow 188 ures16 = u4_12_from_float(float_from_u4_12(v)); 189 EXPECT_EQ(ures16, v); 190 } 191 192 // check infinity 193 EXPECT_EQ(0, clamp8_from_float(-INFINITY)); 194 EXPECT_EQ(255, clamp8_from_float(INFINITY)); 195 } 196 197 TEST(audio_utils_primitives, memcpy) { 198 // test round-trip. 199 constexpr size_t size = 65536; 200 std::vector<int16_t> i16ref(size); 201 std::vector<int16_t> i16ary(size); 202 std::vector<int32_t> i32ary(size); 203 std::vector<float> fary(size); 204 std::vector<uint8_t> pary(size * 3); 205 206 207 // set signed reference monotonic array from -32768 to 32767 208 for (size_t i = 0; i < i16ref.size(); ++i) { 209 i16ref[i] = i16ary[i] = i - 32768; 210 } 211 212 // do round-trip testing i16 and float 213 memcpy_to_float_from_i16(fary.data(), i16ary.data(), fary.size()); 214 zeroFill(i16ary); 215 checkMonotone(fary.data(), fary.size()); 216 217 memcpy_to_i16_from_float(i16ary.data(), fary.data(), i16ary.size()); 218 zeroFill(fary); 219 checkMonotone(i16ary.data(), i16ary.size()); 220 221 // TODO make a template case for the following? 222 223 // do round-trip testing p24 to i16 and float 224 memcpy_to_p24_from_i16(pary.data(), i16ary.data(), size /* note pary elem is 3 bytes */); 225 zeroFill(i16ary); 226 227 // check an intermediate format at a position(???) 228 #if 0 229 printf("pary[%d].0 = %u pary[%d].1 = %u pary[%d].2 = %u\n", 230 1025, (unsigned) pary[1025*3], 231 1025, (unsigned) pary[1025*3+1], 232 1025, (unsigned) pary[1025*3+2] 233 ); 234 #endif 235 236 memcpy_to_float_from_p24(fary.data(), pary.data(), fary.size()); 237 zeroFill(pary); 238 checkMonotone(fary.data(), fary.size()); 239 240 memcpy_to_p24_from_float(pary.data(), fary.data(), size /* note pary elem is 3 bytes */); 241 zeroFill(fary); 242 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/); 243 244 memcpy_to_i16_from_p24(i16ary.data(), pary.data(), i16ary.size()); 245 zeroFill(pary); 246 checkMonotone(i16ary.data(), i16ary.size()); 247 248 // do round-trip testing q8_23 to i16 and float 249 memcpy_to_q8_23_from_i16(i32ary.data(), i16ary.data(), i32ary.size()); 250 zeroFill(i16ary); 251 checkMonotone(i32ary.data(), i32ary.size()); 252 253 memcpy_to_float_from_q8_23(fary.data(), i32ary.data(), fary.size()); 254 zeroFill(i32ary); 255 checkMonotone(fary.data(), fary.size()); 256 257 memcpy_to_q8_23_from_float_with_clamp(i32ary.data(), fary.data(), i32ary.size()); 258 zeroFill(fary); 259 checkMonotone(i32ary.data(), i32ary.size()); 260 261 memcpy_to_i16_from_q8_23(i16ary.data(), i32ary.data(), i16ary.size()); 262 zeroFill(i32ary); 263 checkMonotone(i16ary.data(), i16ary.size()); 264 265 // do round-trip testing i32 to i16 and float 266 memcpy_to_i32_from_i16(i32ary.data(), i16ary.data(), i32ary.size()); 267 zeroFill(i16ary); 268 checkMonotone(i32ary.data(), i32ary.size()); 269 270 memcpy_to_float_from_i32(fary.data(), i32ary.data(), fary.size()); 271 zeroFill(i32ary); 272 checkMonotone(fary.data(), fary.size()); 273 274 memcpy_to_i32_from_float(i32ary.data(), fary.data(), i32ary.size()); 275 zeroFill(fary); 276 checkMonotone(i32ary.data(), i32ary.size()); 277 278 memcpy_to_i16_from_i32(i16ary.data(), i32ary.data(), i16ary.size()); 279 zeroFill(i32ary); 280 checkMonotone(i16ary.data(), i16ary.size()); 281 282 // do round-trip test i16 -> p24 -> i32 -> p24 -> q8_23 -> p24 -> i16 283 memcpy_to_p24_from_i16(pary.data(), i16ary.data(), size /* note pary elem is 3 bytes */); 284 zeroFill(i16ary); 285 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/); 286 287 memcpy_to_i32_from_p24(i32ary.data(), pary.data(), i32ary.size()); 288 zeroFill(pary); 289 checkMonotone(i32ary.data(), i32ary.size()); 290 291 memcpy_to_p24_from_i32(pary.data(), i32ary.data(), size /* note pary elem is 3 bytes */); 292 zeroFill(i32ary); 293 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/); 294 295 memcpy_to_q8_23_from_p24(i32ary.data(), pary.data(), i32ary.size()); 296 zeroFill(pary); 297 checkMonotone(i32ary.data(), i32ary.size()); 298 299 memcpy_to_p24_from_q8_23(pary.data(), i32ary.data(), size /* note pary elem is 3 bytes */); 300 zeroFill(i32ary); 301 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/); 302 303 memcpy_to_i16_from_p24(i16ary.data(), pary.data(), i16ary.size()); 304 zeroFill(pary); 305 checkMonotone(i16ary.data(), i16ary.size()); 306 307 // do partial round-trip testing q4_27 to i16 and float 308 memcpy_to_float_from_i16(fary.data(), i16ary.data(), fary.size()); 309 zeroFill(i16ary); 310 311 memcpy_to_q4_27_from_float(i32ary.data(), fary.data(), i32ary.size()); 312 zeroFill(fary); 313 checkMonotone(i32ary.data(), i32ary.size()); 314 315 memcpy_to_i16_from_q4_27(i16ary.data(), i32ary.data(), i16ary.size()); 316 checkMonotone(i16ary.data(), i16ary.size()); 317 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), i16ary.size() * sizeof(i16ary[0]))); 318 319 zeroFill(i16ary); 320 321 // ditherAndClamp() has non-standard parameters - memcpy_to_float_from_q4_27() is preferred 322 ditherAndClamp(reinterpret_cast<int32_t *>(i16ary.data()), 323 i32ary.data(), i16ary.size() / 2); 324 checkMonotone(i16ary.data(), i16ary.size()); 325 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), i16ary.size() * sizeof(i16ary[0]))); 326 327 memcpy_to_float_from_q4_27(fary.data(), i32ary.data(), fary.size()); 328 zeroFill(i32ary); 329 checkMonotone(fary.data(), fary.size()); 330 331 // at the end, our i16ary must be the same. (Monotone should be equivalent to this) 332 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), i16ary.size() * sizeof(i16ary[0]))); 333 334 // test round-trip for u8 and float. 335 constexpr size_t u8size = 256; 336 std::vector<uint8_t> u8ref(u8size); 337 std::vector<uint8_t> u8ary(u8size); 338 339 for (size_t i = 0; i < u8ref.size(); ++i) { 340 u8ref[i] = i; 341 } 342 343 constexpr size_t testsize = std::min(u8size, size); 344 memcpy_to_float_from_u8(fary.data(), u8ref.data(), testsize); 345 memcpy_to_u8_from_float(u8ary.data(), fary.data(), testsize); 346 347 EXPECT_EQ(0, memcmp(u8ary.data(), u8ref.data(), u8ary.size() * sizeof(u8ary[0]))); 348 } 349 350 template<typename T> 351 void checkMonotoneOrZero(const T *ary, size_t size) 352 { 353 T least = 0; 354 355 for (size_t i = 1; i < size; ++i) { 356 if (ary[i]) { 357 EXPECT_LT(least, ary[i]); 358 least = ary[i]; 359 } 360 } 361 } 362 363 TEST(audio_utils_primitives, memcpy_by_channel_mask) { 364 uint32_t dst_mask; 365 uint32_t src_mask; 366 uint16_t *u16ref = new uint16_t[65536]; 367 uint16_t *u16ary = new uint16_t[65536]; 368 369 for (size_t i = 0; i < 65536; ++i) { 370 u16ref[i] = i; 371 } 372 373 // Test when src mask is 0. Everything copied is zero. 374 src_mask = 0; 375 dst_mask = 0x8d; 376 memset(u16ary, 0x99, 65536 * sizeof(u16ref[0])); 377 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 378 65536 / popcount(dst_mask)); 379 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 380 381 // Test when dst_mask is 0. Nothing should be copied. 382 src_mask = 0; 383 dst_mask = 0; 384 memset(u16ary, 0, 65536 * sizeof(u16ref[0])); 385 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 386 65536); 387 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 388 389 // Test when masks are the same. One to one copy. 390 src_mask = dst_mask = 0x8d; 391 memset(u16ary, 0x99, 65536 * sizeof(u16ref[0])); 392 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 555); 393 EXPECT_EQ(0, memcmp(u16ary, u16ref, 555 * sizeof(u16ref[0]) * popcount(dst_mask))); 394 395 // Test with a gap in source: 396 // Input 3 samples, output 4 samples, one zero inserted. 397 src_mask = 0x8c; 398 dst_mask = 0x8d; 399 memset(u16ary, 0x9, 65536 * sizeof(u16ary[0])); 400 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 401 65536 / popcount(dst_mask)); 402 checkMonotoneOrZero(u16ary, 65536); 403 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); 404 405 // Test with a gap in destination: 406 // Input 4 samples, output 3 samples, one deleted 407 src_mask = 0x8d; 408 dst_mask = 0x8c; 409 memset(u16ary, 0x9, 65536 * sizeof(u16ary[0])); 410 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 411 65536 / popcount(src_mask)); 412 checkMonotone(u16ary, 65536 * 3 / 4); 413 414 delete[] u16ref; 415 delete[] u16ary; 416 } 417 418 void memcpy_by_channel_mask2(void *dst, uint32_t dst_mask, 419 const void *src, uint32_t src_mask, size_t sample_size, size_t count) 420 { 421 int8_t idxary[32]; 422 uint32_t src_channels = popcount(src_mask); 423 uint32_t dst_channels = 424 memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask); 425 426 memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count); 427 } 428 429 // a modified version of the memcpy_by_channel_mask test 430 // but using 24 bit type and memcpy_by_index_array() 431 TEST(audio_utils_primitives, memcpy_by_index_array) { 432 uint32_t dst_mask; 433 uint32_t src_mask; 434 typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t; 435 uint8x3_t *u24ref = new uint8x3_t[65536]; 436 uint8x3_t *u24ary = new uint8x3_t[65536]; 437 uint16_t *u16ref = new uint16_t[65536]; 438 uint16_t *u16ary = new uint16_t[65536]; 439 440 EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct 441 442 // tests prepare_index_array_from_masks() 443 EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization(NULL, 0, 0x8d, 0x8c)); 444 EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization(NULL, 0, 0x8c, 0x8d)); 445 446 for (size_t i = 0; i < 65536; ++i) { 447 u16ref[i] = i; 448 } 449 memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536); 450 451 // Test when src mask is 0. Everything copied is zero. 452 src_mask = 0; 453 dst_mask = 0x8d; 454 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); 455 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 456 65536 / popcount(dst_mask)); 457 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 458 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 459 460 // Test when dst_mask is 0. Nothing should be copied. 461 src_mask = 0; 462 dst_mask = 0; 463 memset(u24ary, 0, 65536 * sizeof(u24ary[0])); 464 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 465 65536); 466 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 467 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 468 469 // Test when masks are the same. One to one copy. 470 src_mask = dst_mask = 0x8d; 471 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); 472 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); 473 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); 474 475 // Test with a gap in source: 476 // Input 3 samples, output 4 samples, one zero inserted. 477 src_mask = 0x8c; 478 dst_mask = 0x8d; 479 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); 480 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 481 65536 / popcount(dst_mask)); 482 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 483 checkMonotoneOrZero(u16ary, 65536); 484 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); 485 486 // Test with a gap in destination: 487 // Input 4 samples, output 3 samples, one deleted 488 src_mask = 0x8d; 489 dst_mask = 0x8c; 490 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); 491 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 492 65536 / popcount(src_mask)); 493 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 494 checkMonotone(u16ary, 65536 * 3 / 4); 495 496 delete[] u16ref; 497 delete[] u16ary; 498 delete[] u24ref; 499 delete[] u24ary; 500 } 501 502 void memcpy_by_channel_mask_dst_index(void *dst, uint32_t dst_mask, 503 const void *src, uint32_t src_mask, size_t sample_size, size_t count) 504 { 505 int8_t idxary[32]; 506 uint32_t src_channels = popcount(src_mask); 507 uint32_t dst_channels = 508 memcpy_by_index_array_initialization_dst_index(idxary, 32, dst_mask, src_mask); 509 510 memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count); 511 } 512 513 // a modified version of the memcpy_by_channel_mask test 514 // but using 24 bit type and memcpy_by_index_array() 515 TEST(audio_utils_primitives, memcpy_by_index_array_dst_index) { 516 uint32_t dst_mask; 517 uint32_t src_mask; 518 typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t; 519 uint8x3_t *u24ref = new uint8x3_t[65536]; 520 uint8x3_t *u24ary = new uint8x3_t[65536]; 521 uint16_t *u16ref = new uint16_t[65536]; 522 uint16_t *u16ary = new uint16_t[65536]; 523 524 EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct 525 526 // tests prepare_index_array_from_masks() 527 EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8d, 0x8c)); 528 EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8c, 0x8d)); 529 530 for (size_t i = 0; i < 65536; ++i) { 531 u16ref[i] = i; 532 } 533 memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536); 534 535 // Test when src mask is 0. Everything copied is zero. 536 src_mask = 0; 537 dst_mask = 0x8d; 538 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); 539 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 540 65536 / popcount(dst_mask)); 541 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 542 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 543 544 // Test when dst_mask is 0. Nothing should be copied. 545 src_mask = 0; 546 dst_mask = 0; 547 memset(u24ary, 0, 65536 * sizeof(u24ary[0])); 548 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 549 65536); 550 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 551 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 552 553 // Test when dst mask equals source count size. One to one copy. 554 src_mask = 0x8d; 555 dst_mask = 0x0f; 556 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); 557 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); 558 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); 559 560 // Test with a gap in source: 561 // Input 3 samples, output 4 samples, one zero inserted. 562 src_mask = 0x8c; 563 dst_mask = 0x0f; 564 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); 565 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 566 65536 / popcount(dst_mask)); 567 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 568 checkMonotoneOrZero(u16ary, 65536); 569 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); 570 571 // Test with a gap in destination: 572 // Input 4 samples, output 3 samples, one deleted 573 src_mask = 0x8d; 574 dst_mask = 0x07; 575 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); 576 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 577 65536 / popcount(src_mask)); 578 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 579 checkMonotone(u16ary, 65536 * 3 / 4); 580 581 delete[] u16ref; 582 delete[] u16ary; 583 delete[] u24ref; 584 delete[] u24ary; 585 } 586 587 void memcpy_by_channel_mask_src_index(void *dst, uint32_t dst_mask, 588 const void *src, uint32_t src_mask, size_t sample_size, size_t count) 589 { 590 int8_t idxary[32]; 591 uint32_t src_channels = popcount(src_mask); 592 uint32_t dst_channels = 593 memcpy_by_index_array_initialization_src_index(idxary, 32, dst_mask, src_mask); 594 595 memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count); 596 } 597 598 // a modified version of the memcpy_by_channel_mask test 599 // but using 24 bit type and memcpy_by_index_array() 600 TEST(audio_utils_primitives, memcpy_by_index_array_src_index) { 601 uint32_t dst_mask; 602 uint32_t src_mask; 603 typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t; 604 uint8x3_t *u24ref = new uint8x3_t[65536]; 605 uint8x3_t *u24ary = new uint8x3_t[65536]; 606 uint16_t *u16ref = new uint16_t[65536]; 607 uint16_t *u16ary = new uint16_t[65536]; 608 609 EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct 610 611 // tests prepare_index_array_from_masks() 612 EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8d, 0x8c)); 613 EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8c, 0x8d)); 614 615 for (size_t i = 0; i < 65536; ++i) { 616 u16ref[i] = i; 617 } 618 memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536); 619 620 // Test when src mask is 0. Everything copied is zero. 621 src_mask = 0; 622 dst_mask = 0x8d; 623 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); 624 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 625 65536 / popcount(dst_mask)); 626 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 627 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 628 629 // Test when dst_mask is 0. Nothing should be copied. 630 src_mask = 0; 631 dst_mask = 0; 632 memset(u24ary, 0, 65536 * sizeof(u24ary[0])); 633 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 634 65536); 635 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 636 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); 637 638 // Test when source mask must copy to dst mask. One to one copy. 639 src_mask = 0xf; 640 dst_mask = 0xf; 641 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); 642 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); 643 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); 644 645 // Test when source mask must copy to dst mask. One to one copy. 646 src_mask = 0xf; 647 dst_mask = 0x8d; 648 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); 649 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); 650 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); 651 652 // Test with a gap in source: 653 // Input 3 samples, output 4 samples, one zero inserted. 654 src_mask = 0x07; 655 dst_mask = 0x8d; 656 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); 657 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 658 65536 / popcount(dst_mask)); 659 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 660 checkMonotoneOrZero(u16ary, 65536); 661 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); 662 663 // Test with a gap in destination: 664 // Input 4 samples, output 3 samples, one deleted 665 src_mask = 0x0f; 666 dst_mask = 0x8c; 667 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); 668 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 669 65536 / popcount(src_mask)); 670 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); 671 checkMonotone(u16ary, 65536 * 3 / 4); 672 673 delete[] u16ref; 674 delete[] u16ary; 675 delete[] u24ref; 676 delete[] u24ary; 677 } 678 679 TEST(audio_utils_primitives, updown_mix) { 680 const size_t size = 32767; 681 std::vector<int16_t> i16ref(size * 2); 682 std::vector<int16_t> i16ary(size * 2); 683 684 for (size_t i = 0; i < size; ++i) { 685 i16ref[i] = i; 686 } 687 upmix_to_stereo_i16_from_mono_i16(i16ary.data(), i16ref.data(), size); 688 downmix_to_mono_i16_from_stereo_i16(i16ary.data(), i16ary.data(), size); 689 690 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), sizeof(i16ref[0]) * size)); 691 } 692 693 template<typename T, typename TComparison> 694 void checkAddedClamped(T *out, const T *in1, const T *in2, size_t size, 695 TComparison limNeg, TComparison limPos) 696 { 697 for (size_t i = 0; i < size; ++i) { 698 TComparison added = (TComparison)in1[i] + in2[i]; 699 if (added <= limNeg) { 700 EXPECT_EQ(limNeg, out[i]); 701 } else if (added >= limPos) { 702 EXPECT_EQ(limPos, out[i]); 703 } else { 704 EXPECT_EQ(added, out[i]); 705 } 706 } 707 } 708 709 void checkAddedClampedp24(uint8_t *pary, const uint8_t *in1, 710 const uint8_t *in2, size_t size) { 711 // Convert to q8_23 for comparison. 712 int32_t *outi32ary = new int32_t[size]; 713 int32_t *in1i32ary = new int32_t[size]; 714 int32_t *in2i32ary = new int32_t[size]; 715 memcpy_to_q8_23_from_p24(outi32ary, pary, size); 716 memcpy_to_q8_23_from_p24(in1i32ary, in1, size); 717 memcpy_to_q8_23_from_p24(in2i32ary, in2, size); 718 checkAddedClamped( 719 outi32ary, in1i32ary, in2i32ary, size, lim24neg, lim24pos); 720 delete[] in2i32ary; 721 delete[] in1i32ary; 722 delete[] outi32ary; 723 } 724 725 void checkAddedClampedu8(uint8_t *out, const uint8_t *in1, 726 const uint8_t *in2, size_t size) { 727 // uint8_t data is centered around 0x80, not 0, so checkAddedClamped 728 // won't work. Convert to i16 first. 729 int16_t *outi16ary = new int16_t[size]; 730 int16_t *in1i16ary = new int16_t[size]; 731 int16_t *in2i16ary = new int16_t[size]; 732 memcpy_to_i16_from_u8(outi16ary, out, size); 733 memcpy_to_i16_from_u8(in1i16ary, in1, size); 734 memcpy_to_i16_from_u8(in2i16ary, in2, size); 735 // Only the higher order bits are used. 736 checkAddedClamped(outi16ary, in1i16ary, in2i16ary, size, 737 -0x8000, 0x7f00); 738 delete[] in2i16ary; 739 delete[] in1i16ary; 740 delete[] outi16ary; 741 } 742 743 TEST(audio_utils_primitives, accumulate) { 744 int16_t *i16ref = new int16_t[65536]; 745 int16_t *i16add = new int16_t[65536]; 746 int16_t *i16ary = new int16_t[65536]; 747 748 for (size_t i = 0; i < 65536; ++i) { 749 i16ref[i] = i16ary[i] = i16add[(i+1) % 65536] = i - 32768; 750 } 751 752 // Test i16. 753 accumulate_i16(i16ary, i16add, 65536); 754 checkAddedClamped(i16ary, i16ref, i16add, 65536, lim16neg, 755 lim16pos); 756 757 // Test i32. 758 int32_t *i32ary = new int32_t[65536]; 759 int32_t *i32add = new int32_t[65536]; 760 int32_t *i32ref = new int32_t[65536]; 761 // Convert sample data to i32 to perform accumulate function. 762 memcpy_to_i32_from_i16(i32ary, i16ref, 65536); 763 memcpy_to_i32_from_i16(i32add, i16add, 65536); 764 // Ensure the reference matches the inital output after conversion. 765 memcpy(i32ref, i32ary, 65536 * sizeof(i32ary[0])); 766 // Accumulate and check. 767 accumulate_i32(i32ary, i32add, 65536); 768 checkAddedClamped( 769 i32ary, i32ref, i32add, 65536, lim32neg, lim32pos); 770 // Cleanup 771 delete[] i32ref; 772 delete[] i32add; 773 delete[] i32ary; 774 775 // Test u8. 776 uint8_t *u8ary = new uint8_t[65536]; 777 uint8_t *u8add = new uint8_t[65536]; 778 uint8_t *u8ref = new uint8_t[65536]; 779 // Convert sample data to u8 to perform accumulate function. 780 memcpy_to_u8_from_i16(u8ary, i16ref, 65536); 781 memcpy_to_u8_from_i16(u8add, i16add, 65536); 782 // Ensure the reference matches the inital output after conversion. 783 memcpy(u8ref, u8ary, 65536 * sizeof(u8ary[0])); 784 // Accumulate and check. 785 accumulate_u8(u8ary, u8add, 65536); 786 checkAddedClampedu8(u8ary, u8ref, u8add, 65536); 787 // Cleanup. 788 delete[] u8ref; 789 delete[] u8add; 790 delete[] u8ary; 791 792 // Test 24 bit packed. 793 uint8_t *pary = new uint8_t[65536 * 3]; 794 uint8_t *padd = new uint8_t[65536 * 3]; 795 uint8_t *pref = new uint8_t[65536 * 3]; 796 // Convert sample data to p24 to perform accumulate function. 797 memcpy_to_p24_from_i16(pary, i16ref, 65536); 798 memcpy_to_p24_from_i16(padd, i16add, 65536); 799 // Ensure the reference matches the inital output after conversion. 800 memcpy(pref, pary, 65536 * sizeof(pary[0]) * 3); 801 // Accumulate and check. 802 accumulate_p24(pary, padd, 65536); 803 checkAddedClampedp24(pary, pref, padd, 65536); 804 // Cleanup. 805 delete[] pref; 806 delete[] padd; 807 delete[] pary; 808 809 // Test 24 bit unpacked. 810 int32_t *q8_23ary = new int32_t[65536]; 811 int32_t *q8_23add = new int32_t[65536]; 812 int32_t *q8_23ref = new int32_t[65536]; 813 // Convert sample data to q8_23 to perform accumulate function. 814 memcpy_to_q8_23_from_i16(q8_23ary, i16ref, 65536); 815 memcpy_to_q8_23_from_i16(q8_23add, i16add, 65536); 816 // Ensure the reference matches the inital output after conversion. 817 memcpy(q8_23ref, q8_23ary, 65536 * sizeof(q8_23ary[0])); 818 // Accumulate and check. 819 accumulate_q8_23(q8_23ary, q8_23add, 65536); 820 checkAddedClamped( 821 q8_23ary, q8_23ref, q8_23add, 65536, lim24neg, lim24pos); 822 // Cleanup. 823 delete[] q8_23ref; 824 delete[] q8_23add; 825 delete[] q8_23ary; 826 827 // Test float. 828 float *fary = new float[65536]; 829 float *fadd = new float[65536]; 830 float *fref = new float[65536]; 831 // Convert sample data to float to perform accumulate function. 832 memcpy_to_float_from_i16(fary, i16ref, 65536); 833 memcpy_to_float_from_i16(fadd, i16add, 65536); 834 // Ensure the reference matches the inital output after conversion. 835 memcpy(fref, fary, 65536 * sizeof(fary[0])); 836 // Accumulate and check. Floats aren't clamped by accumulate, 837 // but given the input is in the [-1.0, 1.0) range output should be in 838 // [-2.0, 2.0) range. 839 accumulate_float(fary, fadd, 65536); 840 checkAddedClamped(fary, fref, fadd, 65536, -2.0f, 2.0f); 841 // Cleanup. 842 delete[] fref; 843 delete[] fadd; 844 delete[] fary; 845 846 delete[] i16ary; 847 delete[] i16add; 848 delete[] i16ref; 849 } 850 851 852 TEST(audio_utils_primitives, MemcpyToFloatFromFloatWithClamping) { 853 std::vector<float> src = {-INFINITY, -2, -1, -0, 0, 0.009, 1.000001, 9999999, INFINITY, NAN}; 854 std::vector<float> dst(src.size()); 855 float absMax = 1; 856 std::vector<float> expected = {-1, -1, -1, -0, 0, 0.009, 1, 1, 1, 1}; 857 ASSERT_EQ(expected.size(), src.size()); 858 859 memcpy_to_float_from_float_with_clamping(dst.data(), src.data(), src.size(), absMax); 860 861 ASSERT_EQ(dst, expected) << "src=" << testing::PrintToString(src); 862 } 863