2 * Copyright 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // #define LOG_NDEBUG 0
18 #define LOG_TAG "audio_utils_power"
23 #include <audio_utils/power.h>
24 #include <audio_utils/primitives.h>
26 #if defined(__aarch64__) || defined(__ARM_NEON__)
33 constexpr inline bool isFormatSupported(audio_format_t format) {
35 case AUDIO_FORMAT_PCM_8_BIT:
36 case AUDIO_FORMAT_PCM_16_BIT:
37 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
38 case AUDIO_FORMAT_PCM_8_24_BIT:
39 case AUDIO_FORMAT_PCM_32_BIT:
40 case AUDIO_FORMAT_PCM_FLOAT:
48 inline T getPtrPtrValueAndIncrement(const void **data)
50 return *(*reinterpret_cast<const T **>(data))++;
53 template <audio_format_t FORMAT>
54 inline float convertToFloatAndIncrement(const void **data)
57 case AUDIO_FORMAT_PCM_8_BIT:
58 return float_from_u8(getPtrPtrValueAndIncrement<uint8_t>(data));
60 case AUDIO_FORMAT_PCM_16_BIT:
61 return float_from_i16(getPtrPtrValueAndIncrement<int16_t>(data));
63 case AUDIO_FORMAT_PCM_24_BIT_PACKED: {
64 const uint8_t *uptr = reinterpret_cast<const uint8_t *>(*data);
66 return float_from_p24(uptr);
69 case AUDIO_FORMAT_PCM_8_24_BIT:
70 return float_from_q8_23(getPtrPtrValueAndIncrement<int32_t>(data));
72 case AUDIO_FORMAT_PCM_32_BIT:
73 return float_from_i32(getPtrPtrValueAndIncrement<int32_t>(data));
75 case AUDIO_FORMAT_PCM_FLOAT:
76 return getPtrPtrValueAndIncrement<float>(data);
79 // static_assert cannot use false because the compiler may interpret it
80 // even though this code path may never be taken.
81 static_assert(isFormatSupported(FORMAT), "unsupported format");
85 // used to normalize integer fixed point value to the floating point equivalent.
86 template <audio_format_t FORMAT>
87 constexpr inline float normalizeAmplitude()
90 case AUDIO_FORMAT_PCM_8_BIT:
91 return 1.f / (1 << 7);
93 case AUDIO_FORMAT_PCM_16_BIT:
94 return 1.f / (1 << 15);
96 case AUDIO_FORMAT_PCM_24_BIT_PACKED: // fall through
97 case AUDIO_FORMAT_PCM_8_24_BIT:
98 return 1.f / (1 << 23);
100 case AUDIO_FORMAT_PCM_32_BIT:
101 return 1.f / (1U << 31);
103 case AUDIO_FORMAT_PCM_FLOAT:
107 // static_assert cannot use false because the compiler may interpret it
108 // even though this code path may never be taken.
109 static_assert(isFormatSupported(FORMAT), "unsupported format");
113 template <audio_format_t FORMAT>
114 constexpr inline float normalizeEnergy()
116 const float val = normalizeAmplitude<FORMAT>();
120 template <audio_format_t FORMAT>
121 inline float energyMonoRef(const void *amplitudes, size_t size)
124 for (size_t i = 0; i < size; ++i) {
125 const float amplitude = convertToFloatAndIncrement<FORMAT>(&litudes);
126 accum += amplitude * amplitude;
131 template <audio_format_t FORMAT>
132 inline float energyMono(const void *amplitudes, size_t size)
134 return energyMonoRef<FORMAT>(amplitudes, size);
137 // fast float power computation for ARM processors that support NEON.
141 inline float energyMono<AUDIO_FORMAT_PCM_FLOAT>(const void *amplitudes, size_t size)
143 float32x4_t *famplitudes = (float32x4_t *)amplitudes;
146 float32x4_t accum = vdupq_n_f32(0);
148 // iterate over array getting sum of squares in 4 lanes.
150 for (i = 0; i < (size & ~3); i += 4) {
151 accum = vmlaq_f32(accum, *famplitudes, *famplitudes);
155 // narrow 4 lanes of floats
156 float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
157 accum2 = vpadd_f32(accum2, accum2); // combine to mono
159 // accumulate remainder
160 float value = vget_lane_f32(accum2, 0);
161 for (; i < size; ++i) {
162 const float amplitude = ((float *)amplitudes)[i];
163 value += amplitude * amplitude;
170 inline float energyMono<AUDIO_FORMAT_PCM_16_BIT>(const void *amplitudes, size_t size)
172 int16x4_t *samplitudes = (int16x4_t *)amplitudes;
175 float32x4_t accum = vdupq_n_f32(0);
177 // iterate over array getting sum of squares in 4 lanes.
179 for (i = 0; i < (size & ~3); i += 4) {
181 int32x4_t amplitude = vmovl_s16(*samplitudes);
183 // convert s32 to f32
184 float32x4_t famplitude = vcvtq_f32_s32(amplitude);
185 accum = vmlaq_f32(accum, famplitude, famplitude);
188 // narrow 4 lanes of floats
189 float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
190 accum2 = vpadd_f32(accum2, accum2); // combine to mono
192 // accumulate remainder
193 float value = vget_lane_f32(accum2, 0);
194 for (; i < size; ++i) {
195 const float amplitude = (float)((int16_t *)amplitudes)[i];
196 value += amplitude * amplitude;
199 return value * normalizeEnergy<AUDIO_FORMAT_PCM_16_BIT>();
202 // fast int32_t power computation for PCM_32
204 inline float energyMono<AUDIO_FORMAT_PCM_32_BIT>(const void *amplitudes, size_t size)
206 int32x4_t *samplitudes = (int32x4_t *)amplitudes;
209 float32x4_t accum = vdupq_n_f32(0);
211 // iterate over array getting sum of squares in 4 lanes.
213 for (i = 0; i < (size & ~3); i += 4) {
214 // convert s32 to f32
215 float32x4_t famplitude = vcvtq_f32_s32(*samplitudes);
217 accum = vmlaq_f32(accum, famplitude, famplitude);
220 // narrow 4 lanes of floats
221 float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
222 accum2 = vpadd_f32(accum2, accum2); // combine to mono
224 // accumulate remainder
225 float value = vget_lane_f32(accum2, 0);
226 for (; i < size; ++i) {
227 const float amplitude = (float)((int32_t *)amplitudes)[i];
228 value += amplitude * amplitude;
231 return value * normalizeEnergy<AUDIO_FORMAT_PCM_32_BIT>();
234 // fast int32_t power computation for PCM_8_24 (essentially identical to PCM_32 above)
236 inline float energyMono<AUDIO_FORMAT_PCM_8_24_BIT>(const void *amplitudes, size_t size)
238 int32x4_t *samplitudes = (int32x4_t *)amplitudes;
241 float32x4_t accum = vdupq_n_f32(0);
243 // iterate over array getting sum of squares in 4 lanes.
245 for (i = 0; i < (size & ~3); i += 4) {
246 // convert s32 to f32
247 float32x4_t famplitude = vcvtq_f32_s32(*samplitudes);
249 accum = vmlaq_f32(accum, famplitude, famplitude);
252 // narrow 4 lanes of floats
253 float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
254 accum2 = vpadd_f32(accum2, accum2); // combine to mono
256 // accumulate remainder
257 float value = vget_lane_f32(accum2, 0);
258 for (; i < size; ++i) {
259 const float amplitude = (float)((int32_t *)amplitudes)[i];
260 value += amplitude * amplitude;
263 return value * normalizeEnergy<AUDIO_FORMAT_PCM_8_24_BIT>();
270 float audio_utils_compute_energy_mono(const void *buffer, audio_format_t format, size_t samples)
273 case AUDIO_FORMAT_PCM_8_BIT:
274 return energyMono<AUDIO_FORMAT_PCM_8_BIT>(buffer, samples);
276 case AUDIO_FORMAT_PCM_16_BIT:
277 return energyMono<AUDIO_FORMAT_PCM_16_BIT>(buffer, samples);
279 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
280 return energyMono<AUDIO_FORMAT_PCM_24_BIT_PACKED>(buffer, samples);
282 case AUDIO_FORMAT_PCM_8_24_BIT:
283 return energyMono<AUDIO_FORMAT_PCM_8_24_BIT>(buffer, samples);
285 case AUDIO_FORMAT_PCM_32_BIT:
286 return energyMono<AUDIO_FORMAT_PCM_32_BIT>(buffer, samples);
288 case AUDIO_FORMAT_PCM_FLOAT:
289 return energyMono<AUDIO_FORMAT_PCM_FLOAT>(buffer, samples);
292 LOG_ALWAYS_FATAL("invalid format: %#x", format);
296 float audio_utils_compute_power_mono(const void *buffer, audio_format_t format, size_t samples)
298 return audio_utils_power_from_energy(
299 audio_utils_compute_energy_mono(buffer, format, samples) / samples);
302 bool audio_utils_is_compute_power_format_supported(audio_format_t format)
304 return isFormatSupported(format);