1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker *
4*b9df5ad1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker *
8*b9df5ad1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker *
10*b9df5ad1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker */
16*b9df5ad1SAndroid Build Coastguard Worker
17*b9df5ad1SAndroid Build Coastguard Worker #include <string.h>
18*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/channels.h>
19*b9df5ad1SAndroid Build Coastguard Worker #include "private/private.h"
20*b9df5ad1SAndroid Build Coastguard Worker
21*b9df5ad1SAndroid Build Coastguard Worker /*
22*b9df5ad1SAndroid Build Coastguard Worker * Clamps a 24-bit value from a 32-bit sample
23*b9df5ad1SAndroid Build Coastguard Worker */
clamp24(int32_t sample)24*b9df5ad1SAndroid Build Coastguard Worker static inline int32_t clamp24(int32_t sample)
25*b9df5ad1SAndroid Build Coastguard Worker {
26*b9df5ad1SAndroid Build Coastguard Worker if ((sample>>23) ^ (sample>>31)) {
27*b9df5ad1SAndroid Build Coastguard Worker sample = 0x007FFFFF ^ (sample>>31);
28*b9df5ad1SAndroid Build Coastguard Worker }
29*b9df5ad1SAndroid Build Coastguard Worker return sample;
30*b9df5ad1SAndroid Build Coastguard Worker }
31*b9df5ad1SAndroid Build Coastguard Worker
32*b9df5ad1SAndroid Build Coastguard Worker /*
33*b9df5ad1SAndroid Build Coastguard Worker * Converts a uint8x3_t into an int32_t
34*b9df5ad1SAndroid Build Coastguard Worker */
uint8x3_to_int32(uint8x3_t val)35*b9df5ad1SAndroid Build Coastguard Worker static inline int32_t uint8x3_to_int32(uint8x3_t val) {
36*b9df5ad1SAndroid Build Coastguard Worker #if HAVE_BIG_ENDIAN
37*b9df5ad1SAndroid Build Coastguard Worker int32_t temp = (val.c[0] << 24 | val.c[1] << 16 | val.c[2] << 8) >> 8;
38*b9df5ad1SAndroid Build Coastguard Worker #else
39*b9df5ad1SAndroid Build Coastguard Worker int32_t temp = (val.c[2] << 24 | val.c[1] << 16 | val.c[0] << 8) >> 8;
40*b9df5ad1SAndroid Build Coastguard Worker #endif
41*b9df5ad1SAndroid Build Coastguard Worker return clamp24(temp);
42*b9df5ad1SAndroid Build Coastguard Worker }
43*b9df5ad1SAndroid Build Coastguard Worker
44*b9df5ad1SAndroid Build Coastguard Worker /*
45*b9df5ad1SAndroid Build Coastguard Worker * Converts an int32_t to a uint8x3_t
46*b9df5ad1SAndroid Build Coastguard Worker */
int32_to_uint8x3(int32_t in)47*b9df5ad1SAndroid Build Coastguard Worker static inline uint8x3_t int32_to_uint8x3(int32_t in) {
48*b9df5ad1SAndroid Build Coastguard Worker uint8x3_t out;
49*b9df5ad1SAndroid Build Coastguard Worker #if HAVE_BIG_ENDIAN
50*b9df5ad1SAndroid Build Coastguard Worker out.c[2] = in;
51*b9df5ad1SAndroid Build Coastguard Worker out.c[1] = in >> 8;
52*b9df5ad1SAndroid Build Coastguard Worker out.c[0] = in >> 16;
53*b9df5ad1SAndroid Build Coastguard Worker #else
54*b9df5ad1SAndroid Build Coastguard Worker out.c[0] = in;
55*b9df5ad1SAndroid Build Coastguard Worker out.c[1] = in >> 8;
56*b9df5ad1SAndroid Build Coastguard Worker out.c[2] = in >> 16;
57*b9df5ad1SAndroid Build Coastguard Worker #endif
58*b9df5ad1SAndroid Build Coastguard Worker return out;
59*b9df5ad1SAndroid Build Coastguard Worker }
60*b9df5ad1SAndroid Build Coastguard Worker
61*b9df5ad1SAndroid Build Coastguard Worker /* This is written as a C macro because it operates on generic types,
62*b9df5ad1SAndroid Build Coastguard Worker * which in a C++ file could be alternatively achieved by a "template"
63*b9df5ad1SAndroid Build Coastguard Worker * or an "auto" declaration.
64*b9df5ad1SAndroid Build Coastguard Worker * TODO: convert this from a C file to a C++ file.
65*b9df5ad1SAndroid Build Coastguard Worker */
66*b9df5ad1SAndroid Build Coastguard Worker
67*b9df5ad1SAndroid Build Coastguard Worker /* Channel expands (adds zeroes to audio frame end) from an input buffer to an output buffer.
68*b9df5ad1SAndroid Build Coastguard Worker * See expand_channels() function below for parameter definitions.
69*b9df5ad1SAndroid Build Coastguard Worker *
70*b9df5ad1SAndroid Build Coastguard Worker * Move from back to front so that the conversion can be done in-place
71*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
72*b9df5ad1SAndroid Build Coastguard Worker * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
73*b9df5ad1SAndroid Build Coastguard Worker *
74*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
75*b9df5ad1SAndroid Build Coastguard Worker */
76*b9df5ad1SAndroid Build Coastguard Worker #define EXPAND_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
77*b9df5ad1SAndroid Build Coastguard Worker { \
78*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
79*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
80*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
81*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
82*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
83*b9df5ad1SAndroid Build Coastguard Worker size_t num_zero_chans = (out_buff_chans) - (in_buff_chans); \
84*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
85*b9df5ad1SAndroid Build Coastguard Worker size_t dst_offset; \
86*b9df5ad1SAndroid Build Coastguard Worker for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
87*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr-- = zero; \
88*b9df5ad1SAndroid Build Coastguard Worker } \
89*b9df5ad1SAndroid Build Coastguard Worker for (; dst_offset < (out_buff_chans); dst_offset++) { \
90*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr-- = *src_ptr--; \
91*b9df5ad1SAndroid Build Coastguard Worker } \
92*b9df5ad1SAndroid Build Coastguard Worker } \
93*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
94*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
95*b9df5ad1SAndroid Build Coastguard Worker }
96*b9df5ad1SAndroid Build Coastguard Worker
97*b9df5ad1SAndroid Build Coastguard Worker /* Channel expands from an input buffer to an output buffer.
98*b9df5ad1SAndroid Build Coastguard Worker * See expand_selected_channels() function below for parameter definitions.
99*b9df5ad1SAndroid Build Coastguard Worker * Selected channels are replaced in the output buffer, with any extra channels
100*b9df5ad1SAndroid Build Coastguard Worker * per frame left alone.
101*b9df5ad1SAndroid Build Coastguard Worker *
102*b9df5ad1SAndroid Build Coastguard Worker * Move from back to front so that the conversion can be done in-place
103*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
104*b9df5ad1SAndroid Build Coastguard Worker * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
105*b9df5ad1SAndroid Build Coastguard Worker *
106*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
107*b9df5ad1SAndroid Build Coastguard Worker */
108*b9df5ad1SAndroid Build Coastguard Worker #define EXPAND_SELECTED_CHANNELS( \
109*b9df5ad1SAndroid Build Coastguard Worker in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
110*b9df5ad1SAndroid Build Coastguard Worker { \
111*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
112*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
113*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
114*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
115*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
116*b9df5ad1SAndroid Build Coastguard Worker size_t num_extra_chans = (out_buff_chans) - (in_buff_chans); \
117*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
118*b9df5ad1SAndroid Build Coastguard Worker dst_ptr -= num_extra_chans; \
119*b9df5ad1SAndroid Build Coastguard Worker for (size_t dst_offset = num_extra_chans; dst_offset < (out_buff_chans); dst_offset++) { \
120*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr-- = *src_ptr--; \
121*b9df5ad1SAndroid Build Coastguard Worker } \
122*b9df5ad1SAndroid Build Coastguard Worker } \
123*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
124*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
125*b9df5ad1SAndroid Build Coastguard Worker }
126*b9df5ad1SAndroid Build Coastguard Worker
127*b9df5ad1SAndroid Build Coastguard Worker /* Expand number of channels from an input buffer to an output buffer.
128*b9df5ad1SAndroid Build Coastguard Worker * See expand_channels_non_destructive() function below for parameter definitions.
129*b9df5ad1SAndroid Build Coastguard Worker *
130*b9df5ad1SAndroid Build Coastguard Worker * Input channels are copied to the output buffer, with extra output
131*b9df5ad1SAndroid Build Coastguard Worker * channels interleaved from back of input buffer.
132*b9df5ad1SAndroid Build Coastguard Worker *
133*b9df5ad1SAndroid Build Coastguard Worker * 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*b9df5ad1SAndroid Build Coastguard Worker *
135*b9df5ad1SAndroid Build Coastguard Worker * NOTE: in_buff must be same size as out_buff and num_in_bytes must
136*b9df5ad1SAndroid Build Coastguard Worker * be a multiple of in_buff_channels * in_buff_sample_size.
137*b9df5ad1SAndroid Build Coastguard Worker *
138*b9df5ad1SAndroid Build Coastguard Worker * Uses a temporary buffer so that the conversion can be done in-place
139*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
140*b9df5ad1SAndroid Build Coastguard Worker *
141*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
142*b9df5ad1SAndroid Build Coastguard Worker */
143*b9df5ad1SAndroid Build Coastguard Worker #define EXPAND_CHANNELS_NON_DESTRUCTIVE(in_buff, in_buff_chans, \
144*b9df5ad1SAndroid Build Coastguard Worker out_buff, out_buff_chans, num_in_bytes) \
145*b9df5ad1SAndroid Build Coastguard Worker { \
146*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
147*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
148*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = (out_buff); \
149*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = (in_buff); \
150*b9df5ad1SAndroid Build Coastguard Worker typeof(*out_buff) temp_buff[num_in_samples]; \
151*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) temp_ptr = temp_buff; \
152*b9df5ad1SAndroid Build Coastguard Worker /* if in-place, copy input channels to a temp buffer */ \
153*b9df5ad1SAndroid Build Coastguard Worker if ((in_buff) == (out_buff)) { \
154*b9df5ad1SAndroid Build Coastguard Worker memcpy(temp_buff, src_ptr, (num_in_bytes)); \
155*b9df5ad1SAndroid Build Coastguard Worker src_ptr += num_in_samples; \
156*b9df5ad1SAndroid Build Coastguard Worker } else { \
157*b9df5ad1SAndroid Build Coastguard Worker temp_ptr = (typeof(out_buff)) src_ptr; \
158*b9df5ad1SAndroid Build Coastguard Worker src_ptr += num_in_samples; \
159*b9df5ad1SAndroid Build Coastguard Worker } \
160*b9df5ad1SAndroid Build Coastguard Worker /* interleave channels from end of source buffer with those from front */ \
161*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
162*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_out_samples; src_index += (out_buff_chans)) { \
163*b9df5ad1SAndroid Build Coastguard Worker size_t dst_offset; \
164*b9df5ad1SAndroid Build Coastguard Worker for (dst_offset = 0; dst_offset < (in_buff_chans); dst_offset++) { \
165*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr++ = *temp_ptr++; \
166*b9df5ad1SAndroid Build Coastguard Worker } \
167*b9df5ad1SAndroid Build Coastguard Worker for (;dst_offset < (out_buff_chans); dst_offset++) { \
168*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr++ = *src_ptr++; \
169*b9df5ad1SAndroid Build Coastguard Worker } \
170*b9df5ad1SAndroid Build Coastguard Worker } \
171*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
172*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
173*b9df5ad1SAndroid Build Coastguard Worker }
174*b9df5ad1SAndroid Build Coastguard Worker
175*b9df5ad1SAndroid Build Coastguard Worker /* Channel expands from a MONO input buffer to a MULTICHANNEL output buffer by duplicating the
176*b9df5ad1SAndroid Build Coastguard Worker * single input channel to the first 2 output channels and 0-filling the remaining.
177*b9df5ad1SAndroid Build Coastguard Worker * See expand_channels() function below for parameter definitions.
178*b9df5ad1SAndroid Build Coastguard Worker *
179*b9df5ad1SAndroid Build Coastguard Worker * in_buff_chans MUST be 1 and out_buff_chans MUST be >= 2
180*b9df5ad1SAndroid Build Coastguard Worker *
181*b9df5ad1SAndroid Build Coastguard Worker * Move from back to front so that the conversion can be done in-place
182*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
183*b9df5ad1SAndroid Build Coastguard Worker * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
184*b9df5ad1SAndroid Build Coastguard Worker *
185*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
186*b9df5ad1SAndroid Build Coastguard Worker */
187*b9df5ad1SAndroid Build Coastguard Worker #define EXPAND_MONO_TO_MULTI(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
188*b9df5ad1SAndroid Build Coastguard Worker { \
189*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
190*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
191*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
192*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
193*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
194*b9df5ad1SAndroid Build Coastguard Worker size_t num_zero_chans = (out_buff_chans) - (in_buff_chans) - 1; \
195*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
196*b9df5ad1SAndroid Build Coastguard Worker size_t dst_offset; \
197*b9df5ad1SAndroid Build Coastguard Worker for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
198*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr-- = zero; \
199*b9df5ad1SAndroid Build Coastguard Worker } \
200*b9df5ad1SAndroid Build Coastguard Worker for (; dst_offset < (out_buff_chans); dst_offset++) { \
201*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr-- = *src_ptr; \
202*b9df5ad1SAndroid Build Coastguard Worker } \
203*b9df5ad1SAndroid Build Coastguard Worker src_ptr--; \
204*b9df5ad1SAndroid Build Coastguard Worker } \
205*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
206*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
207*b9df5ad1SAndroid Build Coastguard Worker }
208*b9df5ad1SAndroid Build Coastguard Worker
209*b9df5ad1SAndroid Build Coastguard Worker /* Channel contracts (removes from audio frame end) from an input buffer to an output buffer.
210*b9df5ad1SAndroid Build Coastguard Worker * See contract_channels() function below for parameter definitions.
211*b9df5ad1SAndroid Build Coastguard Worker *
212*b9df5ad1SAndroid Build Coastguard Worker * Move from front to back so that the conversion can be done in-place
213*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
214*b9df5ad1SAndroid Build Coastguard Worker * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
215*b9df5ad1SAndroid Build Coastguard Worker *
216*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
217*b9df5ad1SAndroid Build Coastguard Worker */
218*b9df5ad1SAndroid Build Coastguard Worker #define CONTRACT_CHANNELS(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes) \
219*b9df5ad1SAndroid Build Coastguard Worker { \
220*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
221*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
222*b9df5ad1SAndroid Build Coastguard Worker size_t num_skip_samples = (in_buff_chans) - (out_buff_chans); \
223*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = out_buff; \
224*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = in_buff; \
225*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
226*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
227*b9df5ad1SAndroid Build Coastguard Worker size_t dst_offset; \
228*b9df5ad1SAndroid Build Coastguard Worker for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
229*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr++ = *src_ptr++; \
230*b9df5ad1SAndroid Build Coastguard Worker } \
231*b9df5ad1SAndroid Build Coastguard Worker src_ptr += num_skip_samples; \
232*b9df5ad1SAndroid Build Coastguard Worker } \
233*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
234*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
235*b9df5ad1SAndroid Build Coastguard Worker }
236*b9df5ad1SAndroid Build Coastguard Worker
237*b9df5ad1SAndroid Build Coastguard Worker /* Contract number of channels from an input buffer to an output buffer,
238*b9df5ad1SAndroid Build Coastguard Worker * storing removed channels at end of buffer.
239*b9df5ad1SAndroid Build Coastguard Worker *
240*b9df5ad1SAndroid Build Coastguard Worker * See contract_channels_non_destructive() function below for parameter definitions.
241*b9df5ad1SAndroid Build Coastguard Worker *
242*b9df5ad1SAndroid Build Coastguard Worker * 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*b9df5ad1SAndroid Build Coastguard Worker *
244*b9df5ad1SAndroid Build Coastguard Worker * NOTE: in_buff must be same size as out_buff and num_in_bytes must
245*b9df5ad1SAndroid Build Coastguard Worker * be a multiple of in_buff_channels * in_buff_sample_size.
246*b9df5ad1SAndroid Build Coastguard Worker *
247*b9df5ad1SAndroid Build Coastguard Worker * Uses a temporary buffer so that the conversion can be done in-place
248*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
249*b9df5ad1SAndroid Build Coastguard Worker *
250*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
251*b9df5ad1SAndroid Build Coastguard Worker */
252*b9df5ad1SAndroid Build Coastguard Worker #define CONTRACT_CHANNELS_NON_DESTRUCTIVE(in_buff, in_buff_chans, out_buff, \
253*b9df5ad1SAndroid Build Coastguard Worker out_buff_chans, num_in_bytes) \
254*b9df5ad1SAndroid Build Coastguard Worker { \
255*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
256*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
257*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = (out_buff); \
258*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = (in_buff); \
259*b9df5ad1SAndroid Build Coastguard Worker size_t num_temp_samples = num_in_samples - num_out_samples; \
260*b9df5ad1SAndroid Build Coastguard Worker typeof(*out_buff) temp_buff[num_temp_samples]; \
261*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) temp_ptr; \
262*b9df5ad1SAndroid Build Coastguard Worker /* if in-place, copy input channels to a temp buffer instead of out buffer */ \
263*b9df5ad1SAndroid Build Coastguard Worker if ((in_buff) == (out_buff)) { \
264*b9df5ad1SAndroid Build Coastguard Worker temp_ptr = temp_buff; \
265*b9df5ad1SAndroid Build Coastguard Worker } else { \
266*b9df5ad1SAndroid Build Coastguard Worker temp_ptr = dst_ptr + num_out_samples; \
267*b9df5ad1SAndroid Build Coastguard Worker } \
268*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
269*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
270*b9df5ad1SAndroid Build Coastguard Worker size_t dst_offset; \
271*b9df5ad1SAndroid Build Coastguard Worker for (dst_offset = 0; dst_offset < (out_buff_chans); dst_offset++) { \
272*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr++ = *src_ptr++; \
273*b9df5ad1SAndroid Build Coastguard Worker } \
274*b9df5ad1SAndroid Build Coastguard Worker for (;dst_offset < (in_buff_chans); dst_offset++) { \
275*b9df5ad1SAndroid Build Coastguard Worker *temp_ptr++ = *src_ptr++; \
276*b9df5ad1SAndroid Build Coastguard Worker } \
277*b9df5ad1SAndroid Build Coastguard Worker } \
278*b9df5ad1SAndroid Build Coastguard Worker /* if in-place, interleave channels from the temp buffer */ \
279*b9df5ad1SAndroid Build Coastguard Worker if ((in_buff) == (out_buff)) { \
280*b9df5ad1SAndroid Build Coastguard Worker temp_ptr = temp_buff; \
281*b9df5ad1SAndroid Build Coastguard Worker memcpy(dst_ptr, temp_ptr, num_temp_samples * sizeof(*(in_buff))); \
282*b9df5ad1SAndroid Build Coastguard Worker } \
283*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
284*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
285*b9df5ad1SAndroid Build Coastguard Worker }
286*b9df5ad1SAndroid Build Coastguard Worker
287*b9df5ad1SAndroid Build Coastguard Worker /* Channel contracts from a MULTICHANNEL input buffer to a MONO output buffer by mixing the
288*b9df5ad1SAndroid Build Coastguard Worker * first two input channels into the single output channel (and skipping the rest).
289*b9df5ad1SAndroid Build Coastguard Worker * See contract_channels() function below for parameter definitions.
290*b9df5ad1SAndroid Build Coastguard Worker *
291*b9df5ad1SAndroid Build Coastguard Worker * in_buff_chans MUST be >= 2 and out_buff_chans MUST be 1
292*b9df5ad1SAndroid Build Coastguard Worker *
293*b9df5ad1SAndroid Build Coastguard Worker * Move from front to back so that the conversion can be done in-place
294*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
295*b9df5ad1SAndroid Build Coastguard Worker * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
296*b9df5ad1SAndroid Build Coastguard Worker * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
297*b9df5ad1SAndroid Build Coastguard Worker * NOTE: Can not be used for uint8x3_t samples, see CONTRACT_TO_MONO_24() below.
298*b9df5ad1SAndroid Build Coastguard Worker *
299*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
300*b9df5ad1SAndroid Build Coastguard Worker */
301*b9df5ad1SAndroid Build Coastguard Worker #define CONTRACT_TO_MONO(in_buff, out_buff, num_in_bytes) \
302*b9df5ad1SAndroid Build Coastguard Worker { \
303*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
304*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
305*b9df5ad1SAndroid Build Coastguard Worker size_t num_skip_samples = in_buff_chans - 2; \
306*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = out_buff; \
307*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = in_buff; \
308*b9df5ad1SAndroid Build Coastguard Worker int32_t temp0, temp1; \
309*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
310*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
311*b9df5ad1SAndroid Build Coastguard Worker temp0 = *src_ptr++; \
312*b9df5ad1SAndroid Build Coastguard Worker temp1 = *src_ptr++; \
313*b9df5ad1SAndroid Build Coastguard Worker /* *dst_ptr++ = temp >> 1; */ \
314*b9df5ad1SAndroid Build Coastguard Worker /* This bit of magic adds and normalizes without overflow (or so claims hunga@) */ \
315*b9df5ad1SAndroid Build Coastguard Worker /* Bitwise half adder trick, see http://en.wikipedia.org/wiki/Adder_(electronics) */ \
316*b9df5ad1SAndroid Build Coastguard Worker /* Hacker's delight, p. 19 http://www.hackersdelight.org/basics2.pdf */ \
317*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr++ = (temp0 & temp1) + ((temp0 ^ temp1) >> 1); \
318*b9df5ad1SAndroid Build Coastguard Worker src_ptr += num_skip_samples; \
319*b9df5ad1SAndroid Build Coastguard Worker } \
320*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
321*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
322*b9df5ad1SAndroid Build Coastguard Worker }
323*b9df5ad1SAndroid Build Coastguard Worker
324*b9df5ad1SAndroid Build Coastguard Worker /* Channel contracts from a MULTICHANNEL uint8x3_t input buffer to a MONO uint8x3_t output buffer
325*b9df5ad1SAndroid Build Coastguard Worker * by mixing the first two input channels into the single output channel (and skipping the rest).
326*b9df5ad1SAndroid Build Coastguard Worker * See contract_channels() function below for parameter definitions.
327*b9df5ad1SAndroid Build Coastguard Worker *
328*b9df5ad1SAndroid Build Coastguard Worker * Move from front to back so that the conversion can be done in-place
329*b9df5ad1SAndroid Build Coastguard Worker * i.e. in_buff == out_buff
330*b9df5ad1SAndroid Build Coastguard Worker * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
331*b9df5ad1SAndroid Build Coastguard Worker * NOTE: Overload of the summed channels is avoided by averaging the two input channels.
332*b9df5ad1SAndroid Build Coastguard Worker * NOTE: Can not be used for normal, scalar samples, see CONTRACT_TO_MONO() above.
333*b9df5ad1SAndroid Build Coastguard Worker *
334*b9df5ad1SAndroid Build Coastguard Worker * Macro has a return statement.
335*b9df5ad1SAndroid Build Coastguard Worker */
336*b9df5ad1SAndroid Build Coastguard Worker #define CONTRACT_TO_MONO_24(in_buff, out_buff, num_in_bytes) \
337*b9df5ad1SAndroid Build Coastguard Worker { \
338*b9df5ad1SAndroid Build Coastguard Worker size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
339*b9df5ad1SAndroid Build Coastguard Worker size_t num_out_samples = (num_in_samples * out_buff_chans) / in_buff_chans; \
340*b9df5ad1SAndroid Build Coastguard Worker size_t num_skip_samples = in_buff_chans - 2; \
341*b9df5ad1SAndroid Build Coastguard Worker typeof(out_buff) dst_ptr = out_buff; \
342*b9df5ad1SAndroid Build Coastguard Worker typeof(in_buff) src_ptr = in_buff; \
343*b9df5ad1SAndroid Build Coastguard Worker int32_t temp; \
344*b9df5ad1SAndroid Build Coastguard Worker size_t src_index; \
345*b9df5ad1SAndroid Build Coastguard Worker for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { \
346*b9df5ad1SAndroid Build Coastguard Worker temp = uint8x3_to_int32(*src_ptr++); \
347*b9df5ad1SAndroid Build Coastguard Worker temp += uint8x3_to_int32(*src_ptr++); \
348*b9df5ad1SAndroid Build Coastguard Worker *dst_ptr = int32_to_uint8x3(temp >> 1); \
349*b9df5ad1SAndroid Build Coastguard Worker src_ptr += num_skip_samples; \
350*b9df5ad1SAndroid Build Coastguard Worker } \
351*b9df5ad1SAndroid Build Coastguard Worker /* return number of *bytes* generated */ \
352*b9df5ad1SAndroid Build Coastguard Worker return num_out_samples * sizeof(*(out_buff)); \
353*b9df5ad1SAndroid Build Coastguard Worker }
354*b9df5ad1SAndroid Build Coastguard Worker
355*b9df5ad1SAndroid Build Coastguard Worker /*
356*b9df5ad1SAndroid Build Coastguard Worker * Convert a buffer of N-channel, interleaved samples to M-channel
357*b9df5ad1SAndroid Build Coastguard Worker * (where N > M).
358*b9df5ad1SAndroid Build Coastguard Worker * in_buff points to the buffer of samples
359*b9df5ad1SAndroid Build Coastguard Worker * in_buff_channels Specifies the number of channels in the input buffer.
360*b9df5ad1SAndroid Build Coastguard Worker * out_buff points to the buffer to receive converted samples.
361*b9df5ad1SAndroid Build Coastguard Worker * out_buff_channels Specifies the number of channels in the output buffer.
362*b9df5ad1SAndroid Build Coastguard Worker * sample_size_in_bytes Specifies the number of bytes per sample.
363*b9df5ad1SAndroid Build Coastguard Worker * num_in_bytes size of input buffer in BYTES
364*b9df5ad1SAndroid Build Coastguard Worker * returns
365*b9df5ad1SAndroid Build Coastguard Worker * the number of BYTES of output data.
366*b9df5ad1SAndroid Build Coastguard Worker * NOTE
367*b9df5ad1SAndroid Build Coastguard Worker * channels > M are thrown away.
368*b9df5ad1SAndroid Build Coastguard Worker * The out and sums buffers must either be completely separate (non-overlapping), or
369*b9df5ad1SAndroid Build Coastguard Worker * they must both start at the same address. Partially overlapping buffers are not supported.
370*b9df5ad1SAndroid Build Coastguard Worker */
contract_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)371*b9df5ad1SAndroid Build Coastguard Worker static size_t contract_channels(const void* in_buff, size_t in_buff_chans,
372*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
373*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
374*b9df5ad1SAndroid Build Coastguard Worker {
375*b9df5ad1SAndroid Build Coastguard Worker switch (sample_size_in_bytes) {
376*b9df5ad1SAndroid Build Coastguard Worker case 1:
377*b9df5ad1SAndroid Build Coastguard Worker if (out_buff_chans == 1) {
378*b9df5ad1SAndroid Build Coastguard Worker /* Special case Multi to Mono */
379*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_TO_MONO((const uint8_t*)in_buff, (uint8_t*)out_buff, num_in_bytes);
380*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
381*b9df5ad1SAndroid Build Coastguard Worker } else {
382*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
383*b9df5ad1SAndroid Build Coastguard Worker (uint8_t*)out_buff, out_buff_chans,
384*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
385*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
386*b9df5ad1SAndroid Build Coastguard Worker }
387*b9df5ad1SAndroid Build Coastguard Worker case 2:
388*b9df5ad1SAndroid Build Coastguard Worker if (out_buff_chans == 1) {
389*b9df5ad1SAndroid Build Coastguard Worker /* Special case Multi to Mono */
390*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_TO_MONO((const int16_t*)in_buff, (int16_t*)out_buff, num_in_bytes);
391*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
392*b9df5ad1SAndroid Build Coastguard Worker } else {
393*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS((const int16_t*)in_buff, in_buff_chans,
394*b9df5ad1SAndroid Build Coastguard Worker (int16_t*)out_buff, out_buff_chans,
395*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
396*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
397*b9df5ad1SAndroid Build Coastguard Worker }
398*b9df5ad1SAndroid Build Coastguard Worker case 3:
399*b9df5ad1SAndroid Build Coastguard Worker if (out_buff_chans == 1) {
400*b9df5ad1SAndroid Build Coastguard Worker /* Special case Multi to Mono */
401*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_TO_MONO_24((const uint8x3_t*)in_buff,
402*b9df5ad1SAndroid Build Coastguard Worker (uint8x3_t*)out_buff, num_in_bytes);
403*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
404*b9df5ad1SAndroid Build Coastguard Worker } else {
405*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
406*b9df5ad1SAndroid Build Coastguard Worker (uint8x3_t*)out_buff, out_buff_chans,
407*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
408*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
409*b9df5ad1SAndroid Build Coastguard Worker }
410*b9df5ad1SAndroid Build Coastguard Worker case 4:
411*b9df5ad1SAndroid Build Coastguard Worker if (out_buff_chans == 1) {
412*b9df5ad1SAndroid Build Coastguard Worker /* Special case Multi to Mono */
413*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_TO_MONO((const int32_t*)in_buff, (int32_t*)out_buff, num_in_bytes);
414*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
415*b9df5ad1SAndroid Build Coastguard Worker } else {
416*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS((const int32_t*)in_buff, in_buff_chans,
417*b9df5ad1SAndroid Build Coastguard Worker (int32_t*)out_buff, out_buff_chans,
418*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
419*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
420*b9df5ad1SAndroid Build Coastguard Worker }
421*b9df5ad1SAndroid Build Coastguard Worker default:
422*b9df5ad1SAndroid Build Coastguard Worker return 0;
423*b9df5ad1SAndroid Build Coastguard Worker }
424*b9df5ad1SAndroid Build Coastguard Worker }
425*b9df5ad1SAndroid Build Coastguard Worker
426*b9df5ad1SAndroid Build Coastguard Worker /*
427*b9df5ad1SAndroid Build Coastguard Worker * Convert a buffer of N-channel, interleaved samples to M-channel
428*b9df5ad1SAndroid Build Coastguard Worker * (where N > M).
429*b9df5ad1SAndroid Build Coastguard Worker * in_buff points to the buffer of samples
430*b9df5ad1SAndroid Build Coastguard Worker * in_buff_channels specifies the number of channels in the input buffer.
431*b9df5ad1SAndroid Build Coastguard Worker * out_buff points to the buffer to receive converted samples.
432*b9df5ad1SAndroid Build Coastguard Worker * out_buff_channels specifies the number of channels in the output buffer.
433*b9df5ad1SAndroid Build Coastguard Worker * sample_size_in_bytes specifies the number of bytes per sample.
434*b9df5ad1SAndroid Build Coastguard Worker * num_in_bytes size of input buffer in BYTES
435*b9df5ad1SAndroid Build Coastguard Worker * returns
436*b9df5ad1SAndroid Build Coastguard Worker * the number of BYTES of output data.
437*b9df5ad1SAndroid Build Coastguard Worker * NOTE
438*b9df5ad1SAndroid Build Coastguard Worker * channels > M are stored at the end of the output buffer.
439*b9df5ad1SAndroid Build Coastguard Worker * The output and input buffers must be the same length.
440*b9df5ad1SAndroid Build Coastguard Worker * The output and input buffers must either be completely separate (non-overlapping), or
441*b9df5ad1SAndroid Build Coastguard Worker * they must both start at the same address. Partially overlapping buffers are not supported.
442*b9df5ad1SAndroid Build Coastguard Worker */
contract_channels_non_destructive(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)443*b9df5ad1SAndroid Build Coastguard Worker static size_t contract_channels_non_destructive(const void* in_buff, size_t in_buff_chans,
444*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
445*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
446*b9df5ad1SAndroid Build Coastguard Worker {
447*b9df5ad1SAndroid Build Coastguard Worker switch (sample_size_in_bytes) {
448*b9df5ad1SAndroid Build Coastguard Worker case 1:
449*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS_NON_DESTRUCTIVE((const uint8_t*)in_buff, in_buff_chans,
450*b9df5ad1SAndroid Build Coastguard Worker (uint8_t*)out_buff, out_buff_chans,
451*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
452*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
453*b9df5ad1SAndroid Build Coastguard Worker case 2:
454*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS_NON_DESTRUCTIVE((const int16_t*)in_buff, in_buff_chans,
455*b9df5ad1SAndroid Build Coastguard Worker (int16_t*)out_buff, out_buff_chans,
456*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
457*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
458*b9df5ad1SAndroid Build Coastguard Worker case 3:
459*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS_NON_DESTRUCTIVE((const uint8x3_t*)in_buff, in_buff_chans,
460*b9df5ad1SAndroid Build Coastguard Worker (uint8x3_t*)out_buff, out_buff_chans,
461*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
462*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
463*b9df5ad1SAndroid Build Coastguard Worker case 4:
464*b9df5ad1SAndroid Build Coastguard Worker CONTRACT_CHANNELS_NON_DESTRUCTIVE((const int32_t*)in_buff, in_buff_chans,
465*b9df5ad1SAndroid Build Coastguard Worker (int32_t*)out_buff, out_buff_chans,
466*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
467*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
468*b9df5ad1SAndroid Build Coastguard Worker default:
469*b9df5ad1SAndroid Build Coastguard Worker return 0;
470*b9df5ad1SAndroid Build Coastguard Worker }
471*b9df5ad1SAndroid Build Coastguard Worker }
472*b9df5ad1SAndroid Build Coastguard Worker
473*b9df5ad1SAndroid Build Coastguard Worker /*
474*b9df5ad1SAndroid Build Coastguard Worker * Convert a buffer of N-channel, interleaved samples to M-channel
475*b9df5ad1SAndroid Build Coastguard Worker * (where N < M).
476*b9df5ad1SAndroid Build Coastguard Worker * in_buff points to the buffer of samples
477*b9df5ad1SAndroid Build Coastguard Worker * in_buff_channels Specifies the number of channels in the input buffer.
478*b9df5ad1SAndroid Build Coastguard Worker * out_buff points to the buffer to receive converted samples.
479*b9df5ad1SAndroid Build Coastguard Worker * out_buff_channels Specifies the number of channels in the output buffer.
480*b9df5ad1SAndroid Build Coastguard Worker * sample_size_in_bytes Specifies the number of bytes per sample.
481*b9df5ad1SAndroid Build Coastguard Worker * num_in_bytes size of input buffer in BYTES
482*b9df5ad1SAndroid Build Coastguard Worker * returns
483*b9df5ad1SAndroid Build Coastguard Worker * the number of BYTES of output data.
484*b9df5ad1SAndroid Build Coastguard Worker * NOTE
485*b9df5ad1SAndroid Build Coastguard Worker * channels > N are filled with silence.
486*b9df5ad1SAndroid Build Coastguard Worker * The out and sums buffers must either be completely separate (non-overlapping), or
487*b9df5ad1SAndroid Build Coastguard Worker * they must both start at the same address. Partially overlapping buffers are not supported.
488*b9df5ad1SAndroid Build Coastguard Worker */
expand_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)489*b9df5ad1SAndroid Build Coastguard Worker static size_t expand_channels(const void* in_buff, size_t in_buff_chans,
490*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
491*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
492*b9df5ad1SAndroid Build Coastguard Worker {
493*b9df5ad1SAndroid Build Coastguard Worker static const uint8x3_t packed24_zero{}; /* zero 24 bit sample */
494*b9df5ad1SAndroid Build Coastguard Worker
495*b9df5ad1SAndroid Build Coastguard Worker switch (sample_size_in_bytes) {
496*b9df5ad1SAndroid Build Coastguard Worker case 1:
497*b9df5ad1SAndroid Build Coastguard Worker if (in_buff_chans == 1) {
498*b9df5ad1SAndroid Build Coastguard Worker /* special case of mono source to multi-channel */
499*b9df5ad1SAndroid Build Coastguard Worker EXPAND_MONO_TO_MULTI((const uint8_t*)in_buff, in_buff_chans,
500*b9df5ad1SAndroid Build Coastguard Worker (uint8_t*)out_buff, out_buff_chans,
501*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, 0);
502*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
503*b9df5ad1SAndroid Build Coastguard Worker } else {
504*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
505*b9df5ad1SAndroid Build Coastguard Worker (uint8_t*)out_buff, out_buff_chans,
506*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, 0);
507*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
508*b9df5ad1SAndroid Build Coastguard Worker }
509*b9df5ad1SAndroid Build Coastguard Worker case 2:
510*b9df5ad1SAndroid Build Coastguard Worker if (in_buff_chans == 1) {
511*b9df5ad1SAndroid Build Coastguard Worker /* special case of mono source to multi-channel */
512*b9df5ad1SAndroid Build Coastguard Worker EXPAND_MONO_TO_MULTI((const int16_t*)in_buff, in_buff_chans,
513*b9df5ad1SAndroid Build Coastguard Worker (int16_t*)out_buff, out_buff_chans,
514*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, 0);
515*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
516*b9df5ad1SAndroid Build Coastguard Worker } else {
517*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS((const int16_t*)in_buff, in_buff_chans,
518*b9df5ad1SAndroid Build Coastguard Worker (int16_t*)out_buff, out_buff_chans,
519*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, 0);
520*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
521*b9df5ad1SAndroid Build Coastguard Worker }
522*b9df5ad1SAndroid Build Coastguard Worker case 3:
523*b9df5ad1SAndroid Build Coastguard Worker if (in_buff_chans == 1) {
524*b9df5ad1SAndroid Build Coastguard Worker /* special case of mono source to multi-channel */
525*b9df5ad1SAndroid Build Coastguard Worker EXPAND_MONO_TO_MULTI((const uint8x3_t*)in_buff, in_buff_chans,
526*b9df5ad1SAndroid Build Coastguard Worker (uint8x3_t*)out_buff, out_buff_chans,
527*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, packed24_zero);
528*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
529*b9df5ad1SAndroid Build Coastguard Worker } else {
530*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
531*b9df5ad1SAndroid Build Coastguard Worker (uint8x3_t*)out_buff, out_buff_chans,
532*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, packed24_zero);
533*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
534*b9df5ad1SAndroid Build Coastguard Worker }
535*b9df5ad1SAndroid Build Coastguard Worker case 4:
536*b9df5ad1SAndroid Build Coastguard Worker if (in_buff_chans == 1) {
537*b9df5ad1SAndroid Build Coastguard Worker /* special case of mono source to multi-channel */
538*b9df5ad1SAndroid Build Coastguard Worker EXPAND_MONO_TO_MULTI((const int32_t*)in_buff, in_buff_chans,
539*b9df5ad1SAndroid Build Coastguard Worker (int32_t*)out_buff, out_buff_chans,
540*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, 0);
541*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
542*b9df5ad1SAndroid Build Coastguard Worker } else {
543*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS((const int32_t*)in_buff, in_buff_chans,
544*b9df5ad1SAndroid Build Coastguard Worker (int32_t*)out_buff, out_buff_chans,
545*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes, 0);
546*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
547*b9df5ad1SAndroid Build Coastguard Worker }
548*b9df5ad1SAndroid Build Coastguard Worker default:
549*b9df5ad1SAndroid Build Coastguard Worker return 0;
550*b9df5ad1SAndroid Build Coastguard Worker }
551*b9df5ad1SAndroid Build Coastguard Worker }
552*b9df5ad1SAndroid Build Coastguard Worker
553*b9df5ad1SAndroid Build Coastguard Worker /*
554*b9df5ad1SAndroid Build Coastguard Worker * Convert a buffer of N-channel, interleaved samples to M-channel
555*b9df5ad1SAndroid Build Coastguard Worker * (where N < M).
556*b9df5ad1SAndroid Build Coastguard Worker * in_buff points to the buffer of samples
557*b9df5ad1SAndroid Build Coastguard Worker * in_buff_channels Specifies the number of channels in the input buffer.
558*b9df5ad1SAndroid Build Coastguard Worker * out_buff points to the buffer to receive converted samples.
559*b9df5ad1SAndroid Build Coastguard Worker * out_buff_channels Specifies the number of channels in the output buffer.
560*b9df5ad1SAndroid Build Coastguard Worker * sample_size_in_bytes Specifies the number of bytes per sample.
561*b9df5ad1SAndroid Build Coastguard Worker * num_in_bytes size of input buffer in BYTES
562*b9df5ad1SAndroid Build Coastguard Worker * returns
563*b9df5ad1SAndroid Build Coastguard Worker * the number of BYTES of output data.
564*b9df5ad1SAndroid Build Coastguard Worker * NOTE
565*b9df5ad1SAndroid Build Coastguard Worker * channels > N are left alone in out_buff.
566*b9df5ad1SAndroid Build Coastguard Worker * The out and in buffers must either be completely separate (non-overlapping), or
567*b9df5ad1SAndroid Build Coastguard Worker * they must both start at the same address. Partially overlapping buffers are not supported.
568*b9df5ad1SAndroid Build Coastguard Worker */
expand_selected_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)569*b9df5ad1SAndroid Build Coastguard Worker static size_t expand_selected_channels(const void* in_buff, size_t in_buff_chans,
570*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
571*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
572*b9df5ad1SAndroid Build Coastguard Worker {
573*b9df5ad1SAndroid Build Coastguard Worker switch (sample_size_in_bytes) {
574*b9df5ad1SAndroid Build Coastguard Worker case 1:
575*b9df5ad1SAndroid Build Coastguard Worker
576*b9df5ad1SAndroid Build Coastguard Worker EXPAND_SELECTED_CHANNELS((const uint8_t*)in_buff, in_buff_chans,
577*b9df5ad1SAndroid Build Coastguard Worker (uint8_t*)out_buff, out_buff_chans,
578*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
579*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
580*b9df5ad1SAndroid Build Coastguard Worker
581*b9df5ad1SAndroid Build Coastguard Worker case 2:
582*b9df5ad1SAndroid Build Coastguard Worker
583*b9df5ad1SAndroid Build Coastguard Worker EXPAND_SELECTED_CHANNELS((const int16_t*)in_buff, in_buff_chans,
584*b9df5ad1SAndroid Build Coastguard Worker (int16_t*)out_buff, out_buff_chans,
585*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
586*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
587*b9df5ad1SAndroid Build Coastguard Worker
588*b9df5ad1SAndroid Build Coastguard Worker case 3:
589*b9df5ad1SAndroid Build Coastguard Worker
590*b9df5ad1SAndroid Build Coastguard Worker EXPAND_SELECTED_CHANNELS((const uint8x3_t*)in_buff, in_buff_chans,
591*b9df5ad1SAndroid Build Coastguard Worker (uint8x3_t*)out_buff, out_buff_chans,
592*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
593*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
594*b9df5ad1SAndroid Build Coastguard Worker
595*b9df5ad1SAndroid Build Coastguard Worker case 4:
596*b9df5ad1SAndroid Build Coastguard Worker
597*b9df5ad1SAndroid Build Coastguard Worker EXPAND_SELECTED_CHANNELS((const int32_t*)in_buff, in_buff_chans,
598*b9df5ad1SAndroid Build Coastguard Worker (int32_t*)out_buff, out_buff_chans,
599*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
600*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
601*b9df5ad1SAndroid Build Coastguard Worker
602*b9df5ad1SAndroid Build Coastguard Worker default:
603*b9df5ad1SAndroid Build Coastguard Worker return 0;
604*b9df5ad1SAndroid Build Coastguard Worker }
605*b9df5ad1SAndroid Build Coastguard Worker }
606*b9df5ad1SAndroid Build Coastguard Worker
607*b9df5ad1SAndroid Build Coastguard Worker /*
608*b9df5ad1SAndroid Build Coastguard Worker * Convert a buffer of N-channel, interleaved samples to M-channel
609*b9df5ad1SAndroid Build Coastguard Worker * (where N < M).
610*b9df5ad1SAndroid Build Coastguard Worker * in_buff points to the buffer of samples
611*b9df5ad1SAndroid Build Coastguard Worker * in_buff_channels Specifies the number of channels in the input buffer.
612*b9df5ad1SAndroid Build Coastguard Worker * out_buff points to the buffer to receive converted samples.
613*b9df5ad1SAndroid Build Coastguard Worker * out_buff_channels Specifies the number of channels in the output buffer.
614*b9df5ad1SAndroid Build Coastguard Worker * sample_size_in_bytes Specifies the number of bytes per sample.
615*b9df5ad1SAndroid Build Coastguard Worker * num_in_bytes size of input buffer in BYTES
616*b9df5ad1SAndroid Build Coastguard Worker * returns
617*b9df5ad1SAndroid Build Coastguard Worker * the number of BYTES of output data.
618*b9df5ad1SAndroid Build Coastguard Worker * NOTE
619*b9df5ad1SAndroid Build Coastguard Worker * channels > N are interleaved with data from the end of the input buffer.
620*b9df5ad1SAndroid Build Coastguard Worker * The output and input buffers must be the same length.
621*b9df5ad1SAndroid Build Coastguard Worker * The output and input buffers must either be completely separate (non-overlapping), or
622*b9df5ad1SAndroid Build Coastguard Worker * they must both start at the same address. Partially overlapping buffers are not supported.
623*b9df5ad1SAndroid Build Coastguard Worker */
expand_channels_non_destructive(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)624*b9df5ad1SAndroid Build Coastguard Worker static size_t expand_channels_non_destructive(const void* in_buff, size_t in_buff_chans,
625*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
626*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
627*b9df5ad1SAndroid Build Coastguard Worker {
628*b9df5ad1SAndroid Build Coastguard Worker switch (sample_size_in_bytes) {
629*b9df5ad1SAndroid Build Coastguard Worker case 1:
630*b9df5ad1SAndroid Build Coastguard Worker
631*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS_NON_DESTRUCTIVE((const uint8_t*)in_buff, in_buff_chans,
632*b9df5ad1SAndroid Build Coastguard Worker (uint8_t*)out_buff, out_buff_chans,
633*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
634*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
635*b9df5ad1SAndroid Build Coastguard Worker
636*b9df5ad1SAndroid Build Coastguard Worker case 2:
637*b9df5ad1SAndroid Build Coastguard Worker
638*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS_NON_DESTRUCTIVE((const int16_t*)in_buff, in_buff_chans,
639*b9df5ad1SAndroid Build Coastguard Worker (int16_t*)out_buff, out_buff_chans,
640*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
641*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
642*b9df5ad1SAndroid Build Coastguard Worker
643*b9df5ad1SAndroid Build Coastguard Worker case 3:
644*b9df5ad1SAndroid Build Coastguard Worker
645*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS_NON_DESTRUCTIVE((const uint8x3_t*)in_buff, in_buff_chans,
646*b9df5ad1SAndroid Build Coastguard Worker (uint8x3_t*)out_buff, out_buff_chans,
647*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
648*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
649*b9df5ad1SAndroid Build Coastguard Worker
650*b9df5ad1SAndroid Build Coastguard Worker case 4:
651*b9df5ad1SAndroid Build Coastguard Worker
652*b9df5ad1SAndroid Build Coastguard Worker EXPAND_CHANNELS_NON_DESTRUCTIVE((const int32_t*)in_buff, in_buff_chans,
653*b9df5ad1SAndroid Build Coastguard Worker (int32_t*)out_buff, out_buff_chans,
654*b9df5ad1SAndroid Build Coastguard Worker num_in_bytes);
655*b9df5ad1SAndroid Build Coastguard Worker // returns in macro
656*b9df5ad1SAndroid Build Coastguard Worker
657*b9df5ad1SAndroid Build Coastguard Worker default:
658*b9df5ad1SAndroid Build Coastguard Worker return 0;
659*b9df5ad1SAndroid Build Coastguard Worker }
660*b9df5ad1SAndroid Build Coastguard Worker }
661*b9df5ad1SAndroid Build Coastguard Worker
adjust_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)662*b9df5ad1SAndroid Build Coastguard Worker size_t adjust_channels(const void* in_buff, size_t in_buff_chans,
663*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
664*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
665*b9df5ad1SAndroid Build Coastguard Worker {
666*b9df5ad1SAndroid Build Coastguard Worker if (out_buff_chans > in_buff_chans) {
667*b9df5ad1SAndroid Build Coastguard Worker return expand_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
668*b9df5ad1SAndroid Build Coastguard Worker sample_size_in_bytes, num_in_bytes);
669*b9df5ad1SAndroid Build Coastguard Worker } else if (out_buff_chans < in_buff_chans) {
670*b9df5ad1SAndroid Build Coastguard Worker return contract_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
671*b9df5ad1SAndroid Build Coastguard Worker sample_size_in_bytes, num_in_bytes);
672*b9df5ad1SAndroid Build Coastguard Worker } else if (in_buff != out_buff) {
673*b9df5ad1SAndroid Build Coastguard Worker memcpy(out_buff, in_buff, num_in_bytes);
674*b9df5ad1SAndroid Build Coastguard Worker }
675*b9df5ad1SAndroid Build Coastguard Worker
676*b9df5ad1SAndroid Build Coastguard Worker return num_in_bytes;
677*b9df5ad1SAndroid Build Coastguard Worker }
678*b9df5ad1SAndroid Build Coastguard Worker
adjust_selected_channels(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)679*b9df5ad1SAndroid Build Coastguard Worker size_t adjust_selected_channels(const void* in_buff, size_t in_buff_chans,
680*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
681*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
682*b9df5ad1SAndroid Build Coastguard Worker {
683*b9df5ad1SAndroid Build Coastguard Worker if (out_buff_chans > in_buff_chans) {
684*b9df5ad1SAndroid Build Coastguard Worker return expand_selected_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
685*b9df5ad1SAndroid Build Coastguard Worker sample_size_in_bytes, num_in_bytes);
686*b9df5ad1SAndroid Build Coastguard Worker } else if (out_buff_chans < in_buff_chans) {
687*b9df5ad1SAndroid Build Coastguard Worker return contract_channels(in_buff, in_buff_chans, out_buff, out_buff_chans,
688*b9df5ad1SAndroid Build Coastguard Worker sample_size_in_bytes, num_in_bytes);
689*b9df5ad1SAndroid Build Coastguard Worker } else if (in_buff != out_buff) {
690*b9df5ad1SAndroid Build Coastguard Worker memcpy(out_buff, in_buff, num_in_bytes);
691*b9df5ad1SAndroid Build Coastguard Worker }
692*b9df5ad1SAndroid Build Coastguard Worker
693*b9df5ad1SAndroid Build Coastguard Worker return num_in_bytes;
694*b9df5ad1SAndroid Build Coastguard Worker }
695*b9df5ad1SAndroid Build Coastguard Worker
adjust_channels_non_destructive(const void * in_buff,size_t in_buff_chans,void * out_buff,size_t out_buff_chans,unsigned sample_size_in_bytes,size_t num_in_bytes)696*b9df5ad1SAndroid Build Coastguard Worker size_t adjust_channels_non_destructive(const void* in_buff, size_t in_buff_chans,
697*b9df5ad1SAndroid Build Coastguard Worker void* out_buff, size_t out_buff_chans,
698*b9df5ad1SAndroid Build Coastguard Worker unsigned sample_size_in_bytes, size_t num_in_bytes)
699*b9df5ad1SAndroid Build Coastguard Worker {
700*b9df5ad1SAndroid Build Coastguard Worker if (out_buff_chans > in_buff_chans) {
701*b9df5ad1SAndroid Build Coastguard Worker return expand_channels_non_destructive(in_buff, in_buff_chans, out_buff, out_buff_chans,
702*b9df5ad1SAndroid Build Coastguard Worker sample_size_in_bytes, num_in_bytes);
703*b9df5ad1SAndroid Build Coastguard Worker } else if (out_buff_chans < in_buff_chans) {
704*b9df5ad1SAndroid Build Coastguard Worker return contract_channels_non_destructive(in_buff, in_buff_chans, out_buff, out_buff_chans,
705*b9df5ad1SAndroid Build Coastguard Worker sample_size_in_bytes, num_in_bytes);
706*b9df5ad1SAndroid Build Coastguard Worker } else if (in_buff != out_buff) {
707*b9df5ad1SAndroid Build Coastguard Worker memcpy(out_buff, in_buff, num_in_bytes);
708*b9df5ad1SAndroid Build Coastguard Worker }
709*b9df5ad1SAndroid Build Coastguard Worker
710*b9df5ad1SAndroid Build Coastguard Worker return num_in_bytes;
711*b9df5ad1SAndroid Build Coastguard Worker }
712