blob: a1bdec1722e5d91eb1428f87c31a6577dea7c222 [file] [log] [blame]
Paul McLeand31709d2014-07-16 13:35:52 -07001/*
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>
Paul McLeand31709d2014-07-16 13:35:52 -070018#include <audio_utils/channels.h>
Andy Hunge0ccb202014-07-27 20:11:31 -070019#include "private/private.h"
Paul McLeand31709d2014-07-16 13:35:52 -070020
Paul McLeand1109302014-09-09 09:09:16 -070021/*
22 * Clamps a 24-bit value from a 32-bit sample
23 */
24static 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 */
Colin Crossc7eae5d2017-06-30 14:05:23 -070035static inline int32_t uint8x3_to_int32(uint8x3_t val) {
Andy Hung2af0e172017-03-31 14:08:14 -070036#if HAVE_BIG_ENDIAN
Paul McLeand1109302014-09-09 09:09:16 -070037 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 */
Colin Crossc7eae5d2017-06-30 14:05:23 -070047static inline uint8x3_t int32_to_uint8x3(int32_t in) {
Paul McLeand1109302014-09-09 09:09:16 -070048 uint8x3_t out;
Andy Hung2af0e172017-03-31 14:08:14 -070049#if HAVE_BIG_ENDIAN
Paul McLeand1109302014-09-09 09:09:16 -070050 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
Emilie Robertscc5cd1b2018-07-13 19:59:18 +000061/* 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
Andy Hunge0ccb202014-07-27 20:11:31 -070067/* 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.
Emilie Robertscc5cd1b2018-07-13 19:59:18 +000073 *
74 * Macro has a return statement.
Paul McLeand31709d2014-07-16 13:35:52 -070075 */
Andy Hunge0ccb202014-07-27 20:11:31 -070076#define EXPAND_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
77{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070078 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; \
Andy Hunge0ccb202014-07-27 20:11:31 -070081 size_t src_index; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070082 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)) { \
Andy Hunge0ccb202014-07-27 20:11:31 -070085 size_t dst_offset; \
86 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
87 *dst_ptr-- = zero; \
88 } \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070089 for (; dst_offset < (out_buff_chans); dst_offset++) { \
Andy Hunge0ccb202014-07-27 20:11:31 -070090 *dst_ptr-- = *src_ptr--; \
91 } \
92 } \
93 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070094 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand31709d2014-07-16 13:35:52 -070095}
96
Andy Hung09bddf22017-12-01 13:24:52 -080097/* 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.
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000105 *
106 * Macro has a return statement.
Andy Hung09bddf22017-12-01 13:24:52 -0800107 */
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
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000127/* 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}
Andy Hung09bddf22017-12-01 13:24:52 -0800174
Paul McLeand1109302014-09-09 09:09:16 -0700175/* 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.
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000184 *
185 * Macro has a return statement.
Paul McLeand1109302014-09-09 09:09:16 -0700186 */
187#define EXPAND_MONO_TO_MULTI(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
188{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700189 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; \
Paul McLeand1109302014-09-09 09:09:16 -0700192 size_t src_index; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700193 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)) { \
Paul McLeand1109302014-09-09 09:09:16 -0700196 size_t dst_offset; \
197 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
198 *dst_ptr-- = zero; \
199 } \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700200 for (; dst_offset < (out_buff_chans); dst_offset++) { \
Paul McLeand1109302014-09-09 09:09:16 -0700201 *dst_ptr-- = *src_ptr; \
202 } \
203 src_ptr--; \
204 } \
205 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700206 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700207}
208
Andy Hunge0ccb202014-07-27 20:11:31 -0700209/* 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.
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000215 *
216 * Macro has a return statement.
Paul McLeand31709d2014-07-16 13:35:52 -0700217 */
Andy Hunge0ccb202014-07-27 20:11:31 -0700218#define CONTRACT_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
219{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700220 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); \
Andy Hunge0ccb202014-07-27 20:11:31 -0700223 typeof(out_buff) dst_ptr = out_buff; \
224 typeof(in_buff) src_ptr = in_buff; \
225 size_t src_index; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700226 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
Andy Hunge0ccb202014-07-27 20:11:31 -0700227 size_t dst_offset; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700228 for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
Andy Hunge0ccb202014-07-27 20:11:31 -0700229 *dst_ptr++ = *src_ptr++; \
230 } \
231 src_ptr += num_skip_samples; \
232 } \
233 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700234 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand31709d2014-07-16 13:35:52 -0700235}
236
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000237/* 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
Paul McLeand1109302014-09-09 09:09:16 -0700287/* 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.
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000298 *
299 * Macro has a return statement.
Paul McLeand1109302014-09-09 09:09:16 -0700300 */
301#define CONTRACT_TO_MONO(in_buff, out_buff, num_in_bytes) \
302{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700303 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700304 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 */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700321 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700322}
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.
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000333 *
334 * Macro has a return statement.
Paul McLeand1109302014-09-09 09:09:16 -0700335 */
336#define CONTRACT_TO_MONO_24(in_buff, out_buff, num_in_bytes) \
337{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700338 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700339 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 */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700352 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700353}
354
Paul McLeand31709d2014-07-16 13:35:52 -0700355/*
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 */
371static 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) {
Andy Hunge0ccb202014-07-27 20:11:31 -0700376 case 1:
Paul McLeand1109302014-09-09 09:09:16 -0700377 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700387 case 2:
Paul McLeand1109302014-09-09 09:09:16 -0700388 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700398 case 3:
Paul McLeand1109302014-09-09 09:09:16 -0700399 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700410 case 4:
Paul McLeand1109302014-09-09 09:09:16 -0700411 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700421 default:
422 return 0;
423 }
424}
425
426/*
427 * Convert a buffer of N-channel, interleaved samples to M-channel
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000428 * (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 */
443static 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
Paul McLeand31709d2014-07-16 13:35:52 -0700475 * (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 */
489static 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{
Andy Hungad861e62021-05-18 11:51:54 -0700493 static const uint8x3_t packed24_zero{}; /* zero 24 bit sample */
Andy Hunge0ccb202014-07-27 20:11:31 -0700494
Paul McLeand31709d2014-07-16 13:35:52 -0700495 switch (sample_size_in_bytes) {
Andy Hunge0ccb202014-07-27 20:11:31 -0700496 case 1:
Paul McLeand1109302014-09-09 09:09:16 -0700497 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700509 case 2:
Paul McLeand1109302014-09-09 09:09:16 -0700510 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700522 case 3:
Paul McLeand1109302014-09-09 09:09:16 -0700523 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700535 case 4:
Paul McLeand1109302014-09-09 09:09:16 -0700536 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 }
Paul McLeand31709d2014-07-16 13:35:52 -0700548 default:
549 return 0;
550 }
551}
552
Andy Hung09bddf22017-12-01 13:24:52 -0800553/*
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 */
569static 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
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000607/*
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 */
624static 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
662size_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
Andy Hung09bddf22017-12-01 13:24:52 -0800679size_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
Emilie Robertscc5cd1b2018-07-13 19:59:18 +0000696size_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}