Home | History | Annotate | Download | only in libaudioprocessing
      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 #ifndef ANDROID_AUDIO_MIXER_OPS_H
     18 #define ANDROID_AUDIO_MIXER_OPS_H
     19 
     20 namespace android {
     21 
     22 /* Behavior of is_same<>::value is true if the types are identical,
     23  * false otherwise. Identical to the STL std::is_same.
     24  */
     25 template<typename T, typename U>
     26 struct is_same
     27 {
     28     static const bool value = false;
     29 };
     30 
     31 template<typename T>
     32 struct is_same<T, T>  // partial specialization
     33 {
     34     static const bool value = true;
     35 };
     36 
     37 
     38 /* MixMul is a multiplication operator to scale an audio input signal
     39  * by a volume gain, with the formula:
     40  *
     41  * O(utput) = I(nput) * V(olume)
     42  *
     43  * The output, input, and volume may have different types.
     44  * There are 27 variants, of which 14 are actually defined in an
     45  * explicitly templated class.
     46  *
     47  * The following type variables and the underlying meaning:
     48  *
     49  * Output type       TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
     50  * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
     51  * Volume type       TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1]
     52  *
     53  * For high precision audio, only the <TO, TI, TV> = <float, float, float>
     54  * needs to be accelerated. This is perhaps the easiest form to do quickly as well.
     55  *
     56  * A generic version is NOT defined to catch any mistake of using it.
     57  */
     58 
     59 template <typename TO, typename TI, typename TV>
     60 TO MixMul(TI value, TV volume);
     61 
     62 template <>
     63 inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
     64     return value * volume;
     65 }
     66 
     67 template <>
     68 inline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
     69     return (value >> 12) * volume;
     70 }
     71 
     72 template <>
     73 inline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
     74     return value * (volume >> 16);
     75 }
     76 
     77 template <>
     78 inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
     79     return (value >> 12) * (volume >> 16);
     80 }
     81 
     82 template <>
     83 inline float MixMul<float, float, int16_t>(float value, int16_t volume) {
     84     static const float norm = 1. / (1 << 12);
     85     return value * volume * norm;
     86 }
     87 
     88 template <>
     89 inline float MixMul<float, float, int32_t>(float value, int32_t volume) {
     90     static const float norm = 1. / (1 << 28);
     91     return value * volume * norm;
     92 }
     93 
     94 template <>
     95 inline int16_t MixMul<int16_t, float, int16_t>(float value, int16_t volume) {
     96     return clamp16_from_float(MixMul<float, float, int16_t>(value, volume));
     97 }
     98 
     99 template <>
    100 inline int16_t MixMul<int16_t, float, int32_t>(float value, int32_t volume) {
    101     return clamp16_from_float(MixMul<float, float, int32_t>(value, volume));
    102 }
    103 
    104 template <>
    105 inline float MixMul<float, int16_t, int16_t>(int16_t value, int16_t volume) {
    106     static const float norm = 1. / (1 << (15 + 12));
    107     return static_cast<float>(value) * static_cast<float>(volume) * norm;
    108 }
    109 
    110 template <>
    111 inline float MixMul<float, int16_t, int32_t>(int16_t value, int32_t volume) {
    112     static const float norm = 1. / (1ULL << (15 + 28));
    113     return static_cast<float>(value) * static_cast<float>(volume) * norm;
    114 }
    115 
    116 template <>
    117 inline int16_t MixMul<int16_t, int16_t, int16_t>(int16_t value, int16_t volume) {
    118     return clamp16(MixMul<int32_t, int16_t, int16_t>(value, volume) >> 12);
    119 }
    120 
    121 template <>
    122 inline int16_t MixMul<int16_t, int32_t, int16_t>(int32_t value, int16_t volume) {
    123     return clamp16(MixMul<int32_t, int32_t, int16_t>(value, volume) >> 12);
    124 }
    125 
    126 template <>
    127 inline int16_t MixMul<int16_t, int16_t, int32_t>(int16_t value, int32_t volume) {
    128     return clamp16(MixMul<int32_t, int16_t, int32_t>(value, volume) >> 12);
    129 }
    130 
    131 template <>
    132 inline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) {
    133     return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12);
    134 }
    135 
    136 /* Required for floating point volume.  Some are needed for compilation but
    137  * are not needed in execution and should be removed from the final build by
    138  * an optimizing compiler.
    139  */
    140 template <>
    141 inline float MixMul<float, float, float>(float value, float volume) {
    142     return value * volume;
    143 }
    144 
    145 template <>
    146 inline float MixMul<float, int16_t, float>(int16_t value, float volume) {
    147     static const float float_from_q_15 = 1. / (1 << 15);
    148     return value * volume * float_from_q_15;
    149 }
    150 
    151 template <>
    152 inline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) {
    153     LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here");
    154     return value * volume;
    155 }
    156 
    157 template <>
    158 inline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) {
    159     LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here");
    160     static const float u4_12_from_float = (1 << 12);
    161     return value * volume * u4_12_from_float;
    162 }
    163 
    164 template <>
    165 inline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) {
    166     LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here");
    167     return clamp16_from_float(MixMul<float, int16_t, float>(value, volume));
    168 }
    169 
    170 template <>
    171 inline int16_t MixMul<int16_t, float, float>(float value, float volume) {
    172     return clamp16_from_float(value * volume);
    173 }
    174 
    175 /*
    176  * MixAccum is used to add into an accumulator register of a possibly different
    177  * type. The TO and TI types are the same as MixMul.
    178  */
    179 
    180 template <typename TO, typename TI>
    181 inline void MixAccum(TO *auxaccum, TI value) {
    182     if (!is_same<TO, TI>::value) {
    183         LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
    184                 sizeof(TO), sizeof(TI));
    185     }
    186     *auxaccum += value;
    187 }
    188 
    189 template<>
    190 inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
    191     static constexpr float norm = 1. / (1 << 15);
    192     *auxaccum += norm * value;
    193 }
    194 
    195 template<>
    196 inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
    197     static constexpr float norm = 1. / (1 << 27);
    198     *auxaccum += norm * value;
    199 }
    200 
    201 template<>
    202 inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
    203     *auxaccum += value << 12;
    204 }
    205 
    206 template<>
    207 inline void MixAccum<int32_t, float>(int32_t *auxaccum, float value) {
    208     *auxaccum += clampq4_27_from_float(value);
    209 }
    210 
    211 /* MixMulAux is just like MixMul except it combines with
    212  * an accumulator operation MixAccum.
    213  */
    214 
    215 template <typename TO, typename TI, typename TV, typename TA>
    216 inline TO MixMulAux(TI value, TV volume, TA *auxaccum) {
    217     MixAccum<TA, TI>(auxaccum, value);
    218     return MixMul<TO, TI, TV>(value, volume);
    219 }
    220 
    221 /* MIXTYPE is used to determine how the samples in the input frame
    222  * are mixed with volume gain into the output frame.
    223  * See the volumeRampMulti functions below for more details.
    224  */
    225 enum {
    226     MIXTYPE_MULTI,
    227     MIXTYPE_MONOEXPAND,
    228     MIXTYPE_MULTI_SAVEONLY,
    229     MIXTYPE_MULTI_MONOVOL,
    230     MIXTYPE_MULTI_SAVEONLY_MONOVOL,
    231 };
    232 
    233 /*
    234  * The volumeRampMulti and volumeRamp functions take a MIXTYPE
    235  * which indicates the per-frame mixing and accumulation strategy.
    236  *
    237  * MIXTYPE_MULTI:
    238  *   NCHAN represents number of input and output channels.
    239  *   TO: int32_t (Q4.27) or float
    240  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
    241  *   TA: int32_t (Q4.27) or float
    242  *   TV: int32_t (U4.28) or int16_t (U4.12) or float
    243  *   vol: represents a volume array.
    244  *
    245  *   This accumulates into the out pointer.
    246  *
    247  * MIXTYPE_MONOEXPAND:
    248  *   Single input channel. NCHAN represents number of output channels.
    249  *   TO: int32_t (Q4.27) or float
    250  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
    251  *   TA: int32_t (Q4.27) or float
    252  *   TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
    253  *   Input channel count is 1.
    254  *   vol: represents volume array.
    255  *
    256  *   This accumulates into the out pointer.
    257  *
    258  * MIXTYPE_MULTI_SAVEONLY:
    259  *   NCHAN represents number of input and output channels.
    260  *   TO: int16_t (Q.15) or float
    261  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
    262  *   TA: int32_t (Q4.27) or float
    263  *   TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
    264  *   vol: represents a volume array.
    265  *
    266  *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
    267  *
    268  * MIXTYPE_MULTI_MONOVOL:
    269  *   Same as MIXTYPE_MULTI, but uses only volume[0].
    270  *
    271  * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    272  *   Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
    273  *
    274  */
    275 
    276 template <int MIXTYPE, int NCHAN,
    277         typename TO, typename TI, typename TV, typename TA, typename TAV>
    278 inline void volumeRampMulti(TO* out, size_t frameCount,
    279         const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
    280 {
    281 #ifdef ALOGVV
    282     ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
    283 #endif
    284     if (aux != NULL) {
    285         do {
    286             TA auxaccum = 0;
    287             switch (MIXTYPE) {
    288             case MIXTYPE_MULTI:
    289                 for (int i = 0; i < NCHAN; ++i) {
    290                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    291                     vol[i] += volinc[i];
    292                 }
    293                 break;
    294             case MIXTYPE_MONOEXPAND:
    295                 for (int i = 0; i < NCHAN; ++i) {
    296                     *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
    297                     vol[i] += volinc[i];
    298                 }
    299                 in++;
    300                 break;
    301             case MIXTYPE_MULTI_SAVEONLY:
    302                 for (int i = 0; i < NCHAN; ++i) {
    303                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    304                     vol[i] += volinc[i];
    305                 }
    306                 break;
    307             case MIXTYPE_MULTI_MONOVOL:
    308                 for (int i = 0; i < NCHAN; ++i) {
    309                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    310                 }
    311                 vol[0] += volinc[0];
    312                 break;
    313             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    314                 for (int i = 0; i < NCHAN; ++i) {
    315                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    316                 }
    317                 vol[0] += volinc[0];
    318                 break;
    319             default:
    320                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    321                 break;
    322             }
    323             auxaccum /= NCHAN;
    324             *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
    325             vola[0] += volainc;
    326         } while (--frameCount);
    327     } else {
    328         do {
    329             switch (MIXTYPE) {
    330             case MIXTYPE_MULTI:
    331                 for (int i = 0; i < NCHAN; ++i) {
    332                     *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
    333                     vol[i] += volinc[i];
    334                 }
    335                 break;
    336             case MIXTYPE_MONOEXPAND:
    337                 for (int i = 0; i < NCHAN; ++i) {
    338                     *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
    339                     vol[i] += volinc[i];
    340                 }
    341                 in++;
    342                 break;
    343             case MIXTYPE_MULTI_SAVEONLY:
    344                 for (int i = 0; i < NCHAN; ++i) {
    345                     *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
    346                     vol[i] += volinc[i];
    347                 }
    348                 break;
    349             case MIXTYPE_MULTI_MONOVOL:
    350                 for (int i = 0; i < NCHAN; ++i) {
    351                     *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
    352                 }
    353                 vol[0] += volinc[0];
    354                 break;
    355             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    356                 for (int i = 0; i < NCHAN; ++i) {
    357                     *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
    358                 }
    359                 vol[0] += volinc[0];
    360                 break;
    361             default:
    362                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    363                 break;
    364             }
    365         } while (--frameCount);
    366     }
    367 }
    368 
    369 template <int MIXTYPE, int NCHAN,
    370         typename TO, typename TI, typename TV, typename TA, typename TAV>
    371 inline void volumeMulti(TO* out, size_t frameCount,
    372         const TI* in, TA* aux, const TV *vol, TAV vola)
    373 {
    374 #ifdef ALOGVV
    375     ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
    376 #endif
    377     if (aux != NULL) {
    378         do {
    379             TA auxaccum = 0;
    380             switch (MIXTYPE) {
    381             case MIXTYPE_MULTI:
    382                 for (int i = 0; i < NCHAN; ++i) {
    383                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    384                 }
    385                 break;
    386             case MIXTYPE_MONOEXPAND:
    387                 for (int i = 0; i < NCHAN; ++i) {
    388                     *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
    389                 }
    390                 in++;
    391                 break;
    392             case MIXTYPE_MULTI_SAVEONLY:
    393                 for (int i = 0; i < NCHAN; ++i) {
    394                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    395                 }
    396                 break;
    397             case MIXTYPE_MULTI_MONOVOL:
    398                 for (int i = 0; i < NCHAN; ++i) {
    399                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    400                 }
    401                 break;
    402             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    403                 for (int i = 0; i < NCHAN; ++i) {
    404                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    405                 }
    406                 break;
    407             default:
    408                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    409                 break;
    410             }
    411             auxaccum /= NCHAN;
    412             *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
    413         } while (--frameCount);
    414     } else {
    415         do {
    416             switch (MIXTYPE) {
    417             case MIXTYPE_MULTI:
    418                 for (int i = 0; i < NCHAN; ++i) {
    419                     *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
    420                 }
    421                 break;
    422             case MIXTYPE_MONOEXPAND:
    423                 for (int i = 0; i < NCHAN; ++i) {
    424                     *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
    425                 }
    426                 in++;
    427                 break;
    428             case MIXTYPE_MULTI_SAVEONLY:
    429                 for (int i = 0; i < NCHAN; ++i) {
    430                     *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
    431                 }
    432                 break;
    433             case MIXTYPE_MULTI_MONOVOL:
    434                 for (int i = 0; i < NCHAN; ++i) {
    435                     *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
    436                 }
    437                 break;
    438             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    439                 for (int i = 0; i < NCHAN; ++i) {
    440                     *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
    441                 }
    442                 break;
    443             default:
    444                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    445                 break;
    446             }
    447         } while (--frameCount);
    448     }
    449 }
    450 
    451 };
    452 
    453 #endif /* ANDROID_AUDIO_MIXER_OPS_H */
    454