1 /*
2 * Copyright (C) 2014 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 #include <string.h>
18 #include <audio_utils/channels.h>
19 #include "private/private.h"
20
21 /*
22 * Clamps a 24-bit value from a 32-bit sample
23 */
clamp24(int32_t sample)24 static inline int32_t clamp24(int32_t sample)
25 {
26 if ((sample>>23) ^ (sample>>31)) {
27 sample = 0x007FFFFF ^ (sample>>31);
28 }
29 return sample;
30 }
31
32 /*
33 * Converts a uint8x3_t into an int32_t
34 */
uint8x3_to_int32(uint8x3_t val)35 static inline int32_t uint8x3_to_int32(uint8x3_t val) {
36 #if HAVE_BIG_ENDIAN
37 int32_t temp = (val.c[0] << 24 | val.c[1] << 16 | val.c[2] << 8) >> 8;
38 #else
39 int32_t temp = (val.c[2] << 24 | val.c[1] << 16 | val.c[0] << 8) >> 8;
40 #endif
41 return clamp24(temp);
42 }
43
44 /*
45 * Converts an int32_t to a uint8x3_t
46 */
int32_to_uint8x3(int32_t in)47 static inline uint8x3_t int32_to_uint8x3(int32_t in) {
48 uint8x3_t out;
49 #if HAVE_BIG_ENDIAN
50 out.c[2] = in;
51 out.c[1] = in >> 8;
52 out.c[0] = in >> 16;
53 #else
54 out.c[0] = in;
55 out.c[1] = in >> 8;
56 out.c[2] = in >> 16;
57 #endif
58 return out;
59 }
60
61 /* This is written as a C macro because it operates on generic types,
62 * which in a C++ file could be alternatively achieved by a "template"
63 * or an "auto" declaration.
64 * TODO: convert this from a C file to a C++ file.
65 */
66
67 /* Channel expands (adds zeroes to audio frame end) from an input buffer to an output buffer.
68 * See expand_channels() function below for parameter definitions.
69 *
70 * Move from back to front so that the conversion can be done in-place
71 * i.e. in_buff == out_buff
72 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
73 *
74 * Macro has a return statement.
75 */
76 #define EXPAND_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
77 { \
78 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
79 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
80 typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
81 size_t src_index; \
82 typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
83 size_t num_zero_chans = (out_buff_chans) - (in_buff_chans); \
84 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
85 size_t dst_offset; \
86 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
87 *dst_ptr-- = zero; \
88 } \
89 for (; dst_offset < (out_buff_chans); dst_offset++) { \
90 *dst_ptr-- = *src_ptr--; \
91 } \
92 } \
93 /* return number of *bytes* generated */ \
94 return num_out_samples * sizeof(*(out_buff)); \
95 }
96
97 /* Channel expands from an input buffer to an output buffer.
98 * See expand_selected_channels() function below for parameter definitions.
99 * Selected channels are replaced in the output buffer, with any extra channels
100 * per frame left alone.
101 *
102 * Move from back to front so that the conversion can be done in-place
103 * i.e. in_buff == out_buff
104 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
105 *
106 * Macro has a return statement.
107 */
108 #define EXPAND_SELECTED_CHANNELS( \
109 in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
110 { \
111 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
112 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
113 typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
114 size_t src_index; \
115 typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
116 size_t num_extra_chans = (out_buff_chans) - (in_buff_chans); \
117 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
118 dst_ptr -= num_extra_chans; \
119 for (size_t dst_offset = num_extra_chans; dst_offset < (out_buff_chans); dst_offset++) { \
120 *dst_ptr-- = *src_ptr--; \
121 } \
122 } \
123 /* return number of *bytes* generated */ \
124 return num_out_samples * sizeof(*(out_buff)); \
125 }
126
127 /* Expand number of channels from an input buffer to an output buffer.
128 * See expand_channels_non_destructive() function below for parameter definitions.
129 *
130 * Input channels are copied to the output buffer, with extra output
131 * channels interleaved from back of input buffer.
132 *
133 * So for in_chans = 2, out_chans = 4: [1|2|1|2...|3|4|3|4] => [1|2|3|4|1|2|3|4...]
134 *
135 * NOTE: in_buff must be same size as out_buff and num_in_bytes must
136 * be a multiple of in_buff_channels * in_buff_sample_size.
137 *
138 * Uses a temporary buffer so that the conversion can be done in-place
139 * i.e. in_buff == out_buff
140 *
141 * Macro has a return statement.
142 */
143 #define EXPAND_CHANNELS_NON_DESTRUCTIVE(in_buff, in_buff_chans, \
144 out_buff, out_buff_chans, num_in_bytes) \
145 { \
146 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
147 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
148 typeof(out_buff) dst_ptr = (out_buff); \
149 typeof(in_buff) src_ptr = (in_buff); \
150 typeof(*out_buff) temp_buff[num_in_samples]; \
151 typeof(out_buff) temp_ptr = temp_buff; \
152 /* if in-place, copy input channels to a temp buffer */ \
153 if ((in_buff) == (out_buff)) { \
154 memcpy(temp_buff, src_ptr, (num_in_bytes)); \
155 src_ptr += num_in_samples; \
156 } else { \
157 temp_ptr = (typeof(out_buff)) src_ptr; \
158 src_ptr += num_in_samples; \
159 } \
160 /* interleave channels from end of source buffer with those from front */ \
161 size_t src_index; \
162 for (src_index = 0; src_index < num_out_samples; src_index += (out_buff_chans)) { \
163 size_t dst_offset; \
164 for (dst_offset = 0; dst_offset < (in_buff_chans); dst_offset++) { \
165 *dst_ptr++ = *temp_ptr++; \
166 } \
167 for (;dst_offset < (out_buff_chans); dst_offset++) { \
168 *dst_ptr++ = *src_ptr++; \
169 } \
170 } \
171 /* return number of *bytes* generated */ \
172 return num_out_samples * sizeof(*(out_buff)); \
173 }
174
175 /* Channel expands from a MONO input buffer to a MULTICHANNEL output buffer by duplicating the
176 * single input channel to the first 2 output channels and 0-filling the remaining.
177 * See expand_channels() function below for parameter definitions.
178 *
179 * in_buff_chans MUST be 1 and out_buff_chans MUST be >= 2
180 *
181 * Move from back to front so that the conversion can be done in-place
182 * i.e. in_buff == out_buff
183 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
184 *
185 * Macro has a return statement.
186 */
187 #define EXPAND_MONO_TO_MULTI(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
188 { \
189 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
190 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
191 typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
192 size_t src_index; \
193 typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
194 size_t num_zero_chans = (out_buff_chans) - (in_buff_chans) - 1; \
195 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
196 size_t dst_offset; \
197 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
198 *dst_ptr-- = zero; \
199 } \
200 for (; dst_offset < (out_buff_chans); dst_offset++) { \
201 *dst_ptr-- = *src_ptr; \
202 } \
203 src_ptr--; \
204 } \
205 /* return number of *bytes* generated */ \
206 return num_out_samples * sizeof(*(out_buff)); \
207 }
208
209 /* Channel contracts (removes from audio frame end) from an input buffer to an output buffer.
210 * See contract_channels() function below for parameter definitions.
211 *
212 * Move from front to back so that the conversion can be done in-place
213 * i.e. in_buff == out_buff
214 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
215 *
216 * Macro has a return statement.
217 */
218 #define CONTRACT_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
219 { \
220 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
221 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
222 size_t num_skip_samples = (in_buff_chans) - (out_buff_chans); \
223 typeof(out_buff) dst_ptr = out_buff; \
224 typeof(in_buff) src_ptr = in_buff; \
225 size_t src_index; \
226 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
227 size_t dst_offset; \
228 for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
229 *dst_ptr++ = *src_ptr++; \
230 } \
231 src_ptr += num_skip_samples; \
232 } \
233 /* return number of *bytes* generated */ \
234 return num_out_samples * sizeof(*(out_buff)); \
235 }
236
237 /* Contract number of channels from an input buffer to an output buffer,
238 * storing removed channels at end of buffer.
239 *
240 * See contract_channels_non_destructive() function below for parameter definitions.
241 *
242 * So for in_chans = 4, out_chans = 2: [1|2|3|4|1|2|3|4...] => [1|2|1|2...|3|4|3|4]
243 *
244 * NOTE: in_buff must be same size as out_buff and num_in_bytes must
245 * be a multiple of in_buff_channels * in_buff_sample_size.
246 *
247 * Uses a temporary buffer so that the conversion can be done in-place
248 * i.e. in_buff == out_buff
249 *
250 * Macro has a return statement.
251 */
252 #define CONTRACT_CHANNELS_NON_DESTRUCTIVE(in_buff, in_buff_chans, out_buff, \
253 out_buff_chans, num_in_bytes) \
254 { \
255 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
256 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
257 typeof(out_buff) dst_ptr = (out_buff); \
258 typeof(in_buff) src_ptr = (in_buff); \
259 size_t num_temp_samples = num_in_samples - num_out_samples; \
260 typeof(*out_buff) temp_buff[num_temp_samples]; \
261 typeof(out_buff) temp_ptr; \
262 /* if in-place, copy input channels to a temp buffer instead of out buffer */ \
263 if ((in_buff) == (out_buff)) { \
264 temp_ptr = temp_buff; \
265 } else { \
266 temp_ptr = dst_ptr + num_out_samples; \
267 } \
268 size_t src_index; \
269 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
270 size_t dst_offset; \
271 for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
272 *dst_ptr++ = *src_ptr++; \
273 } \
274 for (;dst_offset < (in_buff_chans); dst_offset++) { \
275 *temp_ptr++ = *src_ptr++; \
276 } \
277 } \
278 /* if in-place, interleave channels from the temp buffer */ \
279 if ((in_buff) == (out_buff)) { \
280 temp_ptr = temp_buff; \
281 memcpy(dst_ptr, temp_ptr, num_temp_samples * sizeof(*(in_buff))); \
282 } \
283 /* return number of *bytes* generated */ \
284 return num_out_samples * sizeof(*(out_buff)); \
285 }
286
287 /* Channel contracts from a MULTICHANNEL input buffer to a MONO output buffer by mixing the
288 * first two input channels into the single output channel (and skipping the rest).
289 * See contract_channels() function below for parameter definitions.
290 *
291 * in_buff_chans MUST be >= 2 and out_buff_chans MUST be 1
292 *
293 * Move from front to back so that the conversion can be done in-place
294 * i.e. in_buff == out_buff
295 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
296 * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
297 * NOTE: Can not be used for uint8x3_t samples, see CONTRACT_TO_MONO_24() below.
298 *
299 * Macro has a return statement.
300 */
301 #define CONTRACT_TO_MONO(in_buff, out_buff, num_in_bytes) \
302 { \
303 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
304 size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
305 size_t num_skip_samples = in_buff_chans - 2; \
306 typeof(out_buff) dst_ptr = out_buff; \
307 typeof(in_buff) src_ptr = in_buff; \
308 int32_t temp0, temp1; \
309 size_t src_index; \
310 for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
311 temp0 = *src_ptr++; \
312 temp1 = *src_ptr++; \
313 /* *dst_ptr++ = temp >> 1; */ \
314 /* This bit of magic adds and normalizes without overflow (or so claims hunga@) */ \
315 /* Bitwise half adder trick, see http://en.wikipedia.org/wiki/Adder_(electronics) */ \
316 /* Hacker's delight, p. 19 http://www.hackersdelight.org/basics2.pdf */ \
317 *dst_ptr++ = (temp0 & temp1) + ((temp0 ^ temp1) >> 1); \
318 src_ptr += num_skip_samples; \
319 } \
320 /* return number of *bytes* generated */ \
321 return num_out_samples * sizeof(*(out_buff)); \
322 }
323
324 /* Channel contracts from a MULTICHANNEL uint8x3_t input buffer to a MONO uint8x3_t output buffer
325 * by mixing the first two input channels into the single output channel (and skipping the rest).
326 * See contract_channels() function below for parameter definitions.
327 *
328 * Move from front to back so that the conversion can be done in-place
329 * i.e. in_buff == out_buff
330 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
331 * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
332 * NOTE: Can not be used for normal, scalar samples, see CONTRACT_TO_MONO() above.
333 *
334 * Macro has a return statement.
335 */
336 #define CONTRACT_TO_MONO_24(in_buff, out_buff, num_in_bytes) \
337 { \
338 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
339 size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
340 size_t num_skip_samples = in_buff_chans - 2; \
341 typeof(out_buff) dst_ptr = out_buff; \
342 typeof(in_buff) src_ptr = in_buff; \
343 int32_t temp; \
344 size_t src_index; \
345 for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
346 temp = uint8x3_to_int32(*src_ptr++); \
347 temp += uint8x3_to_int32(*src_ptr++); \
348 *dst_ptr = int32_to_uint8x3(temp >> 1); \
349 src_ptr += num_skip_samples; \
350 } \
351 /* return number of *bytes* generated */ \
352 return num_out_samples * sizeof(*(out_buff)); \
353 }
354
355 /*
356 * Convert a buffer of N-channel, interleaved samples to M-channel
357 * (where N > M).
358 * in_buff points to the buffer of samples
359 * in_buff_channels Specifies the number of channels in the input buffer.
360 * out_buff points to the buffer to receive converted samples.
361 * out_buff_channels Specifies the number of channels in the output buffer.
362 * sample_size_in_bytes Specifies the number of bytes per sample.
363 * num_in_bytes size of input buffer in BYTES
364 * returns
365 * the number of BYTES of output data.
366 * NOTE
367 * channels > M are thrown away.
368 * The out and sums buffers must either be completely separate (non-overlapping), or
369 * they must both start at the same address. Partially overlapping buffers are not supported.
370 */
contract_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)371 static size_t contract_channels(const void* in_buff, size_t in_buff_chans,
372 void* out_buff, size_t out_buff_chans,
373 unsigned sample_size_in_bytes, size_t num_in_bytes)
374 {
375 switch (sample_size_in_bytes) {
376 case 1:
377 if (out_buff_chans == 1) {
378 /* Special case Multi to Mono */
379 CONTRACT_TO_MONO((const uint8_t*)in_buff, (uint8_t*)out_buff, num_in_bytes);
380 // returns in macro
381 } else {
382 CONTRACT_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
383 (uint8_t*)out_buff, out_buff_chans,
384 num_in_bytes);
385 // returns in macro
386 }
387 case 2:
388 if (out_buff_chans == 1) {
389 /* Special case Multi to Mono */
390 CONTRACT_TO_MONO((const int16_t*)in_buff, (int16_t*)out_buff, num_in_bytes);
391 // returns in macro
392 } else {
393 CONTRACT_CHANNELS((const int16_t*)in_buff, in_buff_chans,
394 (int16_t*)out_buff, out_buff_chans,
395 num_in_bytes);
396 // returns in macro
397 }
398 case 3:
399 if (out_buff_chans == 1) {
400 /* Special case Multi to Mono */
401 CONTRACT_TO_MONO_24((const uint8x3_t*)in_buff,
402 (uint8x3_t*)out_buff, num_in_bytes);
403 // returns in macro
404 } else {
405 CONTRACT_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
406 (uint8x3_t*)out_buff, out_buff_chans,
407 num_in_bytes);
408 // returns in macro
409 }
410 case 4:
411 if (out_buff_chans == 1) {
412 /* Special case Multi to Mono */
413 CONTRACT_TO_MONO((const int32_t*)in_buff, (int32_t*)out_buff, num_in_bytes);
414 // returns in macro
415 } else {
416 CONTRACT_CHANNELS((const int32_t*)in_buff, in_buff_chans,
417 (int32_t*)out_buff, out_buff_chans,
418 num_in_bytes);
419 // returns in macro
420 }
421 default:
422 return 0;
423 }
424 }
425
426 /*
427 * Convert a buffer of N-channel, interleaved samples to M-channel
428 * (where N > M).
429 * in_buff points to the buffer of samples
430 * in_buff_channels specifies the number of channels in the input buffer.
431 * out_buff points to the buffer to receive converted samples.
432 * out_buff_channels specifies the number of channels in the output buffer.
433 * sample_size_in_bytes specifies the number of bytes per sample.
434 * num_in_bytes size of input buffer in BYTES
435 * returns
436 * the number of BYTES of output data.
437 * NOTE
438 * channels > M are stored at the end of the output buffer.
439 * The output and input buffers must be the same length.
440 * The output and input buffers must either be completely separate (non-overlapping), or
441 * they must both start at the same address. Partially overlapping buffers are not supported.
442 */
contract_channels_non_destructive(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)443 static size_t contract_channels_non_destructive(const void* in_buff, size_t in_buff_chans,
444 void* out_buff, size_t out_buff_chans,
445 unsigned sample_size_in_bytes, size_t num_in_bytes)
446 {
447 switch (sample_size_in_bytes) {
448 case 1:
449 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const uint8_t*)in_buff, in_buff_chans,
450 (uint8_t*)out_buff, out_buff_chans,
451 num_in_bytes);
452 // returns in macro
453 case 2:
454 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const int16_t*)in_buff, in_buff_chans,
455 (int16_t*)out_buff, out_buff_chans,
456 num_in_bytes);
457 // returns in macro
458 case 3:
459 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const uint8x3_t*)in_buff, in_buff_chans,
460 (uint8x3_t*)out_buff, out_buff_chans,
461 num_in_bytes);
462 // returns in macro
463 case 4:
464 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const int32_t*)in_buff, in_buff_chans,
465 (int32_t*)out_buff, out_buff_chans,
466 num_in_bytes);
467 // returns in macro
468 default:
469 return 0;
470 }
471 }
472
473 /*
474 * Convert a buffer of N-channel, interleaved samples to M-channel
475 * (where N < M).
476 * in_buff points to the buffer of samples
477 * in_buff_channels Specifies the number of channels in the input buffer.
478 * out_buff points to the buffer to receive converted samples.
479 * out_buff_channels Specifies the number of channels in the output buffer.
480 * sample_size_in_bytes Specifies the number of bytes per sample.
481 * num_in_bytes size of input buffer in BYTES
482 * returns
483 * the number of BYTES of output data.
484 * NOTE
485 * channels > N are filled with silence.
486 * The out and sums buffers must either be completely separate (non-overlapping), or
487 * they must both start at the same address. Partially overlapping buffers are not supported.
488 */
expand_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)489 static size_t expand_channels(const void* in_buff, size_t in_buff_chans,
490 void* out_buff, size_t out_buff_chans,
491 unsigned sample_size_in_bytes, size_t num_in_bytes)
492 {
493 static const uint8x3_t packed24_zero; /* zero 24 bit sample */
494
495 switch (sample_size_in_bytes) {
496 case 1:
497 if (in_buff_chans == 1) {
498 /* special case of mono source to multi-channel */
499 EXPAND_MONO_TO_MULTI((const uint8_t*)in_buff, in_buff_chans,
500 (uint8_t*)out_buff, out_buff_chans,
501 num_in_bytes, 0);
502 // returns in macro
503 } else {
504 EXPAND_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
505 (uint8_t*)out_buff, out_buff_chans,
506 num_in_bytes, 0);
507 // returns in macro
508 }
509 case 2:
510 if (in_buff_chans == 1) {
511 /* special case of mono source to multi-channel */
512 EXPAND_MONO_TO_MULTI((const int16_t*)in_buff, in_buff_chans,
513 (int16_t*)out_buff, out_buff_chans,
514 num_in_bytes, 0);
515 // returns in macro
516 } else {
517 EXPAND_CHANNELS((const int16_t*)in_buff, in_buff_chans,
518 (int16_t*)out_buff, out_buff_chans,
519 num_in_bytes, 0);
520 // returns in macro
521 }
522 case 3:
523 if (in_buff_chans == 1) {
524 /* special case of mono source to multi-channel */
525 EXPAND_MONO_TO_MULTI((const uint8x3_t*)in_buff, in_buff_chans,
526 (uint8x3_t*)out_buff, out_buff_chans,
527 num_in_bytes, packed24_zero);
528 // returns in macro
529 } else {
530 EXPAND_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
531 (uint8x3_t*)out_buff, out_buff_chans,
532 num_in_bytes, packed24_zero);
533 // returns in macro
534 }
535 case 4:
536 if (in_buff_chans == 1) {
537 /* special case of mono source to multi-channel */
538 EXPAND_MONO_TO_MULTI((const int32_t*)in_buff, in_buff_chans,
539 (int32_t*)out_buff, out_buff_chans,
540 num_in_bytes, 0);
541 // returns in macro
542 } else {
543 EXPAND_CHANNELS((const int32_t*)in_buff, in_buff_chans,
544 (int32_t*)out_buff, out_buff_chans,
545 num_in_bytes, 0);
546 // returns in macro
547 }
548 default:
549 return 0;
550 }
551 }
552
553 /*
554 * Convert a buffer of N-channel, interleaved samples to M-channel
555 * (where N < M).
556 * in_buff points to the buffer of samples
557 * in_buff_channels Specifies the number of channels in the input buffer.
558 * out_buff points to the buffer to receive converted samples.
559 * out_buff_channels Specifies the number of channels in the output buffer.
560 * sample_size_in_bytes Specifies the number of bytes per sample.
561 * num_in_bytes size of input buffer in BYTES
562 * returns
563 * the number of BYTES of output data.
564 * NOTE
565 * channels > N are left alone in out_buff.
566 * The out and in buffers must either be completely separate (non-overlapping), or
567 * they must both start at the same address. Partially overlapping buffers are not supported.
568 */
expand_selected_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)569 static size_t expand_selected_channels(const void* in_buff, size_t in_buff_chans,
570 void* out_buff, size_t out_buff_chans,
571 unsigned sample_size_in_bytes, size_t num_in_bytes)
572 {
573 switch (sample_size_in_bytes) {
574 case 1:
575
576 EXPAND_SELECTED_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
577 (uint8_t*)out_buff, out_buff_chans,
578 num_in_bytes);
579 // returns in macro
580
581 case 2:
582
583 EXPAND_SELECTED_CHANNELS((const int16_t*)in_buff, in_buff_chans,
584 (int16_t*)out_buff, out_buff_chans,
585 num_in_bytes);
586 // returns in macro
587
588 case 3:
589
590 EXPAND_SELECTED_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
591 (uint8x3_t*)out_buff, out_buff_chans,
592 num_in_bytes);
593 // returns in macro
594
595 case 4:
596
597 EXPAND_SELECTED_CHANNELS((const int32_t*)in_buff, in_buff_chans,
598 (int32_t*)out_buff, out_buff_chans,
599 num_in_bytes);
600 // returns in macro
601
602 default:
603 return 0;
604 }
605 }
606
607 /*
608 * Convert a buffer of N-channel, interleaved samples to M-channel
609 * (where N < M).
610 * in_buff points to the buffer of samples
611 * in_buff_channels Specifies the number of channels in the input buffer.
612 * out_buff points to the buffer to receive converted samples.
613 * out_buff_channels Specifies the number of channels in the output buffer.
614 * sample_size_in_bytes Specifies the number of bytes per sample.
615 * num_in_bytes size of input buffer in BYTES
616 * returns
617 * the number of BYTES of output data.
618 * NOTE
619 * channels > N are interleaved with data from the end of the input buffer.
620 * The output and input buffers must be the same length.
621 * The output and input buffers must either be completely separate (non-overlapping), or
622 * they must both start at the same address. Partially overlapping buffers are not supported.
623 */
expand_channels_non_destructive(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)624 static size_t expand_channels_non_destructive(const void* in_buff, size_t in_buff_chans,
625 void* out_buff, size_t out_buff_chans,
626 unsigned sample_size_in_bytes, size_t num_in_bytes)
627 {
628 switch (sample_size_in_bytes) {
629 case 1:
630
631 EXPAND_CHANNELS_NON_DESTRUCTIVE((const uint8_t*)in_buff, in_buff_chans,
632 (uint8_t*)out_buff, out_buff_chans,
633 num_in_bytes);
634 // returns in macro
635
636 case 2:
637
638 EXPAND_CHANNELS_NON_DESTRUCTIVE((const int16_t*)in_buff, in_buff_chans,
639 (int16_t*)out_buff, out_buff_chans,
640 num_in_bytes);
641 // returns in macro
642
643 case 3:
644
645 EXPAND_CHANNELS_NON_DESTRUCTIVE((const uint8x3_t*)in_buff, in_buff_chans,
646 (uint8x3_t*)out_buff, out_buff_chans,
647 num_in_bytes);
648 // returns in macro
649
650 case 4:
651
652 EXPAND_CHANNELS_NON_DESTRUCTIVE((const int32_t*)in_buff, in_buff_chans,
653 (int32_t*)out_buff, out_buff_chans,
654 num_in_bytes);
655 // returns in macro
656
657 default:
658 return 0;
659 }
660 }
661
adjust_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)662 size_t adjust_channels(const void* in_buff, size_t in_buff_chans,
663 void* out_buff, size_t out_buff_chans,
664 unsigned sample_size_in_bytes, size_t num_in_bytes)
665 {
666 if (out_buff_chans > in_buff_chans) {
667 return expand_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
668 sample_size_in_bytes, num_in_bytes);
669 } else if (out_buff_chans < in_buff_chans) {
670 return contract_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
671 sample_size_in_bytes, num_in_bytes);
672 } else if (in_buff != out_buff) {
673 memcpy(out_buff, in_buff, num_in_bytes);
674 }
675
676 return num_in_bytes;
677 }
678
adjust_selected_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)679 size_t adjust_selected_channels(const void* in_buff, size_t in_buff_chans,
680 void* out_buff, size_t out_buff_chans,
681 unsigned sample_size_in_bytes, size_t num_in_bytes)
682 {
683 if (out_buff_chans > in_buff_chans) {
684 return expand_selected_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
685 sample_size_in_bytes, num_in_bytes);
686 } else if (out_buff_chans < in_buff_chans) {
687 return contract_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
688 sample_size_in_bytes, num_in_bytes);
689 } else if (in_buff != out_buff) {
690 memcpy(out_buff, in_buff, num_in_bytes);
691 }
692
693 return num_in_bytes;
694 }
695
adjust_channels_non_destructive(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)696 size_t adjust_channels_non_destructive(const void* in_buff, size_t in_buff_chans,
697 void* out_buff, size_t out_buff_chans,
698 unsigned sample_size_in_bytes, size_t num_in_bytes)
699 {
700 if (out_buff_chans > in_buff_chans) {
701 return expand_channels_non_destructive(in_buff, in_buff_chans, out_buff, out_buff_chans,
702 sample_size_in_bytes, num_in_bytes);
703 } else if (out_buff_chans < in_buff_chans) {
704 return contract_channels_non_destructive(in_buff, in_buff_chans, out_buff, out_buff_chans,
705 sample_size_in_bytes, num_in_bytes);
706 } else if (in_buff != out_buff) {
707 memcpy(out_buff, in_buff, num_in_bytes);
708 }
709
710 return num_in_bytes;
711 }
712