OSDN Git Service

Merge "Make inlines static" into stage-aosp-master am: b76693c9fc -s ours am: 90492d...
[android-x86/system-media.git] / audio_utils / power.cpp
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"
19 #include <log/log.h>
20
21 #include <math.h>
22
23 #include <audio_utils/power.h>
24 #include <audio_utils/primitives.h>
25
26 #if defined(__aarch64__) || defined(__ARM_NEON__)
27 #include <arm_neon.h>
28 #define USE_NEON
29 #endif
30
31 namespace {
32
33 constexpr inline bool isFormatSupported(audio_format_t format) {
34     switch (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:
41         return true;
42     default:
43         return false;
44     }
45 }
46
47 template <typename T>
48 inline T getPtrPtrValueAndIncrement(const void **data)
49 {
50     return *(*reinterpret_cast<const T **>(data))++;
51 }
52
53 template <audio_format_t FORMAT>
54 inline float convertToFloatAndIncrement(const void **data)
55 {
56     switch (FORMAT) {
57     case AUDIO_FORMAT_PCM_8_BIT:
58         return float_from_u8(getPtrPtrValueAndIncrement<uint8_t>(data));
59
60     case AUDIO_FORMAT_PCM_16_BIT:
61         return float_from_i16(getPtrPtrValueAndIncrement<int16_t>(data));
62
63     case AUDIO_FORMAT_PCM_24_BIT_PACKED: {
64         const uint8_t *uptr = reinterpret_cast<const uint8_t *>(*data);
65         *data = uptr + 3;
66         return float_from_p24(uptr);
67     }
68
69     case AUDIO_FORMAT_PCM_8_24_BIT:
70         return float_from_q8_23(getPtrPtrValueAndIncrement<int32_t>(data));
71
72     case AUDIO_FORMAT_PCM_32_BIT:
73         return float_from_i32(getPtrPtrValueAndIncrement<int32_t>(data));
74
75     case AUDIO_FORMAT_PCM_FLOAT:
76         return getPtrPtrValueAndIncrement<float>(data);
77
78     default:
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");
82     }
83 }
84
85 // used to normalize integer fixed point value to the floating point equivalent.
86 template <audio_format_t FORMAT>
87 constexpr inline float normalizeAmplitude()
88 {
89     switch (FORMAT) {
90     case AUDIO_FORMAT_PCM_8_BIT:
91         return 1.f / (1 << 7);
92
93     case AUDIO_FORMAT_PCM_16_BIT:
94         return 1.f / (1 << 15);
95
96     case AUDIO_FORMAT_PCM_24_BIT_PACKED: // fall through
97     case AUDIO_FORMAT_PCM_8_24_BIT:
98         return 1.f / (1 << 23);
99
100     case AUDIO_FORMAT_PCM_32_BIT:
101         return 1.f / (1U << 31);
102
103     case AUDIO_FORMAT_PCM_FLOAT:
104          return 1.f;
105
106     default:
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");
110     }
111 }
112
113 template <audio_format_t FORMAT>
114 constexpr inline float normalizeEnergy()
115 {
116     const float val = normalizeAmplitude<FORMAT>();
117     return val * val;
118 }
119
120 template <audio_format_t FORMAT>
121 inline float energyMonoRef(const void *amplitudes, size_t size)
122 {
123     float accum(0.f);
124     for (size_t i = 0; i < size; ++i) {
125         const float amplitude = convertToFloatAndIncrement<FORMAT>(&amplitudes);
126         accum += amplitude * amplitude;
127     }
128     return accum;
129 }
130
131 template <audio_format_t FORMAT>
132 inline float energyMono(const void *amplitudes, size_t size)
133 {
134     return energyMonoRef<FORMAT>(amplitudes, size);
135 }
136
137 // fast float power computation for ARM processors that support NEON.
138 #ifdef USE_NEON
139
140 template <>
141 inline float energyMono<AUDIO_FORMAT_PCM_FLOAT>(const void *amplitudes, size_t size)
142 {
143     float32x4_t *famplitudes = (float32x4_t *)amplitudes;
144
145     // clear accumulator
146     float32x4_t accum = vdupq_n_f32(0);
147
148     // iterate over array getting sum of squares in 4 lanes.
149     size_t i;
150     for (i = 0; i < (size & ~3); i += 4) {
151         accum = vmlaq_f32(accum, *famplitudes, *famplitudes);
152         ++famplitudes;
153     }
154
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
158
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;
164     }
165
166     return value;
167 }
168
169 template <>
170 inline float energyMono<AUDIO_FORMAT_PCM_16_BIT>(const void *amplitudes, size_t size)
171 {
172     int16x4_t *samplitudes = (int16x4_t *)amplitudes;
173
174     // clear accumulator
175     float32x4_t accum = vdupq_n_f32(0);
176
177     // iterate over array getting sum of squares in 4 lanes.
178     size_t i;
179     for (i = 0; i < (size & ~3); i += 4) {
180         // expand s16 to s32
181         int32x4_t amplitude = vmovl_s16(*samplitudes);
182         ++samplitudes;
183         // convert s32 to f32
184         float32x4_t famplitude = vcvtq_f32_s32(amplitude);
185         accum = vmlaq_f32(accum, famplitude, famplitude);
186     }
187
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
191
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;
197     }
198
199     return value * normalizeEnergy<AUDIO_FORMAT_PCM_16_BIT>();
200 }
201
202 // fast int32_t power computation for PCM_32
203 template <>
204 inline float energyMono<AUDIO_FORMAT_PCM_32_BIT>(const void *amplitudes, size_t size)
205 {
206     int32x4_t *samplitudes = (int32x4_t *)amplitudes;
207
208     // clear accumulator
209     float32x4_t accum = vdupq_n_f32(0);
210
211     // iterate over array getting sum of squares in 4 lanes.
212     size_t i;
213     for (i = 0; i < (size & ~3); i += 4) {
214         // convert s32 to f32
215         float32x4_t famplitude = vcvtq_f32_s32(*samplitudes);
216         ++samplitudes;
217         accum = vmlaq_f32(accum, famplitude, famplitude);
218     }
219
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
223
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;
229     }
230
231     return value * normalizeEnergy<AUDIO_FORMAT_PCM_32_BIT>();
232 }
233
234 // fast int32_t power computation for PCM_8_24 (essentially identical to PCM_32 above)
235 template <>
236 inline float energyMono<AUDIO_FORMAT_PCM_8_24_BIT>(const void *amplitudes, size_t size)
237 {
238     int32x4_t *samplitudes = (int32x4_t *)amplitudes;
239
240     // clear accumulator
241     float32x4_t accum = vdupq_n_f32(0);
242
243     // iterate over array getting sum of squares in 4 lanes.
244     size_t i;
245     for (i = 0; i < (size & ~3); i += 4) {
246         // convert s32 to f32
247         float32x4_t famplitude = vcvtq_f32_s32(*samplitudes);
248         ++samplitudes;
249         accum = vmlaq_f32(accum, famplitude, famplitude);
250     }
251
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
255
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;
261     }
262
263     return value * normalizeEnergy<AUDIO_FORMAT_PCM_8_24_BIT>();
264 }
265
266 #endif // USE_NEON
267
268 } // namespace
269
270 float audio_utils_compute_energy_mono(const void *buffer, audio_format_t format, size_t samples)
271 {
272     switch (format) {
273     case AUDIO_FORMAT_PCM_8_BIT:
274         return energyMono<AUDIO_FORMAT_PCM_8_BIT>(buffer, samples);
275
276     case AUDIO_FORMAT_PCM_16_BIT:
277         return energyMono<AUDIO_FORMAT_PCM_16_BIT>(buffer, samples);
278
279     case AUDIO_FORMAT_PCM_24_BIT_PACKED:
280         return energyMono<AUDIO_FORMAT_PCM_24_BIT_PACKED>(buffer, samples);
281
282     case AUDIO_FORMAT_PCM_8_24_BIT:
283         return energyMono<AUDIO_FORMAT_PCM_8_24_BIT>(buffer, samples);
284
285     case AUDIO_FORMAT_PCM_32_BIT:
286         return energyMono<AUDIO_FORMAT_PCM_32_BIT>(buffer, samples);
287
288     case AUDIO_FORMAT_PCM_FLOAT:
289         return energyMono<AUDIO_FORMAT_PCM_FLOAT>(buffer, samples);
290
291     default:
292         LOG_ALWAYS_FATAL("invalid format: %#x", format);
293     }
294 }
295
296 float audio_utils_compute_power_mono(const void *buffer, audio_format_t format, size_t samples)
297 {
298     return audio_utils_power_from_energy(
299             audio_utils_compute_energy_mono(buffer, format, samples) / samples);
300 }
301
302 bool audio_utils_is_compute_power_format_supported(audio_format_t format)
303 {
304     return isFormatSupported(format);
305 }
306