Home | History | Annotate | Download | only in tests
      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