AudioMixerOps.h revision 5e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020
1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/* 2c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Copyright (C) 2014 The Android Open Source Project 3c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 4c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Licensed under the Apache License, Version 2.0 (the "License"); 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * you may not use this file except in compliance with the License. 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * You may obtain a copy of the License at 7c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * http://www.apache.org/licenses/LICENSE-2.0 9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Unless required by applicable law or agreed to in writing, software 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * distributed under the License is distributed on an "AS IS" BASIS, 12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * See the License for the specific language governing permissions and 1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * limitations under the License. 15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch */ 16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 17c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#ifndef ANDROID_AUDIO_MIXER_OPS_H 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#define ANDROID_AUDIO_MIXER_OPS_H 19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace android { 21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/* Behavior of is_same<>::value is true if the types are identical, 23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * false otherwise. Identical to the STL std::is_same. 24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch */ 25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate<typename T, typename U> 26c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstruct is_same 27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch{ 28c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch static const bool value = false; 29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}; 30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate<typename T> 32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstruct is_same<T, T> // partial specialization 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch static const bool value = true; 35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}; 36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/* MixMul is a multiplication operator to scale an audio input signal 39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * by a volume gain, with the formula: 40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * O(utput) = I(nput) * V(olume) 42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * The output, input, and volume may have different types. 44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * There are 27 variants, of which 14 are actually defined in an 45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * explicitly templated class. 46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * The following type variables and the underlying meaning: 48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Output type TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1] 50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1] 51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Volume type TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1] 52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * For high precision audio, only the <TO, TI, TV> = <float, float, float> 54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * needs to be accelerated. This is perhaps the easiest form to do quickly as well. 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <typename TO, typename TI, typename TV> 58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline TO MixMul(TI value, TV volume) { 59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch COMPILE_TIME_ASSERT_FUNCTION_SCOPE(false); 60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // should not be here :-). 61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // To avoid mistakes, this template is always specialized. 62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return value * volume; 63c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 64c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 65c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <> 66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) { 67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return value * volume; 68c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <> 71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) { 72c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return (value >> 12) * volume; 73c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <> 76c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) { 7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return value * (volume >> 16); 78c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 80template <> 81inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) { 82 return (value >> 12) * (volume >> 16); 83} 84 85template <> 86inline 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 91template <> 92inline 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 97template <> 98inline 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 102template <> 103inline 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 107template <> 108inline 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 113template <> 114inline 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 119template <> 120inline 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 124template <> 125inline 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 129template <> 130inline 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 134template <> 135inline 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 */ 143template <> 144inline float MixMul<float, float, float>(float value, float volume) { 145 return value * volume; 146} 147 148template <> 149inline 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 154template <> 155inline 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 160template <> 161inline 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 167template <> 168inline 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 173template <> 174inline 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 184template <typename TO, typename TI> 185inline void MixAccum(TO *auxaccum, TI value) { 186 if (!is_same<TO, TI>::value) { 187 LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %d %d\n", 188 sizeof(TO), sizeof(TI)); 189 } 190 *auxaccum += value; 191} 192 193template<> 194inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) { 195 static const float norm = 1. / (1 << 15); 196 *auxaccum += norm * value; 197} 198 199template<> 200inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) { 201 static const float norm = 1. / (1 << 27); 202 *auxaccum += norm * value; 203} 204 205template<> 206inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) { 207 *auxaccum += value << 12; 208} 209 210template<> 211inline 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 219template <typename TO, typename TI, typename TV, typename TA> 220inline 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 */ 229enum { 230 MIXTYPE_MULTI, 231 MIXTYPE_MONOEXPAND, 232 MIXTYPE_MULTI_SAVEONLY, 233}; 234 235/* 236 * The volumeRampMulti and volumeRamp functions take a MIXTYPE 237 * which indicates the per-frame mixing and accumulation strategy. 238 * 239 * MIXTYPE_MULTI: 240 * NCHAN represents number of input and output channels. 241 * TO: int32_t (Q4.27) or float 242 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float 243 * TV: int32_t (U4.28) or int16_t (U4.12) or float 244 * vol: represents a volume array. 245 * 246 * This accumulates into the out pointer. 247 * 248 * MIXTYPE_MONOEXPAND: 249 * Single input channel. NCHAN represents number of output channels. 250 * TO: int32_t (Q4.27) or float 251 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float 252 * TV: 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 * TV: int32_t (U4.28) or int16_t (U4.12) or float 263 * vol: represents a volume array. 264 * 265 * MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer. 266 */ 267 268template <int MIXTYPE, int NCHAN, 269 typename TO, typename TI, typename TV, typename TA, typename TAV> 270inline void volumeRampMulti(TO* out, size_t frameCount, 271 const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc) 272{ 273#ifdef ALOGVV 274 ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE); 275#endif 276 if (aux != NULL) { 277 do { 278 TA auxaccum = 0; 279 switch (MIXTYPE) { 280 case MIXTYPE_MULTI: 281 for (int i = 0; i < NCHAN; ++i) { 282 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); 283 vol[i] += volinc[i]; 284 } 285 break; 286 case MIXTYPE_MULTI_SAVEONLY: 287 for (int i = 0; i < NCHAN; ++i) { 288 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); 289 vol[i] += volinc[i]; 290 } 291 break; 292 case MIXTYPE_MONOEXPAND: 293 for (int i = 0; i < NCHAN; ++i) { 294 *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); 295 vol[i] += volinc[i]; 296 } 297 in++; 298 break; 299 default: 300 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); 301 break; 302 } 303 auxaccum /= NCHAN; 304 *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola); 305 vola[0] += volainc; 306 } while (--frameCount); 307 } else { 308 do { 309 switch (MIXTYPE) { 310 case MIXTYPE_MULTI: 311 for (int i = 0; i < NCHAN; ++i) { 312 *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); 313 vol[i] += volinc[i]; 314 } 315 break; 316 case MIXTYPE_MULTI_SAVEONLY: 317 for (int i = 0; i < NCHAN; ++i) { 318 *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); 319 vol[i] += volinc[i]; 320 } 321 break; 322 case MIXTYPE_MONOEXPAND: 323 for (int i = 0; i < NCHAN; ++i) { 324 *out++ += MixMul<TO, TI, TV>(*in, vol[i]); 325 vol[i] += volinc[i]; 326 } 327 in++; 328 break; 329 default: 330 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); 331 break; 332 } 333 } while (--frameCount); 334 } 335} 336 337template <int MIXTYPE, int NCHAN, 338 typename TO, typename TI, typename TV, typename TA, typename TAV> 339inline void volumeMulti(TO* out, size_t frameCount, 340 const TI* in, TA* aux, const TV *vol, TAV vola) 341{ 342#ifdef ALOGVV 343 ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE); 344#endif 345 if (aux != NULL) { 346 do { 347 TA auxaccum = 0; 348 switch (MIXTYPE) { 349 case MIXTYPE_MULTI: 350 for (int i = 0; i < NCHAN; ++i) { 351 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); 352 } 353 break; 354 case MIXTYPE_MULTI_SAVEONLY: 355 for (int i = 0; i < NCHAN; ++i) { 356 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); 357 } 358 break; 359 case MIXTYPE_MONOEXPAND: 360 for (int i = 0; i < NCHAN; ++i) { 361 *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); 362 } 363 in++; 364 break; 365 default: 366 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); 367 break; 368 } 369 auxaccum /= NCHAN; 370 *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola); 371 } while (--frameCount); 372 } else { 373 do { 374 switch (MIXTYPE) { 375 case MIXTYPE_MULTI: 376 for (int i = 0; i < NCHAN; ++i) { 377 *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); 378 } 379 break; 380 case MIXTYPE_MULTI_SAVEONLY: 381 for (int i = 0; i < NCHAN; ++i) { 382 *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); 383 } 384 break; 385 case MIXTYPE_MONOEXPAND: 386 for (int i = 0; i < NCHAN; ++i) { 387 *out++ += MixMul<TO, TI, TV>(*in, vol[i]); 388 } 389 in++; 390 break; 391 default: 392 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); 393 break; 394 } 395 } while (--frameCount); 396 } 397} 398 399}; 400 401#endif /* ANDROID_AUDIO_MIXER_OPS_H */ 402