blob: f3a5a50a44a3b439fcf507b7ac85362e08e3c3b7 [file] [log] [blame]
Glenn Kasten632e0c02011-12-16 10:42:58 -08001/*
2 * Copyright (C) 2011 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
Andy Hunge0ccb202014-07-27 20:11:31 -070017#include <cutils/bitops.h> /* for popcount() */
Glenn Kasten632e0c02011-12-16 10:42:58 -080018#include <audio_utils/primitives.h>
Andy Hunge0ccb202014-07-27 20:11:31 -070019#include "private/private.h"
Glenn Kasten632e0c02011-12-16 10:42:58 -080020
Glenn Kasten7ef795a2013-07-17 07:25:05 -070021void ditherAndClamp(int32_t* out, const int32_t *sums, size_t c)
Glenn Kasten632e0c02011-12-16 10:42:58 -080022{
23 size_t i;
24 for (i=0 ; i<c ; i++) {
25 int32_t l = *sums++;
26 int32_t r = *sums++;
27 int32_t nl = l >> 12;
28 int32_t nr = r >> 12;
29 l = clamp16(nl);
30 r = clamp16(nr);
31 *out++ = (r<<16) | (l & 0xFFFF);
32 }
33}
Glenn Kastenddb2e932012-01-16 13:21:31 -080034
35void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count)
36{
37 dst += count;
38 src += count;
39 while (count--) {
40 *--dst = (int16_t)(*--src - 0x80) << 8;
41 }
42}
Glenn Kasten7a0baca2012-07-19 13:59:50 -070043
Glenn Kasten78da2ac2012-11-12 14:39:36 -080044void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count)
45{
46 while (count--) {
47 *dst++ = (*src++ >> 8) + 0x80;
48 }
49}
50
Andy Hung23ef1b32015-01-13 13:56:37 -080051void memcpy_to_u8_from_float(uint8_t *dst, const float *src, size_t count)
52{
53 while (count--) {
54 *dst++ = clamp8_from_float(*src++);
55 }
56}
57
Glenn Kasten5d436052013-06-21 14:01:54 -070058void memcpy_to_i16_from_i32(int16_t *dst, const int32_t *src, size_t count)
59{
60 while (count--) {
61 *dst++ = *src++ >> 16;
62 }
63}
64
65void memcpy_to_i16_from_float(int16_t *dst, const float *src, size_t count)
66{
67 while (count--) {
Andy Hung65b5ccd2014-03-18 12:00:55 -070068 *dst++ = clamp16_from_float(*src++);
Glenn Kasten5d436052013-06-21 14:01:54 -070069 }
70}
71
Andy Hungb878e522014-04-04 13:05:43 -070072void memcpy_to_float_from_q4_27(float *dst, const int32_t *src, size_t count)
Andy Hungaecb15e2014-02-24 19:07:40 -080073{
Andy Hungb878e522014-04-04 13:05:43 -070074 while (count--) {
Andy Hungd2a25cd2014-04-02 11:23:56 -070075 *dst++ = float_from_q4_27(*src++);
Andy Hungaecb15e2014-02-24 19:07:40 -080076 }
77}
78
Andy Hunge0454e22014-03-06 13:04:56 -080079void memcpy_to_float_from_i16(float *dst, const int16_t *src, size_t count)
80{
81 while (count--) {
82 *dst++ = float_from_i16(*src++);
83 }
84}
85
Andy Hung23ef1b32015-01-13 13:56:37 -080086void memcpy_to_float_from_u8(float *dst, const uint8_t *src, size_t count)
87{
88 while (count--) {
89 *dst++ = float_from_u8(*src++);
90 }
91}
92
Andy Hunge0454e22014-03-06 13:04:56 -080093void memcpy_to_float_from_p24(float *dst, const uint8_t *src, size_t count)
94{
95 while (count--) {
96 *dst++ = float_from_p24(src);
97 src += 3;
98 }
99}
100
101void memcpy_to_i16_from_p24(int16_t *dst, const uint8_t *src, size_t count)
102{
103 while (count--) {
104#ifdef HAVE_BIG_ENDIAN
105 *dst++ = src[1] | (src[0] << 8);
106#else
107 *dst++ = src[1] | (src[2] << 8);
108#endif
109 src += 3;
110 }
111}
112
113void memcpy_to_p24_from_i16(uint8_t *dst, const int16_t *src, size_t count)
114{
115 while (count--) {
116#ifdef HAVE_BIG_ENDIAN
117 *dst++ = *src >> 8;
118 *dst++ = *src++;
119 *dst++ = 0;
120#else
121 *dst++ = 0;
122 *dst++ = *src;
123 *dst++ = *src++ >> 8;
124#endif
125 }
126}
127
128void memcpy_to_p24_from_float(uint8_t *dst, const float *src, size_t count)
129{
130 while (count--) {
131 int32_t ival = clamp24_from_float(*src++);
132
133#ifdef HAVE_BIG_ENDIAN
134 *dst++ = ival >> 16;
135 *dst++ = ival >> 8;
136 *dst++ = ival;
137#else
138 *dst++ = ival;
139 *dst++ = ival >> 8;
140 *dst++ = ival >> 16;
141#endif
142 }
143}
144
Glenn Kasteneee45152014-05-02 12:41:04 -0700145void memcpy_to_p24_from_q8_23(uint8_t *dst, const int32_t *src, size_t count)
146{
147 while (count--) {
148 int32_t ival = clamp24_from_q8_23(*src++);
149
150#ifdef HAVE_BIG_ENDIAN
151 *dst++ = ival >> 16;
152 *dst++ = ival >> 8;
153 *dst++ = ival;
154#else
155 *dst++ = ival;
156 *dst++ = ival >> 8;
157 *dst++ = ival >> 16;
158#endif
159 }
160}
161
Andy Hungd5829882014-03-12 11:46:15 -0700162void memcpy_to_q8_23_from_i16(int32_t *dst, const int16_t *src, size_t count)
163{
164 while (count--) {
165 *dst++ = (int32_t)*src++ << 8;
166 }
167}
168
169void memcpy_to_q8_23_from_float_with_clamp(int32_t *dst, const float *src, size_t count)
170{
171 while (count--) {
172 *dst++ = clamp24_from_float(*src++);
173 }
174}
175
Haynes Mathew George78ac9f82015-04-09 13:50:13 -0700176void memcpy_to_q8_23_from_p24(int32_t *dst, const uint8_t *src, size_t count)
177{
178 while (count--) {
179#ifdef HAVE_BIG_ENDIAN
180 *dst++ = (int8_t)src[0] << 16 | src[1] << 8 | src[2];
181#else
182 *dst++ = (int8_t)src[2] << 16 | src[1] << 8 | src[0];
183#endif
184 src += 3;
185 }
186}
187
Andy Hungb878e522014-04-04 13:05:43 -0700188void memcpy_to_q4_27_from_float(int32_t *dst, const float *src, size_t count)
189{
190 while (count--) {
191 *dst++ = clampq4_27_from_float(*src++);
192 }
193}
194
Andy Hungd5829882014-03-12 11:46:15 -0700195void memcpy_to_i16_from_q8_23(int16_t *dst, const int32_t *src, size_t count)
196{
197 while (count--) {
198 *dst++ = clamp16(*src++ >> 8);
199 }
200}
201
202void memcpy_to_float_from_q8_23(float *dst, const int32_t *src, size_t count)
203{
204 while (count--) {
205 *dst++ = float_from_q8_23(*src++);
206 }
207}
208
Andy Hung2c63fb62014-03-12 14:44:12 -0700209void memcpy_to_i32_from_i16(int32_t *dst, const int16_t *src, size_t count)
210{
211 while (count--) {
212 *dst++ = (int32_t)*src++ << 16;
213 }
214}
215
216void memcpy_to_i32_from_float(int32_t *dst, const float *src, size_t count)
217{
218 while (count--) {
219 *dst++ = clamp32_from_float(*src++);
220 }
221}
222
223void memcpy_to_float_from_i32(float *dst, const int32_t *src, size_t count)
224{
225 while (count--) {
226 *dst++ = float_from_i32(*src++);
227 }
228}
229
Glenn Kasten7a0baca2012-07-19 13:59:50 -0700230void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count)
231{
232 while (count--) {
233 *dst++ = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
234 src += 2;
235 }
236}
237
238void upmix_to_stereo_i16_from_mono_i16(int16_t *dst, const int16_t *src, size_t count)
239{
240 while (count--) {
241 int32_t temp = *src++;
242 dst[0] = temp;
243 dst[1] = temp;
244 dst += 2;
245 }
246}
Glenn Kasteneb247df2014-02-21 10:00:51 -0800247
248size_t nonZeroMono32(const int32_t *samples, size_t count)
249{
250 size_t nonZero = 0;
251 while (count-- > 0) {
252 if (*samples++ != 0) {
253 nonZero++;
254 }
255 }
256 return nonZero;
257}
258
259size_t nonZeroMono16(const int16_t *samples, size_t count)
260{
261 size_t nonZero = 0;
262 while (count-- > 0) {
263 if (*samples++ != 0) {
264 nonZero++;
265 }
266 }
267 return nonZero;
268}
269
270size_t nonZeroStereo32(const int32_t *frames, size_t count)
271{
272 size_t nonZero = 0;
273 while (count-- > 0) {
274 if (frames[0] != 0 || frames[1] != 0) {
275 nonZero++;
276 }
277 frames += 2;
278 }
279 return nonZero;
280}
281
282size_t nonZeroStereo16(const int16_t *frames, size_t count)
283{
284 size_t nonZero = 0;
285 while (count-- > 0) {
286 if (frames[0] != 0 || frames[1] != 0) {
287 nonZero++;
288 }
289 frames += 2;
290 }
291 return nonZero;
292}
Andy Hung3af2af22014-05-22 18:40:30 -0700293
Andy Hung3af2af22014-05-22 18:40:30 -0700294/*
295 * C macro to do channel mask copying independent of dst/src sample type.
296 * Don't pass in any expressions for the macro arguments here.
297 */
298#define copy_frame_by_mask(dst, dmask, src, smask, count, zero) \
299{ \
300 uint32_t bit, ormask; \
301 while (count--) { \
302 ormask = dmask | smask; \
303 while (ormask) { \
304 bit = ormask & -ormask; /* get lowest bit */ \
305 ormask ^= bit; /* remove lowest bit */ \
306 if (dmask & bit) { \
307 *dst++ = smask & bit ? *src++ : zero; \
308 } else { /* source channel only */ \
309 ++src; \
310 } \
311 } \
312 } \
313}
314
315void memcpy_by_channel_mask(void *dst, uint32_t dst_mask,
316 const void *src, uint32_t src_mask, size_t sample_size, size_t count)
317{
318#if 0
319 /* alternate way of handling memcpy_by_channel_mask by using the idxary */
320 int8_t idxary[32];
321 uint32_t src_channels = popcount(src_mask);
322 uint32_t dst_channels =
323 memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask);
324
325 memcpy_by_idxary(dst, dst_channels, src, src_channels, idxary, sample_size, count);
326#else
327 if (dst_mask == src_mask) {
328 memcpy(dst, src, sample_size * popcount(dst_mask) * count);
329 return;
330 }
331 switch (sample_size) {
332 case 1: {
333 uint8_t *udst = (uint8_t*)dst;
334 const uint8_t *usrc = (const uint8_t*)src;
335
336 copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0);
337 } break;
338 case 2: {
339 uint16_t *udst = (uint16_t*)dst;
340 const uint16_t *usrc = (const uint16_t*)src;
341
342 copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0);
343 } break;
344 case 3: { /* could be slow. use a struct to represent 3 bytes of data. */
345 uint8x3_t *udst = (uint8x3_t*)dst;
346 const uint8x3_t *usrc = (const uint8x3_t*)src;
347 static const uint8x3_t zero; /* tricky - we use this to zero out a sample */
348
349 copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, zero);
350 } break;
351 case 4: {
352 uint32_t *udst = (uint32_t*)dst;
353 const uint32_t *usrc = (const uint32_t*)src;
354
355 copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0);
356 } break;
357 default:
358 abort(); /* illegal value */
359 break;
360 }
361#endif
362}
363
364/*
365 * C macro to do copying by index array, to rearrange samples
366 * within a frame. This is independent of src/dst sample type.
367 * Don't pass in any expressions for the macro arguments here.
368 */
369#define copy_frame_by_idx(dst, dst_channels, src, src_channels, idxary, count, zero) \
370{ \
371 unsigned i; \
372 int index; \
373 while (count--) { \
374 for (i = 0; i < dst_channels; ++i) { \
375 index = idxary[i]; \
376 *dst++ = index < 0 ? zero : src[index]; \
377 } \
378 src += src_channels; \
379 } \
380}
381
382void memcpy_by_index_array(void *dst, uint32_t dst_channels,
383 const void *src, uint32_t src_channels,
384 const int8_t *idxary, size_t sample_size, size_t count)
385{
386 switch (sample_size) {
387 case 1: {
388 uint8_t *udst = (uint8_t*)dst;
389 const uint8_t *usrc = (const uint8_t*)src;
390
391 copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0);
392 } break;
393 case 2: {
394 uint16_t *udst = (uint16_t*)dst;
395 const uint16_t *usrc = (const uint16_t*)src;
396
397 copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0);
398 } break;
399 case 3: { /* could be slow. use a struct to represent 3 bytes of data. */
400 uint8x3_t *udst = (uint8x3_t*)dst;
401 const uint8x3_t *usrc = (const uint8x3_t*)src;
402 static const uint8x3_t zero;
403
404 copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, zero);
405 } break;
406 case 4: {
407 uint32_t *udst = (uint32_t*)dst;
408 const uint32_t *usrc = (const uint32_t*)src;
409
410 copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0);
411 } break;
412 default:
413 abort(); /* illegal value */
414 break;
415 }
416}
417
418size_t memcpy_by_index_array_initialization(int8_t *idxary, size_t idxcount,
419 uint32_t dst_mask, uint32_t src_mask)
420{
421 size_t n = 0;
422 int srcidx = 0;
423 uint32_t bit, ormask = src_mask | dst_mask;
424
425 while (ormask && n < idxcount) {
426 bit = ormask & -ormask; /* get lowest bit */
427 ormask ^= bit; /* remove lowest bit */
428 if (src_mask & dst_mask & bit) { /* matching channel */
429 idxary[n++] = srcidx++;
430 } else if (src_mask & bit) { /* source channel only */
431 ++srcidx;
432 } else { /* destination channel only */
433 idxary[n++] = -1;
434 }
435 }
436 return n + popcount(ormask & dst_mask);
437}
Andy Hung5a0d0282015-02-02 15:34:13 -0800438
439size_t memcpy_by_index_array_initialization_src_index(int8_t *idxary, size_t idxcount,
440 uint32_t dst_mask, uint32_t src_mask) {
441 size_t dst_count = popcount(dst_mask);
442 if (idxcount == 0) {
443 return dst_count;
444 }
445 if (dst_count > idxcount) {
446 dst_count = idxcount;
447 }
448
449 size_t src_idx, dst_idx;
450 for (src_idx = 0, dst_idx = 0; dst_idx < dst_count; ++dst_idx) {
451 if (src_mask & 1) {
452 idxary[dst_idx] = src_idx++;
453 } else {
454 idxary[dst_idx] = -1;
455 }
456 src_mask >>= 1;
457 }
458 return dst_idx;
459}