1/* 2 * Copyright 2017 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_power_tests" 19 20#include <cmath> 21#include <math.h> 22 23#include <audio_utils/power.h> 24#include <gtest/gtest.h> 25#include <log/log.h> 26 27typedef struct { uint8_t c[3]; } __attribute__((__packed__)) uint8x3_t; 28 29void testFloatValue(float f_value, size_t length) { 30 const float power = audio_utils_power_from_amplitude(f_value); 31 float f_ary[length]; 32 uint8_t u8_ary[length]; 33 int16_t i16_ary[length]; 34 int32_t i32_ary[length]; 35 int32_t q8_23_ary[length]; 36 uint8x3_t p24_ary[length]; 37 38 // magic formulas to convert floating point to fixed point representations. 39 // we negate the floating point value to ensure full integer range for 1.f. 40 const uint8_t u8_value((1.f - f_value) * 128); 41 const int16_t i16_value(f_value * INT16_MIN); 42 const int32_t i32_value (f_value * INT32_MIN); 43 const int32_t q8_23_value(f_value * -(1 << 23)); 44 45 // PCM_24_BIT_PACKED is native endian. 46#if HAVE_BIG_ENDIAN 47 const uint8x3_t p24_value{{ 48 uint8_t(q8_23_value >> 16), 49 uint8_t(q8_23_value >> 8), 50 uint8_t(q8_23_value), 51 }}; 52#else 53 const uint8x3_t p24_value{{ 54 uint8_t(q8_23_value), 55 uint8_t(q8_23_value >> 8), 56 uint8_t(q8_23_value >> 16), 57 }}; 58#endif 59 60 for (size_t i = 0; i < length; ++i) { 61 f_ary[i] = f_value; 62 u8_ary[i] = u8_value; 63 i16_ary[i] = i16_value; 64 i32_ary[i] = i32_value; 65 q8_23_ary[i] = q8_23_value; 66 p24_ary[i] = p24_value; 67 } 68 69 // check offset by 1, 2, 3 elements for unaligned NEON vector handling. 70 for (size_t i = 0; i < 3; ++i) { 71 if (i >= length) break; 72 EXPECT_EQ(power, 73 audio_utils_compute_power_mono(f_ary + i, AUDIO_FORMAT_PCM_FLOAT, length - i)); 74 EXPECT_EQ(power, 75 audio_utils_compute_power_mono(u8_ary + i, AUDIO_FORMAT_PCM_8_BIT, length - i)); 76 EXPECT_EQ(power, 77 audio_utils_compute_power_mono(i16_ary + i, AUDIO_FORMAT_PCM_16_BIT, length - i)); 78 EXPECT_EQ(power, 79 audio_utils_compute_power_mono(i32_ary + i, AUDIO_FORMAT_PCM_32_BIT, length - i)); 80 EXPECT_EQ(power, 81 audio_utils_compute_power_mono( 82 q8_23_ary + i, AUDIO_FORMAT_PCM_8_24_BIT, length - i)); 83 EXPECT_EQ(power, 84 audio_utils_compute_power_mono( 85 p24_ary + i, AUDIO_FORMAT_PCM_24_BIT_PACKED, length - i)); 86 } 87} 88 89void testFloatRamp(size_t length) { 90 float f_ary[length]; 91 uint8_t u8_ary[length]; 92 int16_t i16_ary[length]; 93 int32_t i32_ary[length]; 94 int32_t q8_23_ary[length]; 95 uint8x3_t p24_ary[length]; 96 97 for (size_t i = 0; i < length; ++i) { 98 // must be expressed cleanly in uint8_t 99 const float f_value = (int(length & 0xff) - 128) / 128.f; 100 101 // magic formulas to convert floating point to fixed point representations. 102 // we negate the floating point value to ensure full integer range for 1.f. 103 const uint8_t u8_value((1.f - f_value) * 128); 104 const int16_t i16_value(f_value * INT16_MIN); 105 const int32_t i32_value (f_value * INT32_MIN); 106 const int32_t q8_23_value(f_value * -(1 << 23)); 107 108 // PCM_24_BIT_PACKED is native endian. 109 #if HAVE_BIG_ENDIAN 110 const uint8x3_t p24_value{{ 111 uint8_t(q8_23_value >> 16), 112 uint8_t(q8_23_value >> 8), 113 uint8_t(q8_23_value), 114 }}; 115 #else 116 const uint8x3_t p24_value{{ 117 uint8_t(q8_23_value), 118 uint8_t(q8_23_value >> 8), 119 uint8_t(q8_23_value >> 16), 120 }}; 121 #endif 122 123 f_ary[i] = f_value; 124 u8_ary[i] = u8_value; 125 i16_ary[i] = i16_value; 126 i32_ary[i] = i32_value; 127 q8_23_ary[i] = q8_23_value; 128 p24_ary[i] = p24_value; 129 } 130 131 const float power8 = audio_utils_compute_power_mono(u8_ary, AUDIO_FORMAT_PCM_8_BIT, length); 132 133 EXPECT_EQ(power8, 134 audio_utils_compute_power_mono(f_ary, AUDIO_FORMAT_PCM_FLOAT, length)); 135 EXPECT_EQ(power8, 136 audio_utils_compute_power_mono(i16_ary, AUDIO_FORMAT_PCM_16_BIT, length)); 137 EXPECT_EQ(power8, 138 audio_utils_compute_power_mono(i32_ary, AUDIO_FORMAT_PCM_32_BIT, length)); 139 EXPECT_EQ(power8, 140 audio_utils_compute_power_mono(q8_23_ary, AUDIO_FORMAT_PCM_8_24_BIT, length)); 141 EXPECT_EQ(power8, 142 audio_utils_compute_power_mono(p24_ary, AUDIO_FORMAT_PCM_24_BIT_PACKED, length)); 143} 144 145// power_mono implicitly tests energy_mono 146TEST(audio_utils_power, power_mono) { 147 // f_values should have limited mantissa 148 for (float f_value : { 0.f, 0.25f, 0.5f, 0.75f, 1.f }) { 149 const float power = audio_utils_power_from_amplitude(f_value); 150 printf("power_mono: amplitude: %f power: %f\n", f_value, power); 151 152 for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37 }) { 153 testFloatValue(f_value, length); 154 } 155 } 156} 157 158// power_mono implicitly tests energy_mono 159TEST(audio_utils_power, power_mono_ramp) { 160 for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37, 297 }) { 161 testFloatRamp(length); 162 } 163} 164 165TEST(audio_utils_power, power_from) { 166 EXPECT_EQ(0.f, audio_utils_power_from_amplitude(1.f)); 167 EXPECT_EQ(-INFINITY, audio_utils_power_from_amplitude(0.f)); 168 EXPECT_EQ(0.f, audio_utils_power_from_amplitude(-1.f)); 169 170 EXPECT_EQ(0.f, audio_utils_power_from_energy(1.f)); 171 EXPECT_EQ(-INFINITY, audio_utils_power_from_energy(0.f)); 172 EXPECT_TRUE(std::isnan(audio_utils_power_from_energy(-1.f))); 173} 174