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