Home | History | Annotate | Download | only in audioflinger
      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 const 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 const 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  *   TV: int32_t (U4.28) or int16_t (U4.12) or float
    242  *   vol: represents a volume array.
    243  *
    244  *   This accumulates into the out pointer.
    245  *
    246  * MIXTYPE_MONOEXPAND:
    247  *   Single input channel. NCHAN represents number of output channels.
    248  *   TO: int32_t (Q4.27) or float
    249  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
    250  *   TV: int32_t (U4.28) or int16_t (U4.12) or float
    251  *   Input channel count is 1.
    252  *   vol: represents volume array.
    253  *
    254  *   This accumulates into the out pointer.
    255  *
    256  * MIXTYPE_MULTI_SAVEONLY:
    257  *   NCHAN represents number of input and output channels.
    258  *   TO: int16_t (Q.15) or float
    259  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
    260  *   TV: int32_t (U4.28) or int16_t (U4.12) or float
    261  *   vol: represents a volume array.
    262  *
    263  *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
    264  *
    265  * MIXTYPE_MULTI_MONOVOL:
    266  *   Same as MIXTYPE_MULTI, but uses only volume[0].
    267  *
    268  * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    269  *   Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
    270  *
    271  */
    272 
    273 template <int MIXTYPE, int NCHAN,
    274         typename TO, typename TI, typename TV, typename TA, typename TAV>
    275 inline void volumeRampMulti(TO* out, size_t frameCount,
    276         const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
    277 {
    278 #ifdef ALOGVV
    279     ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
    280 #endif
    281     if (aux != NULL) {
    282         do {
    283             TA auxaccum = 0;
    284             switch (MIXTYPE) {
    285             case MIXTYPE_MULTI:
    286                 for (int i = 0; i < NCHAN; ++i) {
    287                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    288                     vol[i] += volinc[i];
    289                 }
    290                 break;
    291             case MIXTYPE_MONOEXPAND:
    292                 for (int i = 0; i < NCHAN; ++i) {
    293                     *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
    294                     vol[i] += volinc[i];
    295                 }
    296                 in++;
    297                 break;
    298             case MIXTYPE_MULTI_SAVEONLY:
    299                 for (int i = 0; i < NCHAN; ++i) {
    300                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    301                     vol[i] += volinc[i];
    302                 }
    303                 break;
    304             case MIXTYPE_MULTI_MONOVOL:
    305                 for (int i = 0; i < NCHAN; ++i) {
    306                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    307                 }
    308                 vol[0] += volinc[0];
    309                 break;
    310             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    311                 for (int i = 0; i < NCHAN; ++i) {
    312                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    313                 }
    314                 vol[0] += volinc[0];
    315                 break;
    316             default:
    317                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    318                 break;
    319             }
    320             auxaccum /= NCHAN;
    321             *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
    322             vola[0] += volainc;
    323         } while (--frameCount);
    324     } else {
    325         do {
    326             switch (MIXTYPE) {
    327             case MIXTYPE_MULTI:
    328                 for (int i = 0; i < NCHAN; ++i) {
    329                     *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
    330                     vol[i] += volinc[i];
    331                 }
    332                 break;
    333             case MIXTYPE_MONOEXPAND:
    334                 for (int i = 0; i < NCHAN; ++i) {
    335                     *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
    336                     vol[i] += volinc[i];
    337                 }
    338                 in++;
    339                 break;
    340             case MIXTYPE_MULTI_SAVEONLY:
    341                 for (int i = 0; i < NCHAN; ++i) {
    342                     *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
    343                     vol[i] += volinc[i];
    344                 }
    345                 break;
    346             case MIXTYPE_MULTI_MONOVOL:
    347                 for (int i = 0; i < NCHAN; ++i) {
    348                     *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
    349                 }
    350                 vol[0] += volinc[0];
    351                 break;
    352             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    353                 for (int i = 0; i < NCHAN; ++i) {
    354                     *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
    355                 }
    356                 vol[0] += volinc[0];
    357                 break;
    358             default:
    359                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    360                 break;
    361             }
    362         } while (--frameCount);
    363     }
    364 }
    365 
    366 template <int MIXTYPE, int NCHAN,
    367         typename TO, typename TI, typename TV, typename TA, typename TAV>
    368 inline void volumeMulti(TO* out, size_t frameCount,
    369         const TI* in, TA* aux, const TV *vol, TAV vola)
    370 {
    371 #ifdef ALOGVV
    372     ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
    373 #endif
    374     if (aux != NULL) {
    375         do {
    376             TA auxaccum = 0;
    377             switch (MIXTYPE) {
    378             case MIXTYPE_MULTI:
    379                 for (int i = 0; i < NCHAN; ++i) {
    380                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    381                 }
    382                 break;
    383             case MIXTYPE_MONOEXPAND:
    384                 for (int i = 0; i < NCHAN; ++i) {
    385                     *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
    386                 }
    387                 in++;
    388                 break;
    389             case MIXTYPE_MULTI_SAVEONLY:
    390                 for (int i = 0; i < NCHAN; ++i) {
    391                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
    392                 }
    393                 break;
    394             case MIXTYPE_MULTI_MONOVOL:
    395                 for (int i = 0; i < NCHAN; ++i) {
    396                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    397                 }
    398                 break;
    399             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    400                 for (int i = 0; i < NCHAN; ++i) {
    401                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
    402                 }
    403                 break;
    404             default:
    405                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    406                 break;
    407             }
    408             auxaccum /= NCHAN;
    409             *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
    410         } while (--frameCount);
    411     } else {
    412         do {
    413             switch (MIXTYPE) {
    414             case MIXTYPE_MULTI:
    415                 for (int i = 0; i < NCHAN; ++i) {
    416                     *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
    417                 }
    418                 break;
    419             case MIXTYPE_MONOEXPAND:
    420                 for (int i = 0; i < NCHAN; ++i) {
    421                     *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
    422                 }
    423                 in++;
    424                 break;
    425             case MIXTYPE_MULTI_SAVEONLY:
    426                 for (int i = 0; i < NCHAN; ++i) {
    427                     *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
    428                 }
    429                 break;
    430             case MIXTYPE_MULTI_MONOVOL:
    431                 for (int i = 0; i < NCHAN; ++i) {
    432                     *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
    433                 }
    434                 break;
    435             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
    436                 for (int i = 0; i < NCHAN; ++i) {
    437                     *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
    438                 }
    439                 break;
    440             default:
    441                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
    442                 break;
    443             }
    444         } while (--frameCount);
    445     }
    446 }
    447 
    448 };
    449 
    450 #endif /* ANDROID_AUDIO_MIXER_OPS_H */
    451