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 */
clamp24(int32_t sample)24 static 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 */
uint8x3_to_int32(uint8x3_t val)35 inline 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 */
int32_to_uint8x3(int32_t in)47 inline 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 */
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)227 static 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 */
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)298 static 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
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)362 size_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