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