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