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 */
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 */
35inline int32_t uint8x3_to_int32(uint8x3_t val) {
36#ifdef 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 */
47inline uint8x3_t int32_to_uint8x3(int32_t in) {
48    uint8x3_t out;
49#ifdef 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/* 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.
67 */
68#define EXPAND_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
69{ \
70    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; \
73    size_t src_index; \
74    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) { \
77        size_t dst_offset; \
78        for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
79            *dst_ptr-- = zero; \
80        } \
81        for (; dst_offset < out_buff_chans; dst_offset++) { \
82            *dst_ptr-- = *src_ptr--; \
83        } \
84    } \
85    /* return number of *bytes* generated */ \
86    return num_out_samples * sizeof(*out_buff); \
87}
88
89/* Channel expands from a MONO input buffer to a MULTICHANNEL output buffer by duplicating the
90 * single input channel to the first 2 output channels and 0-filling the remaining.
91 * See expand_channels() function below for parameter definitions.
92 *
93 * in_buff_chans MUST be 1 and out_buff_chans MUST be >= 2
94 *
95 * Move from back to front so that the conversion can be done in-place
96 * i.e. in_buff == out_buff
97 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
98 */
99#define EXPAND_MONO_TO_MULTI(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
100{ \
101    size_t num_in_samples = num_in_bytes / sizeof(*in_buff); \
102    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
103    typeof(out_buff) dst_ptr = out_buff + num_out_samples - 1; \
104    size_t src_index; \
105    typeof(in_buff) src_ptr = in_buff + num_in_samples - 1; \
106    size_t num_zero_chans = out_buff_chans - in_buff_chans - 1; \
107    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
108        size_t dst_offset; \
109        for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
110            *dst_ptr-- = zero; \
111        } \
112        for (; dst_offset < out_buff_chans; dst_offset++) { \
113            *dst_ptr-- = *src_ptr; \
114        } \
115        src_ptr--; \
116    } \
117    /* return number of *bytes* generated */ \
118    return num_out_samples * sizeof(*out_buff); \
119}
120
121/* Channel contracts (removes from audio frame end) from an input buffer to an output buffer.
122 * See contract_channels() function below for parameter definitions.
123 *
124 * Move from front to back so that the conversion can be done in-place
125 * i.e. in_buff == out_buff
126 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
127 */
128#define CONTRACT_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
129{ \
130    size_t num_in_samples = num_in_bytes / sizeof(*in_buff); \
131    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
132    size_t num_skip_samples = in_buff_chans - out_buff_chans; \
133    typeof(out_buff) dst_ptr = out_buff; \
134    typeof(in_buff) src_ptr = in_buff; \
135    size_t src_index; \
136    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
137        size_t dst_offset; \
138        for (dst_offset = 0; dst_offset < out_buff_chans; dst_offset++) { \
139            *dst_ptr++ = *src_ptr++; \
140        } \
141        src_ptr += num_skip_samples; \
142    } \
143    /* return number of *bytes* generated */ \
144    return num_out_samples * sizeof(*out_buff); \
145}
146
147/* Channel contracts from a MULTICHANNEL input buffer to a MONO output buffer by mixing the
148 * first two input channels into the single output channel (and skipping the rest).
149 * See contract_channels() function below for parameter definitions.
150 *
151 * in_buff_chans MUST be >= 2 and out_buff_chans MUST be 1
152 *
153 * Move from front to back so that the conversion can be done in-place
154 * i.e. in_buff == out_buff
155 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
156 * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
157 * NOTE: Can not be used for uint8x3_t samples, see CONTRACT_TO_MONO_24() below.
158 */
159#define CONTRACT_TO_MONO(in_buff, out_buff, num_in_bytes) \
160{ \
161    size_t num_in_samples = num_in_bytes / sizeof(*in_buff); \
162    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
163    size_t num_skip_samples = in_buff_chans - 2; \
164    typeof(out_buff) dst_ptr = out_buff; \
165    typeof(in_buff) src_ptr = in_buff; \
166    int32_t temp0, temp1; \
167    size_t src_index; \
168    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
169        temp0 = *src_ptr++; \
170        temp1 = *src_ptr++; \
171        /* *dst_ptr++ = temp >> 1; */ \
172        /* This bit of magic adds and normalizes without overflow (or so claims hunga@) */ \
173        /* Bitwise half adder trick, see http://en.wikipedia.org/wiki/Adder_(electronics) */ \
174        /* Hacker's delight, p. 19 http://www.hackersdelight.org/basics2.pdf */ \
175        *dst_ptr++ = (temp0 & temp1) + ((temp0 ^ temp1) >> 1); \
176        src_ptr += num_skip_samples; \
177    } \
178    /* return number of *bytes* generated */ \
179    return num_out_samples * sizeof(*out_buff); \
180}
181
182/* Channel contracts from a MULTICHANNEL uint8x3_t input buffer to a MONO uint8x3_t output buffer
183 * by mixing the first two input channels into the single output channel (and skipping the rest).
184 * See contract_channels() function below for parameter definitions.
185 *
186 * Move from front to back so that the conversion can be done in-place
187 * i.e. in_buff == out_buff
188 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
189 * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
190 * NOTE: Can not be used for normal, scalar samples, see CONTRACT_TO_MONO() above.
191 */
192#define CONTRACT_TO_MONO_24(in_buff, out_buff, num_in_bytes) \
193{ \
194    size_t num_in_samples = num_in_bytes / sizeof(*in_buff); \
195    size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
196    size_t num_skip_samples = in_buff_chans - 2; \
197    typeof(out_buff) dst_ptr = out_buff; \
198    typeof(in_buff) src_ptr = in_buff; \
199    int32_t temp; \
200    size_t src_index; \
201    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
202        temp = uint8x3_to_int32(*src_ptr++); \
203        temp += uint8x3_to_int32(*src_ptr++); \
204        *dst_ptr = int32_to_uint8x3(temp >> 1); \
205        src_ptr += num_skip_samples; \
206    } \
207    /* return number of *bytes* generated */ \
208    return num_out_samples * sizeof(*out_buff); \
209}
210
211/*
212 * Convert a buffer of N-channel, interleaved samples to M-channel
213 * (where N > M).
214 *   in_buff points to the buffer of samples
215 *   in_buff_channels Specifies the number of channels in the input buffer.
216 *   out_buff points to the buffer to receive converted samples.
217 *   out_buff_channels Specifies the number of channels in the output buffer.
218 *   sample_size_in_bytes Specifies the number of bytes per sample.
219 *   num_in_bytes size of input buffer in BYTES
220 * returns
221 *   the number of BYTES of output data.
222 * NOTE
223 *   channels > M are thrown away.
224 *   The out and sums buffers must either be completely separate (non-overlapping), or
225 *   they must both start at the same address. Partially overlapping buffers are not supported.
226 */
227static size_t contract_channels(const void* in_buff, size_t in_buff_chans,
228                                void* out_buff, size_t out_buff_chans,
229                                unsigned sample_size_in_bytes, size_t num_in_bytes)
230{
231    switch (sample_size_in_bytes) {
232    case 1:
233        if (out_buff_chans == 1) {
234            /* Special case Multi to Mono */
235            CONTRACT_TO_MONO((const uint8_t*)in_buff, (uint8_t*)out_buff, num_in_bytes);
236            // returns in macro
237        } else {
238            CONTRACT_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
239                              (uint8_t*)out_buff, out_buff_chans,
240                              num_in_bytes);
241            // returns in macro
242        }
243    case 2:
244        if (out_buff_chans == 1) {
245            /* Special case Multi to Mono */
246            CONTRACT_TO_MONO((const int16_t*)in_buff, (int16_t*)out_buff, num_in_bytes);
247            // returns in macro
248        } else {
249            CONTRACT_CHANNELS((const int16_t*)in_buff, in_buff_chans,
250                              (int16_t*)out_buff, out_buff_chans,
251                              num_in_bytes);
252            // returns in macro
253        }
254    case 3:
255        if (out_buff_chans == 1) {
256            /* Special case Multi to Mono */
257            CONTRACT_TO_MONO_24((const uint8x3_t*)in_buff,
258                                       (uint8x3_t*)out_buff, num_in_bytes);
259            // returns in macro
260        } else {
261            CONTRACT_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
262                              (uint8x3_t*)out_buff, out_buff_chans,
263                              num_in_bytes);
264            // returns in macro
265        }
266    case 4:
267        if (out_buff_chans == 1) {
268            /* Special case Multi to Mono */
269            CONTRACT_TO_MONO((const int32_t*)in_buff, (int32_t*)out_buff, num_in_bytes);
270            // returns in macro
271        } else {
272            CONTRACT_CHANNELS((const int32_t*)in_buff, in_buff_chans,
273                              (int32_t*)out_buff, out_buff_chans,
274                              num_in_bytes);
275            // returns in macro
276        }
277    default:
278        return 0;
279    }
280}
281
282/*
283 * Convert a buffer of N-channel, interleaved samples to M-channel
284 * (where N < M).
285 *   in_buff points to the buffer of samples
286 *   in_buff_channels Specifies the number of channels in the input buffer.
287 *   out_buff points to the buffer to receive converted samples.
288 *   out_buff_channels Specifies the number of channels in the output buffer.
289 *   sample_size_in_bytes Specifies the number of bytes per sample.
290 *   num_in_bytes size of input buffer in BYTES
291 * returns
292 *   the number of BYTES of output data.
293 * NOTE
294 *   channels > N are filled with silence.
295 *   The out and sums buffers must either be completely separate (non-overlapping), or
296 *   they must both start at the same address. Partially overlapping buffers are not supported.
297 */
298static size_t expand_channels(const void* in_buff, size_t in_buff_chans,
299                              void* out_buff, size_t out_buff_chans,
300                              unsigned sample_size_in_bytes, size_t num_in_bytes)
301{
302    static const uint8x3_t packed24_zero; /* zero 24 bit sample */
303
304    switch (sample_size_in_bytes) {
305    case 1:
306        if (in_buff_chans == 1) {
307            /* special case of mono source to multi-channel */
308            EXPAND_MONO_TO_MULTI((const uint8_t*)in_buff, in_buff_chans,
309                            (uint8_t*)out_buff, out_buff_chans,
310                            num_in_bytes, 0);
311            // returns in macro
312        } else {
313            EXPAND_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
314                            (uint8_t*)out_buff, out_buff_chans,
315                            num_in_bytes, 0);
316            // returns in macro
317        }
318    case 2:
319        if (in_buff_chans == 1) {
320            /* special case of mono source to multi-channel */
321            EXPAND_MONO_TO_MULTI((const int16_t*)in_buff, in_buff_chans,
322                            (int16_t*)out_buff, out_buff_chans,
323                            num_in_bytes, 0);
324            // returns in macro
325        } else {
326            EXPAND_CHANNELS((const int16_t*)in_buff, in_buff_chans,
327                            (int16_t*)out_buff, out_buff_chans,
328                            num_in_bytes, 0);
329            // returns in macro
330        }
331    case 3:
332        if (in_buff_chans == 1) {
333            /* special case of mono source to multi-channel */
334            EXPAND_MONO_TO_MULTI((const uint8x3_t*)in_buff, in_buff_chans,
335                            (uint8x3_t*)out_buff, out_buff_chans,
336                            num_in_bytes, packed24_zero);
337            // returns in macro
338        } else {
339            EXPAND_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
340                            (uint8x3_t*)out_buff, out_buff_chans,
341                            num_in_bytes, packed24_zero);
342            // returns in macro
343        }
344    case 4:
345        if (in_buff_chans == 1) {
346            /* special case of mono source to multi-channel */
347            EXPAND_MONO_TO_MULTI((const int32_t*)in_buff, in_buff_chans,
348                            (int32_t*)out_buff, out_buff_chans,
349                            num_in_bytes, 0);
350            // returns in macro
351        } else {
352           EXPAND_CHANNELS((const int32_t*)in_buff, in_buff_chans,
353                            (int32_t*)out_buff, out_buff_chans,
354                            num_in_bytes, 0);
355            // returns in macro
356        }
357    default:
358        return 0;
359    }
360}
361
362size_t adjust_channels(const void* in_buff, size_t in_buff_chans,
363                       void* out_buff, size_t out_buff_chans,
364                       unsigned sample_size_in_bytes, size_t num_in_bytes)
365{
366    if (out_buff_chans > in_buff_chans) {
367        return expand_channels(in_buff, in_buff_chans, out_buff,  out_buff_chans,
368                               sample_size_in_bytes, num_in_bytes);
369    } else if (out_buff_chans < in_buff_chans) {
370        return contract_channels(in_buff, in_buff_chans, out_buff,  out_buff_chans,
371                                 sample_size_in_bytes, num_in_bytes);
372    } else if (in_buff != out_buff) {
373        memcpy(out_buff, in_buff, num_in_bytes);
374    }
375
376    return num_in_bytes;
377}
378