blob: 83a74b8485ab1faa8ebed90d135b504a01075e77 [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
Andy Hunge0ccb202014-07-27 20:11:31 -070061/* Channel expands (adds zeroes to audio frame end) from an input buffer to an output buffer.
62 * See expand_channels() function below for parameter definitions.
63 *
64 * Move from back to front so that the conversion can be done in-place
65 * i.e. in_buff == out_buff
66 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
Paul McLeand31709d2014-07-16 13:35:52 -070067 */
Andy Hunge0ccb202014-07-27 20:11:31 -070068#define EXPAND_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
69{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070070 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
71 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
72 typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
Andy Hunge0ccb202014-07-27 20:11:31 -070073 size_t src_index; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070074 typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
75 size_t num_zero_chans = (out_buff_chans) - (in_buff_chans); \
76 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
Andy Hunge0ccb202014-07-27 20:11:31 -070077 size_t dst_offset; \
78 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
79 *dst_ptr-- = zero; \
80 } \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070081 for (; dst_offset < (out_buff_chans); dst_offset++) { \
Andy Hunge0ccb202014-07-27 20:11:31 -070082 *dst_ptr-- = *src_ptr--; \
83 } \
84 } \
85 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -070086 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand31709d2014-07-16 13:35:52 -070087}
88
Andy Hung09bddf22017-12-01 13:24:52 -080089/* Channel expands from an input buffer to an output buffer.
90 * See expand_selected_channels() function below for parameter definitions.
91 * Selected channels are replaced in the output buffer, with any extra channels
92 * per frame left alone.
93 *
94 * Move from back to front so that the conversion can be done in-place
95 * i.e. in_buff == out_buff
96 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
97 */
98/* This is written as a C macro because it operates on generic types,
99 * which in a C++ file could be alternatively achieved by a "template"
100 * or an "auto" declaration.
101 * TODO: convert this from a C file to a C++ file.
102 */
103#define EXPAND_SELECTED_CHANNELS( \
104 in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
105{ \
106 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
107 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
108 typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
109 size_t src_index; \
110 typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
111 size_t num_extra_chans = (out_buff_chans) - (in_buff_chans); \
112 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
113 dst_ptr -= num_extra_chans; \
114 for (size_t dst_offset = num_extra_chans; dst_offset < (out_buff_chans); dst_offset++) { \
115 *dst_ptr-- = *src_ptr--; \
116 } \
117 } \
118 /* return number of *bytes* generated */ \
119 return num_out_samples * sizeof(*(out_buff)); \
120}
121
122
Paul McLeand1109302014-09-09 09:09:16 -0700123/* Channel expands from a MONO input buffer to a MULTICHANNEL output buffer by duplicating the
124 * single input channel to the first 2 output channels and 0-filling the remaining.
125 * See expand_channels() function below for parameter definitions.
126 *
127 * in_buff_chans MUST be 1 and out_buff_chans MUST be >= 2
128 *
129 * Move from back to front so that the conversion can be done in-place
130 * i.e. in_buff == out_buff
131 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
132 */
133#define EXPAND_MONO_TO_MULTI(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
134{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700135 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
136 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
137 typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
Paul McLeand1109302014-09-09 09:09:16 -0700138 size_t src_index; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700139 typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
140 size_t num_zero_chans = (out_buff_chans) - (in_buff_chans) - 1; \
141 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
Paul McLeand1109302014-09-09 09:09:16 -0700142 size_t dst_offset; \
143 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
144 *dst_ptr-- = zero; \
145 } \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700146 for (; dst_offset < (out_buff_chans); dst_offset++) { \
Paul McLeand1109302014-09-09 09:09:16 -0700147 *dst_ptr-- = *src_ptr; \
148 } \
149 src_ptr--; \
150 } \
151 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700152 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700153}
154
Andy Hunge0ccb202014-07-27 20:11:31 -0700155/* Channel contracts (removes from audio frame end) from an input buffer to an output buffer.
156 * See contract_channels() function below for parameter definitions.
157 *
158 * Move from front to back so that the conversion can be done in-place
159 * i.e. in_buff == out_buff
160 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
Paul McLeand31709d2014-07-16 13:35:52 -0700161 */
Andy Hunge0ccb202014-07-27 20:11:31 -0700162#define CONTRACT_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
163{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700164 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
165 size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
166 size_t num_skip_samples = (in_buff_chans) - (out_buff_chans); \
Andy Hunge0ccb202014-07-27 20:11:31 -0700167 typeof(out_buff) dst_ptr = out_buff; \
168 typeof(in_buff) src_ptr = in_buff; \
169 size_t src_index; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700170 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
Andy Hunge0ccb202014-07-27 20:11:31 -0700171 size_t dst_offset; \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700172 for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
Andy Hunge0ccb202014-07-27 20:11:31 -0700173 *dst_ptr++ = *src_ptr++; \
174 } \
175 src_ptr += num_skip_samples; \
176 } \
177 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700178 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand31709d2014-07-16 13:35:52 -0700179}
180
Paul McLeand1109302014-09-09 09:09:16 -0700181/* Channel contracts from a MULTICHANNEL input buffer to a MONO output buffer by mixing the
182 * first two input channels into the single output channel (and skipping the rest).
183 * See contract_channels() function below for parameter definitions.
184 *
185 * in_buff_chans MUST be >= 2 and out_buff_chans MUST be 1
186 *
187 * Move from front to back so that the conversion can be done in-place
188 * i.e. in_buff == out_buff
189 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
190 * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
191 * NOTE: Can not be used for uint8x3_t samples, see CONTRACT_TO_MONO_24() below.
192 */
193#define CONTRACT_TO_MONO(in_buff, out_buff, num_in_bytes) \
194{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700195 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700196 size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
197 size_t num_skip_samples = in_buff_chans - 2; \
198 typeof(out_buff) dst_ptr = out_buff; \
199 typeof(in_buff) src_ptr = in_buff; \
200 int32_t temp0, temp1; \
201 size_t src_index; \
202 for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
203 temp0 = *src_ptr++; \
204 temp1 = *src_ptr++; \
205 /* *dst_ptr++ = temp >> 1; */ \
206 /* This bit of magic adds and normalizes without overflow (or so claims hunga@) */ \
207 /* Bitwise half adder trick, see http://en.wikipedia.org/wiki/Adder_(electronics) */ \
208 /* Hacker's delight, p. 19 http://www.hackersdelight.org/basics2.pdf */ \
209 *dst_ptr++ = (temp0 & temp1) + ((temp0 ^ temp1) >> 1); \
210 src_ptr += num_skip_samples; \
211 } \
212 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700213 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700214}
215
216/* Channel contracts from a MULTICHANNEL uint8x3_t input buffer to a MONO uint8x3_t output buffer
217 * by mixing the first two input channels into the single output channel (and skipping the rest).
218 * See contract_channels() function below for parameter definitions.
219 *
220 * Move from front to back so that the conversion can be done in-place
221 * i.e. in_buff == out_buff
222 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
223 * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
224 * NOTE: Can not be used for normal, scalar samples, see CONTRACT_TO_MONO() above.
225 */
226#define CONTRACT_TO_MONO_24(in_buff, out_buff, num_in_bytes) \
227{ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700228 size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700229 size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
230 size_t num_skip_samples = in_buff_chans - 2; \
231 typeof(out_buff) dst_ptr = out_buff; \
232 typeof(in_buff) src_ptr = in_buff; \
233 int32_t temp; \
234 size_t src_index; \
235 for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
236 temp = uint8x3_to_int32(*src_ptr++); \
237 temp += uint8x3_to_int32(*src_ptr++); \
238 *dst_ptr = int32_to_uint8x3(temp >> 1); \
239 src_ptr += num_skip_samples; \
240 } \
241 /* return number of *bytes* generated */ \
Chih-Hung Hsieh2c853ac2016-05-11 15:13:31 -0700242 return num_out_samples * sizeof(*(out_buff)); \
Paul McLeand1109302014-09-09 09:09:16 -0700243}
244
Paul McLeand31709d2014-07-16 13:35:52 -0700245/*
246 * Convert a buffer of N-channel, interleaved samples to M-channel
247 * (where N > M).
248 * in_buff points to the buffer of samples
249 * in_buff_channels Specifies the number of channels in the input buffer.
250 * out_buff points to the buffer to receive converted samples.
251 * out_buff_channels Specifies the number of channels in the output buffer.
252 * sample_size_in_bytes Specifies the number of bytes per sample.
253 * num_in_bytes size of input buffer in BYTES
254 * returns
255 * the number of BYTES of output data.
256 * NOTE
257 * channels > M are thrown away.
258 * The out and sums buffers must either be completely separate (non-overlapping), or
259 * they must both start at the same address. Partially overlapping buffers are not supported.
260 */
261static size_t contract_channels(const void* in_buff, size_t in_buff_chans,
262 void* out_buff, size_t out_buff_chans,
263 unsigned sample_size_in_bytes, size_t num_in_bytes)
264{
265 switch (sample_size_in_bytes) {
Andy Hunge0ccb202014-07-27 20:11:31 -0700266 case 1:
Paul McLeand1109302014-09-09 09:09:16 -0700267 if (out_buff_chans == 1) {
268 /* Special case Multi to Mono */
269 CONTRACT_TO_MONO((const uint8_t*)in_buff, (uint8_t*)out_buff, num_in_bytes);
270 // returns in macro
271 } else {
272 CONTRACT_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
273 (uint8_t*)out_buff, out_buff_chans,
274 num_in_bytes);
275 // returns in macro
276 }
Paul McLeand31709d2014-07-16 13:35:52 -0700277 case 2:
Paul McLeand1109302014-09-09 09:09:16 -0700278 if (out_buff_chans == 1) {
279 /* Special case Multi to Mono */
280 CONTRACT_TO_MONO((const int16_t*)in_buff, (int16_t*)out_buff, num_in_bytes);
281 // returns in macro
282 } else {
283 CONTRACT_CHANNELS((const int16_t*)in_buff, in_buff_chans,
284 (int16_t*)out_buff, out_buff_chans,
285 num_in_bytes);
286 // returns in macro
287 }
Paul McLeand31709d2014-07-16 13:35:52 -0700288 case 3:
Paul McLeand1109302014-09-09 09:09:16 -0700289 if (out_buff_chans == 1) {
290 /* Special case Multi to Mono */
291 CONTRACT_TO_MONO_24((const uint8x3_t*)in_buff,
292 (uint8x3_t*)out_buff, num_in_bytes);
293 // returns in macro
294 } else {
295 CONTRACT_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
296 (uint8x3_t*)out_buff, out_buff_chans,
297 num_in_bytes);
298 // returns in macro
299 }
Paul McLeand31709d2014-07-16 13:35:52 -0700300 case 4:
Paul McLeand1109302014-09-09 09:09:16 -0700301 if (out_buff_chans == 1) {
302 /* Special case Multi to Mono */
303 CONTRACT_TO_MONO((const int32_t*)in_buff, (int32_t*)out_buff, num_in_bytes);
304 // returns in macro
305 } else {
306 CONTRACT_CHANNELS((const int32_t*)in_buff, in_buff_chans,
307 (int32_t*)out_buff, out_buff_chans,
308 num_in_bytes);
309 // returns in macro
310 }
Paul McLeand31709d2014-07-16 13:35:52 -0700311 default:
312 return 0;
313 }
314}
315
316/*
317 * Convert a buffer of N-channel, interleaved samples to M-channel
318 * (where N < M).
319 * in_buff points to the buffer of samples
320 * in_buff_channels Specifies the number of channels in the input buffer.
321 * out_buff points to the buffer to receive converted samples.
322 * out_buff_channels Specifies the number of channels in the output buffer.
323 * sample_size_in_bytes Specifies the number of bytes per sample.
324 * num_in_bytes size of input buffer in BYTES
325 * returns
326 * the number of BYTES of output data.
327 * NOTE
328 * channels > N are filled with silence.
329 * The out and sums buffers must either be completely separate (non-overlapping), or
330 * they must both start at the same address. Partially overlapping buffers are not supported.
331 */
332static size_t expand_channels(const void* in_buff, size_t in_buff_chans,
333 void* out_buff, size_t out_buff_chans,
334 unsigned sample_size_in_bytes, size_t num_in_bytes)
335{
Andy Hunge0ccb202014-07-27 20:11:31 -0700336 static const uint8x3_t packed24_zero; /* zero 24 bit sample */
337
Paul McLeand31709d2014-07-16 13:35:52 -0700338 switch (sample_size_in_bytes) {
Andy Hunge0ccb202014-07-27 20:11:31 -0700339 case 1:
Paul McLeand1109302014-09-09 09:09:16 -0700340 if (in_buff_chans == 1) {
341 /* special case of mono source to multi-channel */
342 EXPAND_MONO_TO_MULTI((const uint8_t*)in_buff, in_buff_chans,
343 (uint8_t*)out_buff, out_buff_chans,
344 num_in_bytes, 0);
345 // returns in macro
346 } else {
347 EXPAND_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
348 (uint8_t*)out_buff, out_buff_chans,
349 num_in_bytes, 0);
350 // returns in macro
351 }
Paul McLeand31709d2014-07-16 13:35:52 -0700352 case 2:
Paul McLeand1109302014-09-09 09:09:16 -0700353 if (in_buff_chans == 1) {
354 /* special case of mono source to multi-channel */
355 EXPAND_MONO_TO_MULTI((const int16_t*)in_buff, in_buff_chans,
356 (int16_t*)out_buff, out_buff_chans,
357 num_in_bytes, 0);
358 // returns in macro
359 } else {
360 EXPAND_CHANNELS((const int16_t*)in_buff, in_buff_chans,
361 (int16_t*)out_buff, out_buff_chans,
362 num_in_bytes, 0);
363 // returns in macro
364 }
Paul McLeand31709d2014-07-16 13:35:52 -0700365 case 3:
Paul McLeand1109302014-09-09 09:09:16 -0700366 if (in_buff_chans == 1) {
367 /* special case of mono source to multi-channel */
368 EXPAND_MONO_TO_MULTI((const uint8x3_t*)in_buff, in_buff_chans,
369 (uint8x3_t*)out_buff, out_buff_chans,
370 num_in_bytes, packed24_zero);
371 // returns in macro
372 } else {
373 EXPAND_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
374 (uint8x3_t*)out_buff, out_buff_chans,
375 num_in_bytes, packed24_zero);
376 // returns in macro
377 }
Paul McLeand31709d2014-07-16 13:35:52 -0700378 case 4:
Paul McLeand1109302014-09-09 09:09:16 -0700379 if (in_buff_chans == 1) {
380 /* special case of mono source to multi-channel */
381 EXPAND_MONO_TO_MULTI((const int32_t*)in_buff, in_buff_chans,
382 (int32_t*)out_buff, out_buff_chans,
383 num_in_bytes, 0);
384 // returns in macro
385 } else {
386 EXPAND_CHANNELS((const int32_t*)in_buff, in_buff_chans,
387 (int32_t*)out_buff, out_buff_chans,
388 num_in_bytes, 0);
389 // returns in macro
390 }
Paul McLeand31709d2014-07-16 13:35:52 -0700391 default:
392 return 0;
393 }
394}
395
396size_t adjust_channels(const void* in_buff, size_t in_buff_chans,
397 void* out_buff, size_t out_buff_chans,
398 unsigned sample_size_in_bytes, size_t num_in_bytes)
399{
400 if (out_buff_chans > in_buff_chans) {
401 return expand_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
402 sample_size_in_bytes, num_in_bytes);
403 } else if (out_buff_chans < in_buff_chans) {
404 return contract_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
405 sample_size_in_bytes, num_in_bytes);
406 } else if (in_buff != out_buff) {
407 memcpy(out_buff, in_buff, num_in_bytes);
408 }
409
410 return num_in_bytes;
411}
Andy Hung09bddf22017-12-01 13:24:52 -0800412
413/*
414 * Convert a buffer of N-channel, interleaved samples to M-channel
415 * (where N < M).
416 * in_buff points to the buffer of samples
417 * in_buff_channels Specifies the number of channels in the input buffer.
418 * out_buff points to the buffer to receive converted samples.
419 * out_buff_channels Specifies the number of channels in the output buffer.
420 * sample_size_in_bytes Specifies the number of bytes per sample.
421 * num_in_bytes size of input buffer in BYTES
422 * returns
423 * the number of BYTES of output data.
424 * NOTE
425 * channels > N are left alone in out_buff.
426 * The out and in buffers must either be completely separate (non-overlapping), or
427 * they must both start at the same address. Partially overlapping buffers are not supported.
428 */
429static size_t expand_selected_channels(const void* in_buff, size_t in_buff_chans,
430 void* out_buff, size_t out_buff_chans,
431 unsigned sample_size_in_bytes, size_t num_in_bytes)
432{
433 switch (sample_size_in_bytes) {
434 case 1:
435
436 EXPAND_SELECTED_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
437 (uint8_t*)out_buff, out_buff_chans,
438 num_in_bytes);
439 // returns in macro
440
441 case 2:
442
443 EXPAND_SELECTED_CHANNELS((const int16_t*)in_buff, in_buff_chans,
444 (int16_t*)out_buff, out_buff_chans,
445 num_in_bytes);
446 // returns in macro
447
448 case 3:
449
450 EXPAND_SELECTED_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
451 (uint8x3_t*)out_buff, out_buff_chans,
452 num_in_bytes);
453 // returns in macro
454
455 case 4:
456
457 EXPAND_SELECTED_CHANNELS((const int32_t*)in_buff, in_buff_chans,
458 (int32_t*)out_buff, out_buff_chans,
459 num_in_bytes);
460 // returns in macro
461
462 default:
463 return 0;
464 }
465}
466
467size_t adjust_selected_channels(const void* in_buff, size_t in_buff_chans,
468 void* out_buff, size_t out_buff_chans,
469 unsigned sample_size_in_bytes, size_t num_in_bytes)
470{
471 if (out_buff_chans > in_buff_chans) {
472 return expand_selected_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
473 sample_size_in_bytes, num_in_bytes);
474 } else if (out_buff_chans < in_buff_chans) {
475 return contract_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
476 sample_size_in_bytes, num_in_bytes);
477 } else if (in_buff != out_buff) {
478 memcpy(out_buff, in_buff, num_in_bytes);
479 }
480
481 return num_in_bytes;
482}
483