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  * A generic version is NOT defined to catch any mistake of using it.
57  */
58 
59 template <typename TO, typename TI, typename TV>
60 TO MixMul(TI value, TV volume);
61 
62 template <>
63 inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
64     return value * volume;
65 }
66 
67 template <>
68 inline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
69     return (value >> 12) * volume;
70 }
71 
72 template <>
73 inline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
74     return value * (volume >> 16);
75 }
76 
77 template <>
78 inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
79     return (value >> 12) * (volume >> 16);
80 }
81 
82 template <>
83 inline 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 
88 template <>
89 inline 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 
94 template <>
95 inline 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 
99 template <>
100 inline 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 
104 template <>
105 inline 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 
110 template <>
111 inline 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 
116 template <>
117 inline 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 
121 template <>
122 inline 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 
126 template <>
127 inline 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 
131 template <>
132 inline 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  */
140 template <>
141 inline float MixMul<float, float, float>(float value, float volume) {
142     return value * volume;
143 }
144 
145 template <>
146 inline 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 
151 template <>
152 inline 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 
157 template <>
158 inline 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 
164 template <>
165 inline 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 
170 template <>
171 inline 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 
180 template <typename TO, typename TI>
181 inline 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 
189 template<>
190 inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
191     static constexpr float norm = 1. / (1 << 15);
192     *auxaccum += norm * value;
193 }
194 
195 template<>
196 inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
197     static constexpr float norm = 1. / (1 << 27);
198     *auxaccum += norm * value;
199 }
200 
201 template<>
202 inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
203     *auxaccum += value << 12;
204 }
205 
206 template<>
207 inline 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 
215 template <typename TO, typename TI, typename TV, typename TA>
216 inline 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  */
225 enum {
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  *   TA: int32_t (Q4.27) or float
242  *   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
251  *   TA: int32_t (Q4.27) or float
252  *   TV/TAV: 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  *   TA: int32_t (Q4.27) or float
263  *   TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
264  *   vol: represents a volume array.
265  *
266  *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
267  *
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  *
274  */
275 
276 template <int MIXTYPE, int NCHAN,
277         typename TO, typename TI, typename TV, typename TA, typename TAV>
278 inline 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;
294             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;
301             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;
319             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;
336             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;
343             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;
361             default:
362                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
363                 break;
364             }
365         } while (--frameCount);
366     }
367 }
368 
369 template <int MIXTYPE, int NCHAN,
370         typename TO, typename TI, typename TV, typename TA, typename TAV>
371 inline 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;
386             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;
392             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;
407             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;
422             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;
428             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;
443             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 */
454