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 */ 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 */ 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 */ 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 */ 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 */ 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 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