blob: f33e36169fa8250247cdb92b6f6f9536de8bfaad [file] [log] [blame]
Andy Hung296b7412014-06-17 15:25:47 -07001/*
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.
Chih-Hung Hsieh65025402014-12-11 13:06:46 -080055 *
56 * A generic version is NOT defined to catch any mistake of using it.
Andy Hung296b7412014-06-17 15:25:47 -070057 */
58
59template <typename TO, typename TI, typename TV>
Chih-Hung Hsieh65025402014-12-11 13:06:46 -080060TO MixMul(TI value, TV volume);
Andy Hung296b7412014-06-17 15:25:47 -070061
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
Andy Hung5e58b0a2014-06-23 19:07:29 -0700136/* 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");
Andy Hung83ffcfb2015-06-18 17:34:40 -0700167 return clamp16_from_float(MixMul<float, int16_t, float>(value, volume));
Andy Hung5e58b0a2014-06-23 19:07:29 -0700168}
169
170template <>
171inline int16_t MixMul<int16_t, float, float>(float value, float volume) {
Andy Hung83ffcfb2015-06-18 17:34:40 -0700172 return clamp16_from_float(value * volume);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700173}
174
Andy Hung296b7412014-06-17 15:25:47 -0700175/*
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) {
Glenn Kastena4daf0b2014-07-28 16:34:45 -0700183 LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
Andy Hung296b7412014-06-17 15:25:47 -0700184 sizeof(TO), sizeof(TI));
185 }
186 *auxaccum += value;
187}
188
189template<>
190inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
Andy Hung116a4982017-11-30 10:15:08 -0800191 static constexpr float norm = 1. / (1 << 15);
Andy Hung296b7412014-06-17 15:25:47 -0700192 *auxaccum += norm * value;
193}
194
195template<>
196inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
Andy Hung116a4982017-11-30 10:15:08 -0800197 static constexpr float norm = 1. / (1 << 27);
Andy Hung296b7412014-06-17 15:25:47 -0700198 *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,
Andy Hunge93b6b72014-07-17 21:30:53 -0700229 MIXTYPE_MULTI_MONOVOL,
230 MIXTYPE_MULTI_SAVEONLY_MONOVOL,
Andy Hung296b7412014-06-17 15:25:47 -0700231};
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
Andy Hung116a4982017-11-30 10:15:08 -0800241 * TA: int32_t (Q4.27) or float
Andy Hung296b7412014-06-17 15:25:47 -0700242 * 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
Andy Hung116a4982017-11-30 10:15:08 -0800251 * TA: int32_t (Q4.27) or float
252 * TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
Andy Hung296b7412014-06-17 15:25:47 -0700253 * 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
Andy Hung116a4982017-11-30 10:15:08 -0800262 * TA: int32_t (Q4.27) or float
263 * TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
Andy Hung296b7412014-06-17 15:25:47 -0700264 * vol: represents a volume array.
265 *
266 * MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
Andy Hunge93b6b72014-07-17 21:30:53 -0700267 *
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 *
Andy Hung296b7412014-06-17 15:25:47 -0700274 */
275
276template <int MIXTYPE, int NCHAN,
277 typename TO, typename TI, typename TV, typename TA, typename TAV>
278inline 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;
Andy Hung296b7412014-06-17 15:25:47 -0700294 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;
Andy Hunge93b6b72014-07-17 21:30:53 -0700301 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;
Andy Hung296b7412014-06-17 15:25:47 -0700319 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;
Andy Hung296b7412014-06-17 15:25:47 -0700336 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;
Andy Hunge93b6b72014-07-17 21:30:53 -0700343 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;
Andy Hung296b7412014-06-17 15:25:47 -0700361 default:
362 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
363 break;
364 }
365 } while (--frameCount);
366 }
367}
368
369template <int MIXTYPE, int NCHAN,
370 typename TO, typename TI, typename TV, typename TA, typename TAV>
371inline 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;
Andy Hung296b7412014-06-17 15:25:47 -0700386 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;
Andy Hunge93b6b72014-07-17 21:30:53 -0700392 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;
Andy Hung296b7412014-06-17 15:25:47 -0700407 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;
Andy Hung296b7412014-06-17 15:25:47 -0700422 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;
Andy Hunge93b6b72014-07-17 21:30:53 -0700428 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;
Andy Hung296b7412014-06-17 15:25:47 -0700443 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 */