AudioMixerOps.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. #pragma once
  17. #include "audio/android/cutils/log.h"
  18. namespace cocos2d { namespace experimental {
  19. /* Behavior of is_same<>::value is true if the types are identical,
  20. * false otherwise. Identical to the STL std::is_same.
  21. */
  22. template<typename T, typename U>
  23. struct is_same
  24. {
  25. static const bool value = false;
  26. };
  27. template<typename T>
  28. struct is_same<T, T> // partial specialization
  29. {
  30. static const bool value = true;
  31. };
  32. /* MixMul is a multiplication operator to scale an audio input signal
  33. * by a volume gain, with the formula:
  34. *
  35. * O(utput) = I(nput) * V(olume)
  36. *
  37. * The output, input, and volume may have different types.
  38. * There are 27 variants, of which 14 are actually defined in an
  39. * explicitly templated class.
  40. *
  41. * The following type variables and the underlying meaning:
  42. *
  43. * Output type TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
  44. * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
  45. * Volume type TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1]
  46. *
  47. * For high precision audio, only the <TO, TI, TV> = <float, float, float>
  48. * needs to be accelerated. This is perhaps the easiest form to do quickly as well.
  49. *
  50. * A generic version is NOT defined to catch any mistake of using it.
  51. */
  52. template <typename TO, typename TI, typename TV>
  53. TO MixMul(TI value, TV volume);
  54. template <>
  55. inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
  56. return value * volume;
  57. }
  58. template <>
  59. inline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
  60. return (value >> 12) * volume;
  61. }
  62. template <>
  63. inline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
  64. return value * (volume >> 16);
  65. }
  66. template <>
  67. inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
  68. return (value >> 12) * (volume >> 16);
  69. }
  70. template <>
  71. inline float MixMul<float, float, int16_t>(float value, int16_t volume) {
  72. static const float norm = 1. / (1 << 12);
  73. return value * volume * norm;
  74. }
  75. template <>
  76. inline float MixMul<float, float, int32_t>(float value, int32_t volume) {
  77. static const float norm = 1. / (1 << 28);
  78. return value * volume * norm;
  79. }
  80. template <>
  81. inline int16_t MixMul<int16_t, float, int16_t>(float value, int16_t volume) {
  82. return clamp16_from_float(MixMul<float, float, int16_t>(value, volume));
  83. }
  84. template <>
  85. inline int16_t MixMul<int16_t, float, int32_t>(float value, int32_t volume) {
  86. return clamp16_from_float(MixMul<float, float, int32_t>(value, volume));
  87. }
  88. template <>
  89. inline float MixMul<float, int16_t, int16_t>(int16_t value, int16_t volume) {
  90. static const float norm = 1. / (1 << (15 + 12));
  91. return static_cast<float>(value) * static_cast<float>(volume) * norm;
  92. }
  93. template <>
  94. inline float MixMul<float, int16_t, int32_t>(int16_t value, int32_t volume) {
  95. static const float norm = 1. / (1ULL << (15 + 28));
  96. return static_cast<float>(value) * static_cast<float>(volume) * norm;
  97. }
  98. template <>
  99. inline int16_t MixMul<int16_t, int16_t, int16_t>(int16_t value, int16_t volume) {
  100. return clamp16(MixMul<int32_t, int16_t, int16_t>(value, volume) >> 12);
  101. }
  102. template <>
  103. inline int16_t MixMul<int16_t, int32_t, int16_t>(int32_t value, int16_t volume) {
  104. return clamp16(MixMul<int32_t, int32_t, int16_t>(value, volume) >> 12);
  105. }
  106. template <>
  107. inline int16_t MixMul<int16_t, int16_t, int32_t>(int16_t value, int32_t volume) {
  108. return clamp16(MixMul<int32_t, int16_t, int32_t>(value, volume) >> 12);
  109. }
  110. template <>
  111. inline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) {
  112. return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12);
  113. }
  114. /* Required for floating point volume. Some are needed for compilation but
  115. * are not needed in execution and should be removed from the final build by
  116. * an optimizing compiler.
  117. */
  118. template <>
  119. inline float MixMul<float, float, float>(float value, float volume) {
  120. return value * volume;
  121. }
  122. template <>
  123. inline float MixMul<float, int16_t, float>(int16_t value, float volume) {
  124. static const float float_from_q_15 = 1. / (1 << 15);
  125. return value * volume * float_from_q_15;
  126. }
  127. template <>
  128. inline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) {
  129. LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here");
  130. return value * volume;
  131. }
  132. template <>
  133. inline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) {
  134. LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here");
  135. static const float u4_12_from_float = (1 << 12);
  136. return value * volume * u4_12_from_float;
  137. }
  138. template <>
  139. inline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) {
  140. LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here");
  141. return clamp16_from_float(MixMul<float, int16_t, float>(value, volume));
  142. }
  143. template <>
  144. inline int16_t MixMul<int16_t, float, float>(float value, float volume) {
  145. return clamp16_from_float(value * volume);
  146. }
  147. /*
  148. * MixAccum is used to add into an accumulator register of a possibly different
  149. * type. The TO and TI types are the same as MixMul.
  150. */
  151. template <typename TO, typename TI>
  152. inline void MixAccum(TO *auxaccum, TI value) {
  153. if (!is_same<TO, TI>::value) {
  154. LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
  155. sizeof(TO), sizeof(TI));
  156. }
  157. *auxaccum += value;
  158. }
  159. template<>
  160. inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
  161. static const float norm = 1. / (1 << 15);
  162. *auxaccum += norm * value;
  163. }
  164. template<>
  165. inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
  166. static const float norm = 1. / (1 << 27);
  167. *auxaccum += norm * value;
  168. }
  169. template<>
  170. inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
  171. *auxaccum += value << 12;
  172. }
  173. template<>
  174. inline void MixAccum<int32_t, float>(int32_t *auxaccum, float value) {
  175. *auxaccum += clampq4_27_from_float(value);
  176. }
  177. /* MixMulAux is just like MixMul except it combines with
  178. * an accumulator operation MixAccum.
  179. */
  180. template <typename TO, typename TI, typename TV, typename TA>
  181. inline TO MixMulAux(TI value, TV volume, TA *auxaccum) {
  182. MixAccum<TA, TI>(auxaccum, value);
  183. return MixMul<TO, TI, TV>(value, volume);
  184. }
  185. /* MIXTYPE is used to determine how the samples in the input frame
  186. * are mixed with volume gain into the output frame.
  187. * See the volumeRampMulti functions below for more details.
  188. */
  189. enum {
  190. MIXTYPE_MULTI,
  191. MIXTYPE_MONOEXPAND,
  192. MIXTYPE_MULTI_SAVEONLY,
  193. MIXTYPE_MULTI_MONOVOL,
  194. MIXTYPE_MULTI_SAVEONLY_MONOVOL,
  195. };
  196. /*
  197. * The volumeRampMulti and volumeRamp functions take a MIXTYPE
  198. * which indicates the per-frame mixing and accumulation strategy.
  199. *
  200. * MIXTYPE_MULTI:
  201. * NCHAN represents number of input and output channels.
  202. * TO: int32_t (Q4.27) or float
  203. * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
  204. * TV: int32_t (U4.28) or int16_t (U4.12) or float
  205. * vol: represents a volume array.
  206. *
  207. * This accumulates into the out pointer.
  208. *
  209. * MIXTYPE_MONOEXPAND:
  210. * Single input channel. NCHAN represents number of output channels.
  211. * TO: int32_t (Q4.27) or float
  212. * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
  213. * TV: int32_t (U4.28) or int16_t (U4.12) or float
  214. * Input channel count is 1.
  215. * vol: represents volume array.
  216. *
  217. * This accumulates into the out pointer.
  218. *
  219. * MIXTYPE_MULTI_SAVEONLY:
  220. * NCHAN represents number of input and output channels.
  221. * TO: int16_t (Q.15) or float
  222. * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
  223. * TV: int32_t (U4.28) or int16_t (U4.12) or float
  224. * vol: represents a volume array.
  225. *
  226. * MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
  227. *
  228. * MIXTYPE_MULTI_MONOVOL:
  229. * Same as MIXTYPE_MULTI, but uses only volume[0].
  230. *
  231. * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
  232. * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
  233. *
  234. */
  235. template <int MIXTYPE, int NCHAN,
  236. typename TO, typename TI, typename TV, typename TA, typename TAV>
  237. inline void volumeRampMulti(TO* out, size_t frameCount,
  238. const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
  239. {
  240. #ifdef ALOGVV
  241. ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
  242. #endif
  243. if (aux != NULL) {
  244. do {
  245. TA auxaccum = 0;
  246. switch (MIXTYPE) {
  247. case MIXTYPE_MULTI:
  248. for (int i = 0; i < NCHAN; ++i) {
  249. *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
  250. vol[i] += volinc[i];
  251. }
  252. break;
  253. case MIXTYPE_MONOEXPAND:
  254. for (int i = 0; i < NCHAN; ++i) {
  255. *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
  256. vol[i] += volinc[i];
  257. }
  258. in++;
  259. break;
  260. case MIXTYPE_MULTI_SAVEONLY:
  261. for (int i = 0; i < NCHAN; ++i) {
  262. *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
  263. vol[i] += volinc[i];
  264. }
  265. break;
  266. case MIXTYPE_MULTI_MONOVOL:
  267. for (int i = 0; i < NCHAN; ++i) {
  268. *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
  269. }
  270. vol[0] += volinc[0];
  271. break;
  272. case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
  273. for (int i = 0; i < NCHAN; ++i) {
  274. *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
  275. }
  276. vol[0] += volinc[0];
  277. break;
  278. default:
  279. LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
  280. break;
  281. }
  282. auxaccum /= NCHAN;
  283. *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
  284. vola[0] += volainc;
  285. } while (--frameCount);
  286. } else {
  287. do {
  288. switch (MIXTYPE) {
  289. case MIXTYPE_MULTI:
  290. for (int i = 0; i < NCHAN; ++i) {
  291. *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
  292. vol[i] += volinc[i];
  293. }
  294. break;
  295. case MIXTYPE_MONOEXPAND:
  296. for (int i = 0; i < NCHAN; ++i) {
  297. *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
  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++ = MixMul<TO, TI, TV>(*in++, vol[i]);
  305. vol[i] += volinc[i];
  306. }
  307. break;
  308. case MIXTYPE_MULTI_MONOVOL:
  309. for (int i = 0; i < NCHAN; ++i) {
  310. *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
  311. }
  312. vol[0] += volinc[0];
  313. break;
  314. case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
  315. for (int i = 0; i < NCHAN; ++i) {
  316. *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
  317. }
  318. vol[0] += volinc[0];
  319. break;
  320. default:
  321. LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
  322. break;
  323. }
  324. } while (--frameCount);
  325. }
  326. }
  327. template <int MIXTYPE, int NCHAN,
  328. typename TO, typename TI, typename TV, typename TA, typename TAV>
  329. inline void volumeMulti(TO* out, size_t frameCount,
  330. const TI* in, TA* aux, const TV *vol, TAV vola)
  331. {
  332. #ifdef ALOGVV
  333. ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
  334. #endif
  335. if (aux != NULL) {
  336. do {
  337. TA auxaccum = 0;
  338. switch (MIXTYPE) {
  339. case MIXTYPE_MULTI:
  340. for (int i = 0; i < NCHAN; ++i) {
  341. *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
  342. }
  343. break;
  344. case MIXTYPE_MONOEXPAND:
  345. for (int i = 0; i < NCHAN; ++i) {
  346. *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
  347. }
  348. in++;
  349. break;
  350. case MIXTYPE_MULTI_SAVEONLY:
  351. for (int i = 0; i < NCHAN; ++i) {
  352. *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
  353. }
  354. break;
  355. case MIXTYPE_MULTI_MONOVOL:
  356. for (int i = 0; i < NCHAN; ++i) {
  357. *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
  358. }
  359. break;
  360. case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
  361. for (int i = 0; i < NCHAN; ++i) {
  362. *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
  363. }
  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_MONOEXPAND:
  381. for (int i = 0; i < NCHAN; ++i) {
  382. *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
  383. }
  384. in++;
  385. break;
  386. case MIXTYPE_MULTI_SAVEONLY:
  387. for (int i = 0; i < NCHAN; ++i) {
  388. *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
  389. }
  390. break;
  391. case MIXTYPE_MULTI_MONOVOL:
  392. for (int i = 0; i < NCHAN; ++i) {
  393. *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
  394. }
  395. break;
  396. case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
  397. for (int i = 0; i < NCHAN; ++i) {
  398. *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
  399. }
  400. break;
  401. default:
  402. LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
  403. break;
  404. }
  405. } while (--frameCount);
  406. }
  407. }
  408. }} // namespace cocos2d { namespace experimental {