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 20namespace 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 */ 25template<typename T, typename U> 26struct is_same 27{ 28 static const bool value = false; 29}; 30 31template<typename T> 32struct 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 59template <typename TO, typename TI, typename TV> 60TO MixMul(TI value, TV volume); 61 62template <> 63inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) { 64 return value * volume; 65} 66 67template <> 68inline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) { 69 return (value >> 12) * volume; 70} 71 72template <> 73inline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) { 74 return value * (volume >> 16); 75} 76 77template <> 78inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) { 79 return (value >> 12) * (volume >> 16); 80} 81 82template <> 83inline 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 88template <> 89inline 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 94template <> 95inline 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 99template <> 100inline 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 104template <> 105inline 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 110template <> 111inline 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 116template <> 117inline 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 121template <> 122inline 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 126template <> 127inline 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 131template <> 132inline 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 */ 140template <> 141inline float MixMul<float, float, float>(float value, float volume) { 142 return value * volume; 143} 144 145template <> 146inline 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 151template <> 152inline 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 157template <> 158inline 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 164template <> 165inline 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 170template <> 171inline 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 180template <typename TO, typename TI> 181inline 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 189template<> 190inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) { 191 static const float norm = 1. / (1 << 15); 192 *auxaccum += norm * value; 193} 194 195template<> 196inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) { 197 static const float norm = 1. / (1 << 27); 198 *auxaccum += norm * value; 199} 200 201template<> 202inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) { 203 *auxaccum += value << 12; 204} 205 206template<> 207inline 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 215template <typename TO, typename TI, typename TV, typename TA> 216inline 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 */ 225enum { 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 273template <int MIXTYPE, int NCHAN, 274 typename TO, typename TI, typename TV, typename TA, typename TAV> 275inline 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 366template <int MIXTYPE, int NCHAN, 367 typename TO, typename TI, typename TV, typename TA, typename TAV> 368inline 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