• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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