2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <audio_utils/channels.h>
19 #include "private/private.h"
22 * Clamps a 24-bit value from a 32-bit sample
24 static inline int32_t clamp24(int32_t sample)
26 if ((sample>>23) ^ (sample>>31)) {
27 sample = 0x007FFFFF ^ (sample>>31);
33 * Converts a uint8x3_t into an int32_t
35 static inline int32_t uint8x3_to_int32(uint8x3_t val) {
37 int32_t temp = (val.c[0] << 24 | val.c[1] << 16 | val.c[2] << 8) >> 8;
39 int32_t temp = (val.c[2] << 24 | val.c[1] << 16 | val.c[0] << 8) >> 8;
45 * Converts an int32_t to a uint8x3_t
47 static inline uint8x3_t int32_to_uint8x3(int32_t in) {
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.
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.
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.
74 * Macro has a return statement.
76 #define EXPAND_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
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; \
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)) { \
86 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
89 for (; dst_offset < (out_buff_chans); dst_offset++) { \
90 *dst_ptr-- = *src_ptr--; \
93 /* return number of *bytes* generated */ \
94 return num_out_samples * sizeof(*(out_buff)); \
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.
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.
106 * Macro has a return statement.
108 #define EXPAND_SELECTED_CHANNELS( \
109 in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
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; \
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--; \
123 /* return number of *bytes* generated */ \
124 return num_out_samples * sizeof(*(out_buff)); \
127 /* Expand number of channels from an input buffer to an output buffer.
128 * See expand_channels_non_destructive() function below for parameter definitions.
130 * Input channels are copied to the output buffer, with extra output
131 * channels interleaved from back of input buffer.
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...]
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.
138 * Uses a temporary buffer so that the conversion can be done in-place
139 * i.e. in_buff == out_buff
141 * Macro has a return statement.
143 #define EXPAND_CHANNELS_NON_DESTRUCTIVE(in_buff, in_buff_chans, \
144 out_buff, out_buff_chans, num_in_bytes) \
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; \
157 temp_ptr = (typeof(out_buff)) src_ptr; \
158 src_ptr += num_in_samples; \
160 /* interleave channels from end of source buffer with those from front */ \
162 for (src_index = 0; src_index < num_out_samples; src_index += (out_buff_chans)) { \
164 for (dst_offset = 0; dst_offset < (in_buff_chans); dst_offset++) { \
165 *dst_ptr++ = *temp_ptr++; \
167 for (;dst_offset < (out_buff_chans); dst_offset++) { \
168 *dst_ptr++ = *src_ptr++; \
171 /* return number of *bytes* generated */ \
172 return num_out_samples * sizeof(*(out_buff)); \
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.
179 * in_buff_chans MUST be 1 and out_buff_chans MUST be >= 2
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.
185 * Macro has a return statement.
187 #define EXPAND_MONO_TO_MULTI(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
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; \
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)) { \
197 for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
200 for (; dst_offset < (out_buff_chans); dst_offset++) { \
201 *dst_ptr-- = *src_ptr; \
205 /* return number of *bytes* generated */ \
206 return num_out_samples * sizeof(*(out_buff)); \
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.
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.
216 * Macro has a return statement.
218 #define CONTRACT_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
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; \
226 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
228 for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
229 *dst_ptr++ = *src_ptr++; \
231 src_ptr += num_skip_samples; \
233 /* return number of *bytes* generated */ \
234 return num_out_samples * sizeof(*(out_buff)); \
237 /* Contract number of channels from an input buffer to an output buffer,
238 * storing removed channels at end of buffer.
240 * See contract_channels_non_destructive() function below for parameter definitions.
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]
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.
247 * Uses a temporary buffer so that the conversion can be done in-place
248 * i.e. in_buff == out_buff
250 * Macro has a return statement.
252 #define CONTRACT_CHANNELS_NON_DESTRUCTIVE(in_buff, in_buff_chans, out_buff, \
253 out_buff_chans, num_in_bytes) \
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; \
266 temp_ptr = dst_ptr + num_out_samples; \
269 for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
271 for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
272 *dst_ptr++ = *src_ptr++; \
274 for (;dst_offset < (in_buff_chans); dst_offset++) { \
275 *temp_ptr++ = *src_ptr++; \
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))); \
283 /* return number of *bytes* generated */ \
284 return num_out_samples * sizeof(*(out_buff)); \
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.
291 * in_buff_chans MUST be >= 2 and out_buff_chans MUST be 1
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.
299 * Macro has a return statement.
301 #define CONTRACT_TO_MONO(in_buff, out_buff, num_in_bytes) \
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; \
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; \
320 /* return number of *bytes* generated */ \
321 return num_out_samples * sizeof(*(out_buff)); \
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.
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.
334 * Macro has a return statement.
336 #define CONTRACT_TO_MONO_24(in_buff, out_buff, num_in_bytes) \
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; \
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; \
351 /* return number of *bytes* generated */ \
352 return num_out_samples * sizeof(*(out_buff)); \
356 * Convert a buffer of N-channel, interleaved samples to M-channel
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
365 * the number of BYTES of output data.
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.
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)
375 switch (sample_size_in_bytes) {
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);
382 CONTRACT_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
383 (uint8_t*)out_buff, out_buff_chans,
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);
393 CONTRACT_CHANNELS((const int16_t*)in_buff, in_buff_chans,
394 (int16_t*)out_buff, out_buff_chans,
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);
405 CONTRACT_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
406 (uint8x3_t*)out_buff, out_buff_chans,
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);
416 CONTRACT_CHANNELS((const int32_t*)in_buff, in_buff_chans,
417 (int32_t*)out_buff, out_buff_chans,
427 * Convert a buffer of N-channel, interleaved samples to M-channel
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
436 * the number of BYTES of output data.
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.
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)
447 switch (sample_size_in_bytes) {
449 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const uint8_t*)in_buff, in_buff_chans,
450 (uint8_t*)out_buff, out_buff_chans,
454 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const int16_t*)in_buff, in_buff_chans,
455 (int16_t*)out_buff, out_buff_chans,
459 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const uint8x3_t*)in_buff, in_buff_chans,
460 (uint8x3_t*)out_buff, out_buff_chans,
464 CONTRACT_CHANNELS_NON_DESTRUCTIVE((const int32_t*)in_buff, in_buff_chans,
465 (int32_t*)out_buff, out_buff_chans,
474 * Convert a buffer of N-channel, interleaved samples to M-channel
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
483 * the number of BYTES of output data.
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.
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)
493 static const uint8x3_t packed24_zero; /* zero 24 bit sample */
495 switch (sample_size_in_bytes) {
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,
504 EXPAND_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
505 (uint8_t*)out_buff, out_buff_chans,
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,
517 EXPAND_CHANNELS((const int16_t*)in_buff, in_buff_chans,
518 (int16_t*)out_buff, out_buff_chans,
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);
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);
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,
543 EXPAND_CHANNELS((const int32_t*)in_buff, in_buff_chans,
544 (int32_t*)out_buff, out_buff_chans,
554 * Convert a buffer of N-channel, interleaved samples to M-channel
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
563 * the number of BYTES of output data.
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.
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)
573 switch (sample_size_in_bytes) {
576 EXPAND_SELECTED_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
577 (uint8_t*)out_buff, out_buff_chans,
583 EXPAND_SELECTED_CHANNELS((const int16_t*)in_buff, in_buff_chans,
584 (int16_t*)out_buff, out_buff_chans,
590 EXPAND_SELECTED_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
591 (uint8x3_t*)out_buff, out_buff_chans,
597 EXPAND_SELECTED_CHANNELS((const int32_t*)in_buff, in_buff_chans,
598 (int32_t*)out_buff, out_buff_chans,
608 * Convert a buffer of N-channel, interleaved samples to M-channel
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
617 * the number of BYTES of output data.
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.
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)
628 switch (sample_size_in_bytes) {
631 EXPAND_CHANNELS_NON_DESTRUCTIVE((const uint8_t*)in_buff, in_buff_chans,
632 (uint8_t*)out_buff, out_buff_chans,
638 EXPAND_CHANNELS_NON_DESTRUCTIVE((const int16_t*)in_buff, in_buff_chans,
639 (int16_t*)out_buff, out_buff_chans,
645 EXPAND_CHANNELS_NON_DESTRUCTIVE((const uint8x3_t*)in_buff, in_buff_chans,
646 (uint8x3_t*)out_buff, out_buff_chans,
652 EXPAND_CHANNELS_NON_DESTRUCTIVE((const int32_t*)in_buff, in_buff_chans,
653 (int32_t*)out_buff, out_buff_chans,
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)
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);
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)
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);
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)
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);