Home | History | Annotate | Download | only in audio_utils
      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