You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
691 lines
24 KiB
691 lines
24 KiB
/* |
|
* Copyright (C) 2014 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
//#define LOG_NDEBUG 0 |
|
#define LOG_TAG "audio_utils_primitives_tests" |
|
|
|
#include <math.h> |
|
#include <vector> |
|
|
|
#include <gtest/gtest.h> |
|
#include <log/log.h> |
|
|
|
#include <audio_utils/primitives.h> |
|
#include <audio_utils/format.h> |
|
#include <audio_utils/channels.h> |
|
|
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) |
|
|
|
static const int32_t lim8pos = 255; |
|
static const int32_t lim8neg = 0; |
|
static const int32_t lim16pos = (1 << 15) - 1; |
|
static const int32_t lim16neg = -(1 << 15); |
|
static const int32_t lim24pos = (1 << 23) - 1; |
|
static const int32_t lim24neg = -(1 << 23); |
|
|
|
inline void testClamp8(float f) |
|
{ |
|
// f is in native u8 scaling to test rounding |
|
uint8_t uval = clamp8_from_float((f - 128) / (1 << 7)); |
|
|
|
// test clamping |
|
ALOGV("clamp8_from_float(%f) = %u\n", f, uval); |
|
if (f > lim8pos) { |
|
EXPECT_EQ(lim8pos, uval); |
|
} else if (f < lim8neg) { |
|
EXPECT_EQ(lim8neg, uval); |
|
} |
|
|
|
// if in range, make sure round trip clamp and conversion is correct. |
|
if (f < lim8pos - 1. && f > lim8neg + 1.) { |
|
uint8_t uval2 = clamp8_from_float(float_from_u8(uval)); |
|
int diff = abs(uval - uval2); |
|
EXPECT_LE(diff, 1); |
|
} |
|
} |
|
|
|
inline void testClamp16(float f) |
|
{ |
|
int16_t ival = clamp16_from_float(f / (1 << 15)); |
|
|
|
// test clamping |
|
ALOGV("clamp16_from_float(%f) = %d\n", f, ival); |
|
if (f > lim16pos) { |
|
EXPECT_EQ(lim16pos, ival); |
|
} else if (f < lim16neg) { |
|
EXPECT_EQ(lim16neg, ival); |
|
} |
|
|
|
// if in range, make sure round trip clamp and conversion is correct. |
|
if (f < lim16pos - 1. && f > lim16neg + 1.) { |
|
int ival2 = clamp16_from_float(float_from_i16(ival)); |
|
int diff = abs(ival - ival2); |
|
EXPECT_LE(diff, 1); |
|
} |
|
} |
|
|
|
inline void testClamp24(float f) |
|
{ |
|
int32_t ival = clamp24_from_float(f / (1 << 23)); |
|
|
|
// test clamping |
|
ALOGV("clamp24_from_float(%f) = %d\n", f, ival); |
|
if (f > lim24pos) { |
|
EXPECT_EQ(lim24pos, ival); |
|
} else if (f < lim24neg) { |
|
EXPECT_EQ(lim24neg, ival); |
|
} |
|
|
|
// if in range, make sure round trip clamp and conversion is correct. |
|
if (f < lim24pos - 1. && f > lim24neg + 1.) { |
|
int ival2 = clamp24_from_float(float_from_q8_23(ival)); |
|
int diff = abs(ival - ival2); |
|
EXPECT_LE(diff, 1); |
|
} |
|
} |
|
|
|
template<typename T> |
|
void checkMonotone(const T *ary, size_t size) |
|
{ |
|
for (size_t i = 1; i < size; ++i) { |
|
EXPECT_LT(ary[i-1], ary[i]); |
|
} |
|
} |
|
|
|
void checkMonotonep24(uint8_t * pary, size_t size) |
|
{ |
|
size_t frames = size/3; |
|
for (size_t i = 1; i < frames; ++i) { |
|
EXPECT_LT(i32_from_p24(pary + 3*(i-1)), i32_from_p24(pary + 3*i)); |
|
} |
|
} |
|
|
|
TEST(audio_utils_primitives, clamp_to_int) { |
|
static const float testArray[] = { |
|
-NAN, -INFINITY, |
|
-1.e20, -32768., 63.9, |
|
-3.5, -3.4, -2.5, 2.4, -1.5, -1.4, -0.5, -0.2, 0., 0.2, 0.5, 0.8, |
|
1.4, 1.5, 1.8, 2.4, 2.5, 2.6, 3.4, 3.5, |
|
32767., 32768., 1.e20, |
|
INFINITY, NAN }; |
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) { |
|
testClamp8(testArray[i]); |
|
} |
|
for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) { |
|
testClamp16(testArray[i]); |
|
} |
|
for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) { |
|
testClamp24(testArray[i]); |
|
} |
|
|
|
// used for ULP testing (tweaking the lsb of the float) |
|
union { |
|
int32_t i; |
|
float f; |
|
} val; |
|
int32_t res; |
|
|
|
// check clampq4_27_from_float() |
|
val.f = 16.; |
|
res = clampq4_27_from_float(val.f); |
|
EXPECT_EQ(0x7fffffff, res); |
|
val.i--; |
|
res = clampq4_27_from_float(val.f); |
|
EXPECT_LE(res, 0x7fffffff); |
|
EXPECT_GE(res, 0x7fff0000); |
|
val.f = -16.; |
|
res = clampq4_27_from_float(val.f); |
|
EXPECT_EQ((int32_t)0x80000000, res); // negative |
|
val.i++; |
|
res = clampq4_27_from_float(val.f); |
|
EXPECT_GE(res, (int32_t)0x80000000); // negative |
|
EXPECT_LE(res, (int32_t)0x80008000); // negative |
|
|
|
// check u4_28_from_float and u4_12_from_float |
|
uint32_t ures; |
|
uint16_t ures16; |
|
val.f = 16.; |
|
ures = u4_28_from_float(val.f); |
|
EXPECT_EQ(0xffffffff, ures); |
|
ures16 = u4_12_from_float(val.f); |
|
EXPECT_EQ(0xffff, ures16); |
|
|
|
val.f = -1.; |
|
ures = u4_28_from_float(val.f); |
|
EXPECT_EQ((uint32_t)0, ures); |
|
ures16 = u4_12_from_float(val.f); |
|
EXPECT_EQ(0, ures16); |
|
|
|
// check float_from_u4_28 and float_from_u4_12 (roundtrip) |
|
for (uint32_t v = 0x100000; v <= 0xff000000; v += 0x100000) { |
|
ures = u4_28_from_float(float_from_u4_28(v)); |
|
EXPECT_EQ(ures, v); |
|
} |
|
for (uint32_t v = 0; v <= 0xffff; ++v) { // uint32_t prevents overflow |
|
ures16 = u4_12_from_float(float_from_u4_12(v)); |
|
EXPECT_EQ(ures16, v); |
|
} |
|
|
|
// check infinity |
|
EXPECT_EQ(0, clamp8_from_float(-INFINITY)); |
|
EXPECT_EQ(255, clamp8_from_float(INFINITY)); |
|
} |
|
|
|
TEST(audio_utils_primitives, memcpy) { |
|
// test round-trip. |
|
int16_t *i16ref = new int16_t[65536]; |
|
int16_t *i16ary = new int16_t[65536]; |
|
int32_t *i32ary = new int32_t[65536]; |
|
float *fary = new float[65536]; |
|
uint8_t *pary = new uint8_t[65536*3]; |
|
|
|
for (size_t i = 0; i < 65536; ++i) { |
|
i16ref[i] = i16ary[i] = i - 32768; |
|
} |
|
|
|
// do round-trip testing i16 and float |
|
memcpy_to_float_from_i16(fary, i16ary, 65536); |
|
memset(i16ary, 0, 65536 * sizeof(i16ary[0])); |
|
checkMonotone(fary, 65536); |
|
|
|
memcpy_to_i16_from_float(i16ary, fary, 65536); |
|
memset(fary, 0, 65536 * sizeof(fary[0])); |
|
checkMonotone(i16ary, 65536); |
|
|
|
// TODO make a template case for the following? |
|
|
|
// do round-trip testing p24 to i16 and float |
|
memcpy_to_p24_from_i16(pary, i16ary, 65536); |
|
memset(i16ary, 0, 65536 * sizeof(i16ary[0])); |
|
|
|
// check an intermediate format at a position(???) |
|
#if 0 |
|
printf("pary[%d].0 = %u pary[%d].1 = %u pary[%d].2 = %u\n", |
|
1025, (unsigned) pary[1025*3], |
|
1025, (unsigned) pary[1025*3+1], |
|
1025, (unsigned) pary[1025*3+2] |
|
); |
|
#endif |
|
|
|
memcpy_to_float_from_p24(fary, pary, 65536); |
|
memset(pary, 0, 65536 * 3 * sizeof(pary[0])); |
|
checkMonotone(fary, 65536); |
|
|
|
memcpy_to_p24_from_float(pary, fary, 65536); |
|
memset(fary, 0, 65536 * sizeof(fary[0])); |
|
|
|
memcpy_to_i16_from_p24(i16ary, pary, 65536); |
|
memset(pary, 0, 65536 * 3 * sizeof(pary[0])); |
|
checkMonotone(i16ary, 65536); |
|
|
|
// do round-trip testing q8_23 to i16 and float |
|
memcpy_to_q8_23_from_i16(i32ary, i16ary, 65536); |
|
memset(i16ary, 0, 65536 * sizeof(i16ary[0])); |
|
checkMonotone(i32ary, 65536); |
|
|
|
memcpy_to_float_from_q8_23(fary, i32ary, 65536); |
|
memset(i32ary, 0, 65536 * sizeof(i32ary[0])); |
|
checkMonotone(fary, 65536); |
|
|
|
memcpy_to_q8_23_from_float_with_clamp(i32ary, fary, 65536); |
|
memset(fary, 0, 65536 * sizeof(fary[0])); |
|
checkMonotone(i32ary, 65536); |
|
|
|
memcpy_to_i16_from_q8_23(i16ary, i32ary, 65536); |
|
memset(i32ary, 0, 65536 * sizeof(i32ary[0])); |
|
checkMonotone(i16ary, 65536); |
|
|
|
// do round-trip testing i32 to i16 and float |
|
memcpy_to_i32_from_i16(i32ary, i16ary, 65536); |
|
memset(i16ary, 0, 65536 * sizeof(i16ary[0])); |
|
checkMonotone(i32ary, 65536); |
|
|
|
memcpy_to_float_from_i32(fary, i32ary, 65536); |
|
memset(i32ary, 0, 65536 * sizeof(i32ary[0])); |
|
checkMonotone(fary, 65536); |
|
|
|
memcpy_to_i32_from_float(i32ary, fary, 65536); |
|
memset(fary, 0, 65536 * sizeof(fary[0])); |
|
checkMonotone(i32ary, 65536); |
|
|
|
memcpy_to_i16_from_i32(i16ary, i32ary, 65536); |
|
memset(i32ary, 0, 65536 * sizeof(i32ary[0])); |
|
checkMonotone(i16ary, 65536); |
|
|
|
// do round-trip test i16 -> p24 -> i32 -> p24 -> q8_23 -> p24 -> i16 |
|
memcpy_to_p24_from_i16(pary, i16ary, 65536); |
|
memset(i16ary, 0, 65536 * sizeof(i16ary[0])); |
|
checkMonotonep24(pary, 65536 * 3); |
|
|
|
memcpy_to_i32_from_p24(i32ary, pary, 65536); |
|
memset(pary, 0, 65536 * 3 * sizeof(pary[0])); |
|
checkMonotone(i32ary, 65536); |
|
|
|
memcpy_to_p24_from_i32(pary, i32ary, 65536); |
|
memset(i32ary, 0, 65536 * sizeof(i32ary[0])); |
|
checkMonotonep24(pary, 65536 * 3); |
|
|
|
memcpy_to_q8_23_from_p24(i32ary, pary, 65536); |
|
memset(pary, 0, 65536 * 3 * sizeof(pary[0])); |
|
checkMonotone(i32ary, 65536); |
|
|
|
memcpy_to_p24_from_q8_23(pary, i32ary, 65536); |
|
memset(i32ary, 0, 65536 * sizeof(i32ary[0])); |
|
checkMonotonep24(pary, 65536 * 3); |
|
|
|
memcpy_to_i16_from_p24(i16ary, pary, 65536); |
|
memset(pary, 0, 65536 * 3 * sizeof(pary[0])); |
|
checkMonotone(i16ary, 65536); |
|
|
|
// do partial round-trip testing q4_27 to i16 and float |
|
memcpy_to_float_from_i16(fary, i16ary, 65536); |
|
//memset(i16ary, 0, 65536 * sizeof(i16ary[0])); // not cleared: we don't do full roundtrip |
|
|
|
memcpy_to_q4_27_from_float(i32ary, fary, 65536); |
|
memset(fary, 0, 65536 * sizeof(fary[0])); |
|
checkMonotone(i32ary, 65536); |
|
|
|
memcpy_to_float_from_q4_27(fary, i32ary, 65536); |
|
memset(i32ary, 0, 65536 * sizeof(i32ary[0])); |
|
checkMonotone(fary, 65536); |
|
|
|
// at the end, our i16ary must be the same. (Monotone should be equivalent to this) |
|
EXPECT_EQ(0, memcmp(i16ary, i16ref, 65536*sizeof(i16ary[0]))); |
|
|
|
// test round-trip for u8 and float. |
|
uint8_t *u8ref = new uint8_t[256]; |
|
uint8_t *u8ary = new uint8_t[256]; |
|
|
|
for (unsigned i = 0; i < 256; ++i) { |
|
u8ref[i] = i; |
|
} |
|
|
|
memcpy_to_float_from_u8(fary, u8ref, 256); |
|
memcpy_to_u8_from_float(u8ary, fary, 256); |
|
|
|
EXPECT_EQ(0, memcmp(u8ary, u8ref, 256 * sizeof(u8ary[0]))); |
|
|
|
delete[] u8ref; |
|
delete[] u8ary; |
|
delete[] i16ref; |
|
delete[] i16ary; |
|
delete[] i32ary; |
|
delete[] fary; |
|
delete[] pary; |
|
} |
|
|
|
template<typename T> |
|
void checkMonotoneOrZero(const T *ary, size_t size) |
|
{ |
|
T least = 0; |
|
|
|
for (size_t i = 1; i < size; ++i) { |
|
if (ary[i]) { |
|
EXPECT_LT(least, ary[i]); |
|
least = ary[i]; |
|
} |
|
} |
|
} |
|
|
|
TEST(audio_utils_primitives, memcpy_by_channel_mask) { |
|
uint32_t dst_mask; |
|
uint32_t src_mask; |
|
uint16_t *u16ref = new uint16_t[65536]; |
|
uint16_t *u16ary = new uint16_t[65536]; |
|
|
|
for (size_t i = 0; i < 65536; ++i) { |
|
u16ref[i] = i; |
|
} |
|
|
|
// Test when src mask is 0. Everything copied is zero. |
|
src_mask = 0; |
|
dst_mask = 0x8d; |
|
memset(u16ary, 0x99, 65536 * sizeof(u16ref[0])); |
|
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), |
|
65536 / popcount(dst_mask)); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when dst_mask is 0. Nothing should be copied. |
|
src_mask = 0; |
|
dst_mask = 0; |
|
memset(u16ary, 0, 65536 * sizeof(u16ref[0])); |
|
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), |
|
65536); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when masks are the same. One to one copy. |
|
src_mask = dst_mask = 0x8d; |
|
memset(u16ary, 0x99, 65536 * sizeof(u16ref[0])); |
|
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 555); |
|
EXPECT_EQ(0, memcmp(u16ary, u16ref, 555 * sizeof(u16ref[0]) * popcount(dst_mask))); |
|
|
|
// Test with a gap in source: |
|
// Input 3 samples, output 4 samples, one zero inserted. |
|
src_mask = 0x8c; |
|
dst_mask = 0x8d; |
|
memset(u16ary, 0x9, 65536 * sizeof(u16ary[0])); |
|
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), |
|
65536 / popcount(dst_mask)); |
|
checkMonotoneOrZero(u16ary, 65536); |
|
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); |
|
|
|
// Test with a gap in destination: |
|
// Input 4 samples, output 3 samples, one deleted |
|
src_mask = 0x8d; |
|
dst_mask = 0x8c; |
|
memset(u16ary, 0x9, 65536 * sizeof(u16ary[0])); |
|
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), |
|
65536 / popcount(src_mask)); |
|
checkMonotone(u16ary, 65536 * 3 / 4); |
|
|
|
delete[] u16ref; |
|
delete[] u16ary; |
|
} |
|
|
|
void memcpy_by_channel_mask2(void *dst, uint32_t dst_mask, |
|
const void *src, uint32_t src_mask, size_t sample_size, size_t count) |
|
{ |
|
int8_t idxary[32]; |
|
uint32_t src_channels = popcount(src_mask); |
|
uint32_t dst_channels = |
|
memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask); |
|
|
|
memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count); |
|
} |
|
|
|
// a modified version of the memcpy_by_channel_mask test |
|
// but using 24 bit type and memcpy_by_index_array() |
|
TEST(audio_utils_primitives, memcpy_by_index_array) { |
|
uint32_t dst_mask; |
|
uint32_t src_mask; |
|
typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t; |
|
uint8x3_t *u24ref = new uint8x3_t[65536]; |
|
uint8x3_t *u24ary = new uint8x3_t[65536]; |
|
uint16_t *u16ref = new uint16_t[65536]; |
|
uint16_t *u16ary = new uint16_t[65536]; |
|
|
|
EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct |
|
|
|
// tests prepare_index_array_from_masks() |
|
EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization(NULL, 0, 0x8d, 0x8c)); |
|
EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization(NULL, 0, 0x8c, 0x8d)); |
|
|
|
for (size_t i = 0; i < 65536; ++i) { |
|
u16ref[i] = i; |
|
} |
|
memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536); |
|
|
|
// Test when src mask is 0. Everything copied is zero. |
|
src_mask = 0; |
|
dst_mask = 0x8d; |
|
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(dst_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when dst_mask is 0. Nothing should be copied. |
|
src_mask = 0; |
|
dst_mask = 0; |
|
memset(u24ary, 0, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when masks are the same. One to one copy. |
|
src_mask = dst_mask = 0x8d; |
|
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); |
|
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); |
|
|
|
// Test with a gap in source: |
|
// Input 3 samples, output 4 samples, one zero inserted. |
|
src_mask = 0x8c; |
|
dst_mask = 0x8d; |
|
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(dst_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
checkMonotoneOrZero(u16ary, 65536); |
|
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); |
|
|
|
// Test with a gap in destination: |
|
// Input 4 samples, output 3 samples, one deleted |
|
src_mask = 0x8d; |
|
dst_mask = 0x8c; |
|
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(src_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
checkMonotone(u16ary, 65536 * 3 / 4); |
|
|
|
delete[] u16ref; |
|
delete[] u16ary; |
|
delete[] u24ref; |
|
delete[] u24ary; |
|
} |
|
|
|
void memcpy_by_channel_mask_dst_index(void *dst, uint32_t dst_mask, |
|
const void *src, uint32_t src_mask, size_t sample_size, size_t count) |
|
{ |
|
int8_t idxary[32]; |
|
uint32_t src_channels = popcount(src_mask); |
|
uint32_t dst_channels = |
|
memcpy_by_index_array_initialization_dst_index(idxary, 32, dst_mask, src_mask); |
|
|
|
memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count); |
|
} |
|
|
|
// a modified version of the memcpy_by_channel_mask test |
|
// but using 24 bit type and memcpy_by_index_array() |
|
TEST(audio_utils_primitives, memcpy_by_index_array_dst_index) { |
|
uint32_t dst_mask; |
|
uint32_t src_mask; |
|
typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t; |
|
uint8x3_t *u24ref = new uint8x3_t[65536]; |
|
uint8x3_t *u24ary = new uint8x3_t[65536]; |
|
uint16_t *u16ref = new uint16_t[65536]; |
|
uint16_t *u16ary = new uint16_t[65536]; |
|
|
|
EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct |
|
|
|
// tests prepare_index_array_from_masks() |
|
EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8d, 0x8c)); |
|
EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8c, 0x8d)); |
|
|
|
for (size_t i = 0; i < 65536; ++i) { |
|
u16ref[i] = i; |
|
} |
|
memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536); |
|
|
|
// Test when src mask is 0. Everything copied is zero. |
|
src_mask = 0; |
|
dst_mask = 0x8d; |
|
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(dst_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when dst_mask is 0. Nothing should be copied. |
|
src_mask = 0; |
|
dst_mask = 0; |
|
memset(u24ary, 0, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when dst mask equals source count size. One to one copy. |
|
src_mask = 0x8d; |
|
dst_mask = 0x0f; |
|
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); |
|
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); |
|
|
|
// Test with a gap in source: |
|
// Input 3 samples, output 4 samples, one zero inserted. |
|
src_mask = 0x8c; |
|
dst_mask = 0x0f; |
|
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(dst_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
checkMonotoneOrZero(u16ary, 65536); |
|
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); |
|
|
|
// Test with a gap in destination: |
|
// Input 4 samples, output 3 samples, one deleted |
|
src_mask = 0x8d; |
|
dst_mask = 0x07; |
|
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(src_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
checkMonotone(u16ary, 65536 * 3 / 4); |
|
|
|
delete[] u16ref; |
|
delete[] u16ary; |
|
delete[] u24ref; |
|
delete[] u24ary; |
|
} |
|
|
|
void memcpy_by_channel_mask_src_index(void *dst, uint32_t dst_mask, |
|
const void *src, uint32_t src_mask, size_t sample_size, size_t count) |
|
{ |
|
int8_t idxary[32]; |
|
uint32_t src_channels = popcount(src_mask); |
|
uint32_t dst_channels = |
|
memcpy_by_index_array_initialization_src_index(idxary, 32, dst_mask, src_mask); |
|
|
|
memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count); |
|
} |
|
|
|
// a modified version of the memcpy_by_channel_mask test |
|
// but using 24 bit type and memcpy_by_index_array() |
|
TEST(audio_utils_primitives, memcpy_by_index_array_src_index) { |
|
uint32_t dst_mask; |
|
uint32_t src_mask; |
|
typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t; |
|
uint8x3_t *u24ref = new uint8x3_t[65536]; |
|
uint8x3_t *u24ary = new uint8x3_t[65536]; |
|
uint16_t *u16ref = new uint16_t[65536]; |
|
uint16_t *u16ary = new uint16_t[65536]; |
|
|
|
EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct |
|
|
|
// tests prepare_index_array_from_masks() |
|
EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8d, 0x8c)); |
|
EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8c, 0x8d)); |
|
|
|
for (size_t i = 0; i < 65536; ++i) { |
|
u16ref[i] = i; |
|
} |
|
memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536); |
|
|
|
// Test when src mask is 0. Everything copied is zero. |
|
src_mask = 0; |
|
dst_mask = 0x8d; |
|
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(dst_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when dst_mask is 0. Nothing should be copied. |
|
src_mask = 0; |
|
dst_mask = 0; |
|
memset(u24ary, 0, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530)); |
|
|
|
// Test when source mask must copy to dst mask. One to one copy. |
|
src_mask = 0xf; |
|
dst_mask = 0xf; |
|
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); |
|
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); |
|
|
|
// Test when source mask must copy to dst mask. One to one copy. |
|
src_mask = 0xf; |
|
dst_mask = 0x8d; |
|
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555); |
|
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask))); |
|
|
|
// Test with a gap in source: |
|
// Input 3 samples, output 4 samples, one zero inserted. |
|
src_mask = 0x07; |
|
dst_mask = 0x8d; |
|
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(dst_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
checkMonotoneOrZero(u16ary, 65536); |
|
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536)); |
|
|
|
// Test with a gap in destination: |
|
// Input 4 samples, output 3 samples, one deleted |
|
src_mask = 0x0f; |
|
dst_mask = 0x8c; |
|
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0])); |
|
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), |
|
65536 / popcount(src_mask)); |
|
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536); |
|
checkMonotone(u16ary, 65536 * 3 / 4); |
|
|
|
delete[] u16ref; |
|
delete[] u16ary; |
|
delete[] u24ref; |
|
delete[] u24ary; |
|
} |
|
|
|
TEST(audio_utils_channels, adjust_channels) { |
|
uint16_t *u16ref = new uint16_t[65536]; |
|
uint16_t *u16expand = new uint16_t[65536*2]; |
|
uint16_t *u16ary = new uint16_t[65536]; |
|
|
|
// reference buffer always increases |
|
for (size_t i = 0; i < 65536; ++i) { |
|
u16ref[i] = i; |
|
} |
|
|
|
// expand channels from stereo to quad. |
|
adjust_channels(u16ref /*in_buff*/, 2 /*in_channels*/, |
|
u16expand /*out_buff*/, 4 /*out_channels*/, |
|
sizeof(u16ref[0]) /*sample_size_in_bytes*/, |
|
sizeof(u16ref[0])*65536 /*num_in_bytes*/); |
|
|
|
// expanded buffer must increase (or be zero) |
|
checkMonotoneOrZero(u16expand, 65536*2); |
|
|
|
// contract channels back to stereo. |
|
adjust_channels(u16expand /*in_buff*/, 4 /*in_channels*/, |
|
u16ary /*out_buff*/, 2 /*out_channels*/, |
|
sizeof(u16expand[0]) /*sample_size_in_bytes*/, |
|
sizeof(u16expand[0])*65536*2 /*num_in_bytes*/); |
|
|
|
// must be identical to original. |
|
EXPECT_EQ(0, memcmp(u16ary, u16ref, sizeof(u16ref[0])*65536)); |
|
|
|
delete[] u16ref; |
|
delete[] u16expand; |
|
delete[] u16ary; |
|
}
|
|
|