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 
     39 inline void testClamp8(float f)
     40 {
     41     // f is in native u8 scaling to test rounding
     42     uint8_t uval = clamp8_from_float((f - 128) / (1 << 7));
     43 
     44     // test clamping
     45     ALOGV("clamp8_from_float(%f) = %u\n", f, uval);
     46     if (f > lim8pos) {
     47         EXPECT_EQ(lim8pos, uval);
     48     } else if (f < lim8neg) {
     49         EXPECT_EQ(lim8neg, uval);
     50     }
     51 
     52     // if in range, make sure round trip clamp and conversion is correct.
     53     if (f < lim8pos - 1. && f > lim8neg + 1.) {
     54         uint8_t uval2 = clamp8_from_float(float_from_u8(uval));
     55         int diff = abs(uval - uval2);
     56         EXPECT_LE(diff, 1);
     57     }
     58 }
     59 
     60 inline void testClamp16(float f)
     61 {
     62     int16_t ival = clamp16_from_float(f / (1 << 15));
     63 
     64     // test clamping
     65     ALOGV("clamp16_from_float(%f) = %d\n", f, ival);
     66     if (f > lim16pos) {
     67         EXPECT_EQ(lim16pos, ival);
     68     } else if (f < lim16neg) {
     69         EXPECT_EQ(lim16neg, ival);
     70     }
     71 
     72     // if in range, make sure round trip clamp and conversion is correct.
     73     if (f < lim16pos - 1. && f > lim16neg + 1.) {
     74         int ival2 = clamp16_from_float(float_from_i16(ival));
     75         int diff = abs(ival - ival2);
     76         EXPECT_LE(diff, 1);
     77     }
     78 }
     79 
     80 inline void testClamp24(float f)
     81 {
     82     int32_t ival = clamp24_from_float(f / (1 << 23));
     83 
     84     // test clamping
     85     ALOGV("clamp24_from_float(%f) = %d\n", f, ival);
     86     if (f > lim24pos) {
     87         EXPECT_EQ(lim24pos, ival);
     88     } else if (f < lim24neg) {
     89         EXPECT_EQ(lim24neg, ival);
     90     }
     91 
     92     // if in range, make sure round trip clamp and conversion is correct.
     93     if (f < lim24pos - 1. && f > lim24neg + 1.) {
     94         int ival2 = clamp24_from_float(float_from_q8_23(ival));
     95         int diff = abs(ival - ival2);
     96         EXPECT_LE(diff, 1);
     97     }
     98 }
     99 
    100 template<typename T>
    101 void checkMonotone(const T *ary, size_t size)
    102 {
    103     for (size_t i = 1; i < size; ++i) {
    104         EXPECT_LT(ary[i-1], ary[i]);
    105     }
    106 }
    107 
    108 void checkMonotonep24(uint8_t * pary, size_t size)
    109 {
    110     size_t frames = size/3;
    111     for (size_t i = 1; i < frames; ++i) {
    112         EXPECT_LT(i32_from_p24(pary + 3*(i-1)), i32_from_p24(pary + 3*i));
    113     }
    114 }
    115 
    116 TEST(audio_utils_primitives, clamp_to_int) {
    117     static const float testArray[] = {
    118             -NAN, -INFINITY,
    119             -1.e20, -32768., 63.9,
    120             -3.5, -3.4, -2.5, 2.4, -1.5, -1.4, -0.5, -0.2, 0., 0.2, 0.5, 0.8,
    121             1.4, 1.5, 1.8, 2.4, 2.5, 2.6, 3.4, 3.5,
    122             32767., 32768., 1.e20,
    123             INFINITY, NAN };
    124 
    125     for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
    126         testClamp8(testArray[i]);
    127     }
    128     for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
    129         testClamp16(testArray[i]);
    130     }
    131     for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
    132         testClamp24(testArray[i]);
    133     }
    134 
    135     // used for ULP testing (tweaking the lsb of the float)
    136     union {
    137         int32_t i;
    138         float f;
    139     } val;
    140     int32_t res;
    141 
    142     // check clampq4_27_from_float()
    143     val.f = 16.;
    144     res = clampq4_27_from_float(val.f);
    145     EXPECT_EQ(0x7fffffff, res);
    146     val.i--;
    147     res = clampq4_27_from_float(val.f);
    148     EXPECT_LE(res, 0x7fffffff);
    149     EXPECT_GE(res, 0x7fff0000);
    150     val.f = -16.;
    151     res = clampq4_27_from_float(val.f);
    152     EXPECT_EQ((int32_t)0x80000000, res); // negative
    153     val.i++;
    154     res = clampq4_27_from_float(val.f);
    155     EXPECT_GE(res, (int32_t)0x80000000); // negative
    156     EXPECT_LE(res, (int32_t)0x80008000); // negative
    157 
    158     // check u4_28_from_float and u4_12_from_float
    159     uint32_t ures;
    160     uint16_t ures16;
    161     val.f = 16.;
    162     ures = u4_28_from_float(val.f);
    163     EXPECT_EQ(0xffffffff, ures);
    164     ures16 = u4_12_from_float(val.f);
    165     EXPECT_EQ(0xffff, ures16);
    166 
    167     val.f = -1.;
    168     ures = u4_28_from_float(val.f);
    169     EXPECT_EQ((uint32_t)0, ures);
    170     ures16 = u4_12_from_float(val.f);
    171     EXPECT_EQ(0, ures16);
    172 
    173     // check float_from_u4_28 and float_from_u4_12 (roundtrip)
    174     for (uint32_t v = 0x100000; v <= 0xff000000; v += 0x100000) {
    175         ures = u4_28_from_float(float_from_u4_28(v));
    176         EXPECT_EQ(ures, v);
    177     }
    178     for (uint32_t v = 0; v <= 0xffff; ++v) { // uint32_t prevents overflow
    179         ures16 = u4_12_from_float(float_from_u4_12(v));
    180         EXPECT_EQ(ures16, v);
    181     }
    182 
    183     // check infinity
    184     EXPECT_EQ(0, clamp8_from_float(-INFINITY));
    185     EXPECT_EQ(255, clamp8_from_float(INFINITY));
    186 }
    187 
    188 TEST(audio_utils_primitives, memcpy) {
    189     // test round-trip.
    190     int16_t *i16ref = new int16_t[65536];
    191     int16_t *i16ary = new int16_t[65536];
    192     int32_t *i32ary = new int32_t[65536];
    193     float *fary = new float[65536];
    194     uint8_t *pary = new uint8_t[65536*3];
    195 
    196     for (size_t i = 0; i < 65536; ++i) {
    197         i16ref[i] = i16ary[i] = i - 32768;
    198     }
    199 
    200     // do round-trip testing i16 and float
    201     memcpy_to_float_from_i16(fary, i16ary, 65536);
    202     memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
    203     checkMonotone(fary, 65536);
    204 
    205     memcpy_to_i16_from_float(i16ary, fary, 65536);
    206     memset(fary, 0, 65536 * sizeof(fary[0]));
    207     checkMonotone(i16ary, 65536);
    208 
    209     // TODO make a template case for the following?
    210 
    211     // do round-trip testing p24 to i16 and float
    212     memcpy_to_p24_from_i16(pary, i16ary, 65536);
    213     memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
    214 
    215     // check an intermediate format at a position(???)
    216 #if 0
    217     printf("pary[%d].0 = %u  pary[%d].1 = %u  pary[%d].2 = %u\n",
    218             1025, (unsigned) pary[1025*3],
    219             1025, (unsigned) pary[1025*3+1],
    220             1025, (unsigned) pary[1025*3+2]
    221             );
    222 #endif
    223 
    224     memcpy_to_float_from_p24(fary, pary, 65536);
    225     memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
    226     checkMonotone(fary, 65536);
    227 
    228     memcpy_to_p24_from_float(pary, fary, 65536);
    229     memset(fary, 0, 65536 * sizeof(fary[0]));
    230 
    231     memcpy_to_i16_from_p24(i16ary, pary, 65536);
    232     memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
    233     checkMonotone(i16ary, 65536);
    234 
    235     // do round-trip testing q8_23 to i16 and float
    236     memcpy_to_q8_23_from_i16(i32ary, i16ary, 65536);
    237     memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
    238     checkMonotone(i32ary, 65536);
    239 
    240     memcpy_to_float_from_q8_23(fary, i32ary, 65536);
    241     memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
    242     checkMonotone(fary, 65536);
    243 
    244     memcpy_to_q8_23_from_float_with_clamp(i32ary, fary, 65536);
    245     memset(fary, 0, 65536 * sizeof(fary[0]));
    246     checkMonotone(i32ary, 65536);
    247 
    248     memcpy_to_i16_from_q8_23(i16ary, i32ary, 65536);
    249     memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
    250     checkMonotone(i16ary, 65536);
    251 
    252     // do round-trip testing i32 to i16 and float
    253     memcpy_to_i32_from_i16(i32ary, i16ary, 65536);
    254     memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
    255     checkMonotone(i32ary, 65536);
    256 
    257     memcpy_to_float_from_i32(fary, i32ary, 65536);
    258     memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
    259     checkMonotone(fary, 65536);
    260 
    261     memcpy_to_i32_from_float(i32ary, fary, 65536);
    262     memset(fary, 0, 65536 * sizeof(fary[0]));
    263     checkMonotone(i32ary, 65536);
    264 
    265     memcpy_to_i16_from_i32(i16ary, i32ary, 65536);
    266     memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
    267     checkMonotone(i16ary, 65536);
    268 
    269     // do round-trip test i16 -> p24 -> i32 -> p24 -> q8_23 -> p24 -> i16
    270     memcpy_to_p24_from_i16(pary, i16ary, 65536);
    271     memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
    272     checkMonotonep24(pary, 65536 * 3);
    273 
    274     memcpy_to_i32_from_p24(i32ary, pary, 65536);
    275     memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
    276     checkMonotone(i32ary, 65536);
    277 
    278     memcpy_to_p24_from_i32(pary, i32ary, 65536);
    279     memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
    280     checkMonotonep24(pary, 65536 * 3);
    281 
    282     memcpy_to_q8_23_from_p24(i32ary, pary, 65536);
    283     memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
    284     checkMonotone(i32ary, 65536);
    285 
    286     memcpy_to_p24_from_q8_23(pary, i32ary, 65536);
    287     memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
    288     checkMonotonep24(pary, 65536 * 3);
    289 
    290     memcpy_to_i16_from_p24(i16ary, pary, 65536);
    291     memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
    292     checkMonotone(i16ary, 65536);
    293 
    294     // do partial round-trip testing q4_27 to i16 and float
    295     memcpy_to_float_from_i16(fary, i16ary, 65536);
    296     //memset(i16ary, 0, 65536 * sizeof(i16ary[0])); // not cleared: we don't do full roundtrip
    297 
    298     memcpy_to_q4_27_from_float(i32ary, fary, 65536);
    299     memset(fary, 0, 65536 * sizeof(fary[0]));
    300     checkMonotone(i32ary, 65536);
    301 
    302     memcpy_to_float_from_q4_27(fary, i32ary, 65536);
    303     memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
    304     checkMonotone(fary, 65536);
    305 
    306     // at the end, our i16ary must be the same. (Monotone should be equivalent to this)
    307     EXPECT_EQ(0, memcmp(i16ary, i16ref, 65536*sizeof(i16ary[0])));
    308 
    309     // test round-trip for u8 and float.
    310     uint8_t *u8ref = new uint8_t[256];
    311     uint8_t *u8ary = new uint8_t[256];
    312 
    313     for (unsigned i = 0; i < 256; ++i) {
    314         u8ref[i] = i;
    315     }
    316 
    317     memcpy_to_float_from_u8(fary, u8ref, 256);
    318     memcpy_to_u8_from_float(u8ary, fary, 256);
    319 
    320     EXPECT_EQ(0, memcmp(u8ary, u8ref, 256 * sizeof(u8ary[0])));
    321 
    322     delete[] u8ref;
    323     delete[] u8ary;
    324     delete[] i16ref;
    325     delete[] i16ary;
    326     delete[] i32ary;
    327     delete[] fary;
    328     delete[] pary;
    329 }
    330 
    331 template<typename T>
    332 void checkMonotoneOrZero(const T *ary, size_t size)
    333 {
    334     T least = 0;
    335 
    336     for (size_t i = 1; i < size; ++i) {
    337         if (ary[i]) {
    338             EXPECT_LT(least, ary[i]);
    339             least = ary[i];
    340         }
    341     }
    342 }
    343 
    344 TEST(audio_utils_primitives, memcpy_by_channel_mask) {
    345     uint32_t dst_mask;
    346     uint32_t src_mask;
    347     uint16_t *u16ref = new uint16_t[65536];
    348     uint16_t *u16ary = new uint16_t[65536];
    349 
    350     for (size_t i = 0; i < 65536; ++i) {
    351         u16ref[i] = i;
    352     }
    353 
    354     // Test when src mask is 0.  Everything copied is zero.
    355     src_mask = 0;
    356     dst_mask = 0x8d;
    357     memset(u16ary, 0x99, 65536 * sizeof(u16ref[0]));
    358     memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
    359             65536 / popcount(dst_mask));
    360     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    361 
    362     // Test when dst_mask is 0.  Nothing should be copied.
    363     src_mask = 0;
    364     dst_mask = 0;
    365     memset(u16ary, 0, 65536 * sizeof(u16ref[0]));
    366     memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
    367             65536);
    368     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    369 
    370     // Test when masks are the same.  One to one copy.
    371     src_mask = dst_mask = 0x8d;
    372     memset(u16ary, 0x99, 65536 * sizeof(u16ref[0]));
    373     memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 555);
    374     EXPECT_EQ(0, memcmp(u16ary, u16ref, 555 * sizeof(u16ref[0]) * popcount(dst_mask)));
    375 
    376     // Test with a gap in source:
    377     // Input 3 samples, output 4 samples, one zero inserted.
    378     src_mask = 0x8c;
    379     dst_mask = 0x8d;
    380     memset(u16ary, 0x9, 65536 * sizeof(u16ary[0]));
    381     memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
    382             65536 / popcount(dst_mask));
    383     checkMonotoneOrZero(u16ary, 65536);
    384     EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
    385 
    386     // Test with a gap in destination:
    387     // Input 4 samples, output 3 samples, one deleted
    388     src_mask = 0x8d;
    389     dst_mask = 0x8c;
    390     memset(u16ary, 0x9, 65536 * sizeof(u16ary[0]));
    391     memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
    392             65536 / popcount(src_mask));
    393     checkMonotone(u16ary, 65536 * 3 / 4);
    394 
    395     delete[] u16ref;
    396     delete[] u16ary;
    397 }
    398 
    399 void memcpy_by_channel_mask2(void *dst, uint32_t dst_mask,
    400         const void *src, uint32_t src_mask, size_t sample_size, size_t count)
    401 {
    402     int8_t idxary[32];
    403     uint32_t src_channels = popcount(src_mask);
    404     uint32_t dst_channels =
    405             memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask);
    406 
    407     memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
    408 }
    409 
    410 // a modified version of the memcpy_by_channel_mask test
    411 // but using 24 bit type and memcpy_by_index_array()
    412 TEST(audio_utils_primitives, memcpy_by_index_array) {
    413     uint32_t dst_mask;
    414     uint32_t src_mask;
    415     typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
    416     uint8x3_t *u24ref = new uint8x3_t[65536];
    417     uint8x3_t *u24ary = new uint8x3_t[65536];
    418     uint16_t *u16ref = new uint16_t[65536];
    419     uint16_t *u16ary = new uint16_t[65536];
    420 
    421     EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
    422 
    423     // tests prepare_index_array_from_masks()
    424     EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization(NULL, 0, 0x8d, 0x8c));
    425     EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization(NULL, 0, 0x8c, 0x8d));
    426 
    427     for (size_t i = 0; i < 65536; ++i) {
    428         u16ref[i] = i;
    429     }
    430     memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
    431 
    432     // Test when src mask is 0.  Everything copied is zero.
    433     src_mask = 0;
    434     dst_mask = 0x8d;
    435     memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
    436     memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    437             65536 / popcount(dst_mask));
    438     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    439     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    440 
    441     // Test when dst_mask is 0.  Nothing should be copied.
    442     src_mask = 0;
    443     dst_mask = 0;
    444     memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
    445     memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    446             65536);
    447     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    448     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    449 
    450     // Test when masks are the same.  One to one copy.
    451     src_mask = dst_mask = 0x8d;
    452     memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
    453     memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
    454     EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
    455 
    456     // Test with a gap in source:
    457     // Input 3 samples, output 4 samples, one zero inserted.
    458     src_mask = 0x8c;
    459     dst_mask = 0x8d;
    460     memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
    461     memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    462             65536 / popcount(dst_mask));
    463     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    464     checkMonotoneOrZero(u16ary, 65536);
    465     EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
    466 
    467     // Test with a gap in destination:
    468     // Input 4 samples, output 3 samples, one deleted
    469     src_mask = 0x8d;
    470     dst_mask = 0x8c;
    471     memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
    472     memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    473             65536 / popcount(src_mask));
    474     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    475     checkMonotone(u16ary, 65536 * 3 / 4);
    476 
    477     delete[] u16ref;
    478     delete[] u16ary;
    479     delete[] u24ref;
    480     delete[] u24ary;
    481 }
    482 
    483 void memcpy_by_channel_mask_dst_index(void *dst, uint32_t dst_mask,
    484         const void *src, uint32_t src_mask, size_t sample_size, size_t count)
    485 {
    486     int8_t idxary[32];
    487     uint32_t src_channels = popcount(src_mask);
    488     uint32_t dst_channels =
    489             memcpy_by_index_array_initialization_dst_index(idxary, 32, dst_mask, src_mask);
    490 
    491     memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
    492 }
    493 
    494 // a modified version of the memcpy_by_channel_mask test
    495 // but using 24 bit type and memcpy_by_index_array()
    496 TEST(audio_utils_primitives, memcpy_by_index_array_dst_index) {
    497     uint32_t dst_mask;
    498     uint32_t src_mask;
    499     typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
    500     uint8x3_t *u24ref = new uint8x3_t[65536];
    501     uint8x3_t *u24ary = new uint8x3_t[65536];
    502     uint16_t *u16ref = new uint16_t[65536];
    503     uint16_t *u16ary = new uint16_t[65536];
    504 
    505     EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
    506 
    507     // tests prepare_index_array_from_masks()
    508     EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8d, 0x8c));
    509     EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8c, 0x8d));
    510 
    511     for (size_t i = 0; i < 65536; ++i) {
    512         u16ref[i] = i;
    513     }
    514     memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
    515 
    516     // Test when src mask is 0.  Everything copied is zero.
    517     src_mask = 0;
    518     dst_mask = 0x8d;
    519     memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
    520     memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    521             65536 / popcount(dst_mask));
    522     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    523     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    524 
    525     // Test when dst_mask is 0.  Nothing should be copied.
    526     src_mask = 0;
    527     dst_mask = 0;
    528     memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
    529     memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    530             65536);
    531     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    532     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    533 
    534     // Test when dst mask equals source count size.  One to one copy.
    535     src_mask = 0x8d;
    536     dst_mask = 0x0f;
    537     memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
    538     memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
    539     EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
    540 
    541     // Test with a gap in source:
    542     // Input 3 samples, output 4 samples, one zero inserted.
    543     src_mask = 0x8c;
    544     dst_mask = 0x0f;
    545     memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
    546     memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    547             65536 / popcount(dst_mask));
    548     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    549     checkMonotoneOrZero(u16ary, 65536);
    550     EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
    551 
    552     // Test with a gap in destination:
    553     // Input 4 samples, output 3 samples, one deleted
    554     src_mask = 0x8d;
    555     dst_mask = 0x07;
    556     memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
    557     memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    558             65536 / popcount(src_mask));
    559     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    560     checkMonotone(u16ary, 65536 * 3 / 4);
    561 
    562     delete[] u16ref;
    563     delete[] u16ary;
    564     delete[] u24ref;
    565     delete[] u24ary;
    566 }
    567 
    568 void memcpy_by_channel_mask_src_index(void *dst, uint32_t dst_mask,
    569         const void *src, uint32_t src_mask, size_t sample_size, size_t count)
    570 {
    571     int8_t idxary[32];
    572     uint32_t src_channels = popcount(src_mask);
    573     uint32_t dst_channels =
    574             memcpy_by_index_array_initialization_src_index(idxary, 32, dst_mask, src_mask);
    575 
    576     memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
    577 }
    578 
    579 // a modified version of the memcpy_by_channel_mask test
    580 // but using 24 bit type and memcpy_by_index_array()
    581 TEST(audio_utils_primitives, memcpy_by_index_array_src_index) {
    582     uint32_t dst_mask;
    583     uint32_t src_mask;
    584     typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
    585     uint8x3_t *u24ref = new uint8x3_t[65536];
    586     uint8x3_t *u24ary = new uint8x3_t[65536];
    587     uint16_t *u16ref = new uint16_t[65536];
    588     uint16_t *u16ary = new uint16_t[65536];
    589 
    590     EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
    591 
    592     // tests prepare_index_array_from_masks()
    593     EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8d, 0x8c));
    594     EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8c, 0x8d));
    595 
    596     for (size_t i = 0; i < 65536; ++i) {
    597         u16ref[i] = i;
    598     }
    599     memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
    600 
    601     // Test when src mask is 0.  Everything copied is zero.
    602     src_mask = 0;
    603     dst_mask = 0x8d;
    604     memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
    605     memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    606             65536 / popcount(dst_mask));
    607     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    608     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    609 
    610     // Test when dst_mask is 0.  Nothing should be copied.
    611     src_mask = 0;
    612     dst_mask = 0;
    613     memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
    614     memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    615             65536);
    616     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    617     EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
    618 
    619     // Test when source mask must copy to dst mask.  One to one copy.
    620     src_mask = 0xf;
    621     dst_mask = 0xf;
    622     memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
    623     memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
    624     EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
    625 
    626     // Test when source mask must copy to dst mask.  One to one copy.
    627     src_mask = 0xf;
    628     dst_mask = 0x8d;
    629     memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
    630     memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
    631     EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
    632 
    633     // Test with a gap in source:
    634     // Input 3 samples, output 4 samples, one zero inserted.
    635     src_mask = 0x07;
    636     dst_mask = 0x8d;
    637     memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
    638     memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    639             65536 / popcount(dst_mask));
    640     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    641     checkMonotoneOrZero(u16ary, 65536);
    642     EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
    643 
    644     // Test with a gap in destination:
    645     // Input 4 samples, output 3 samples, one deleted
    646     src_mask = 0x0f;
    647     dst_mask = 0x8c;
    648     memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
    649     memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
    650             65536 / popcount(src_mask));
    651     memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
    652     checkMonotone(u16ary, 65536 * 3 / 4);
    653 
    654     delete[] u16ref;
    655     delete[] u16ary;
    656     delete[] u24ref;
    657     delete[] u24ary;
    658 }
    659 
    660 TEST(audio_utils_channels, adjust_channels) {
    661     uint16_t *u16ref = new uint16_t[65536];
    662     uint16_t *u16expand = new uint16_t[65536*2];
    663     uint16_t *u16ary = new uint16_t[65536];
    664 
    665     // reference buffer always increases
    666     for (size_t i = 0; i < 65536; ++i) {
    667         u16ref[i] = i;
    668     }
    669 
    670     // expand channels from stereo to quad.
    671     adjust_channels(u16ref /*in_buff*/, 2 /*in_channels*/,
    672             u16expand /*out_buff*/, 4 /*out_channels*/,
    673             sizeof(u16ref[0]) /*sample_size_in_bytes*/,
    674             sizeof(u16ref[0])*65536 /*num_in_bytes*/);
    675 
    676     // expanded buffer must increase (or be zero)
    677     checkMonotoneOrZero(u16expand, 65536*2);
    678 
    679     // contract channels back to stereo.
    680     adjust_channels(u16expand /*in_buff*/, 4 /*in_channels*/,
    681             u16ary /*out_buff*/, 2 /*out_channels*/,
    682             sizeof(u16expand[0]) /*sample_size_in_bytes*/,
    683             sizeof(u16expand[0])*65536*2 /*num_in_bytes*/);
    684 
    685     // must be identical to original.
    686     EXPECT_EQ(0, memcmp(u16ary, u16ref, sizeof(u16ref[0])*65536));
    687 
    688     delete[] u16ref;
    689     delete[] u16expand;
    690     delete[] u16ary;
    691 }
    692