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 
57 template <typename TO, typename TI, typename TV>
58 inline TO MixMul(TI value, TV volume) {
59     COMPILE_TIME_ASSERT_FUNCTION_SCOPE(false);
60     // should not be here :-).
61     // To avoid mistakes, this template is always specialized.
62     return value * volume;
63 }
64 
65 template <>
66 inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
67     return value * volume;
68 }
69 
70 template <>
71 inline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
72     return (value >> 12) * volume;
73 }
74 
75 template <>
76 inline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
77     return value * (volume >> 16);
78 }
79 
80 template <>
81 inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
82     return (value >> 12) * (volume >> 16);
83 }
84 
85 template <>
86 inline 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 
91 template <>
92 inline 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 
97 template <>
98 inline 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 
102 template <>
103 inline 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 
107 template <>
108 inline 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 
113 template <>
114 inline 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 
119 template <>
120 inline 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 
124 template <>
125 inline 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 
129 template <>
130 inline 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 
134 template <>
135 inline 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  */
143 template <>
144 inline float MixMul<float, float, float>(float value, float volume) {
145     return value * volume;
146 }
147 
148 template <>
149 inline 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 
154 template <>
155 inline 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 
160 template <>
161 inline 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 
167 template <>
168 inline 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 
173 template <>
174 inline 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 
184 template <typename TO, typename TI>
185 inline void MixAccum(TO *auxaccum, TI value) {
186     if (!is_same<TO, TI>::value) {
187         LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
188                 sizeof(TO), sizeof(TI));
189     }
190     *auxaccum += value;
191 }
192 
193 template<>
194 inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
195     static const float norm = 1. / (1 << 15);
196     *auxaccum += norm * value;
197 }
198 
199 template<>
200 inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
201     static const float norm = 1. / (1 << 27);
202     *auxaccum += norm * value;
203 }
204 
205 template<>
206 inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
207     *auxaccum += value << 12;
208 }
209 
210 template<>
211 inline 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 
219 template <typename TO, typename TI, typename TV, typename TA>
220 inline 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  */
229 enum {
230     MIXTYPE_MULTI,
231     MIXTYPE_MONOEXPAND,
232     MIXTYPE_MULTI_SAVEONLY,
233     MIXTYPE_MULTI_MONOVOL,
234     MIXTYPE_MULTI_SAVEONLY_MONOVOL,
235 };
236 
237 /*
238  * The volumeRampMulti and volumeRamp functions take a MIXTYPE
239  * which indicates the per-frame mixing and accumulation strategy.
240  *
241  * MIXTYPE_MULTI:
242  *   NCHAN represents number of input and output channels.
243  *   TO: int32_t (Q4.27) or float
244  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
245  *   TV: int32_t (U4.28) or int16_t (U4.12) or float
246  *   vol: represents a volume array.
247  *
248  *   This accumulates into the out pointer.
249  *
250  * MIXTYPE_MONOEXPAND:
251  *   Single input channel. NCHAN represents number of output channels.
252  *   TO: int32_t (Q4.27) or float
253  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
254  *   TV: int32_t (U4.28) or int16_t (U4.12) or float
255  *   Input channel count is 1.
256  *   vol: represents volume array.
257  *
258  *   This accumulates into the out pointer.
259  *
260  * MIXTYPE_MULTI_SAVEONLY:
261  *   NCHAN represents number of input and output channels.
262  *   TO: int16_t (Q.15) or float
263  *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
264  *   TV: int32_t (U4.28) or int16_t (U4.12) or float
265  *   vol: represents a volume array.
266  *
267  *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
268  *
269  * MIXTYPE_MULTI_MONOVOL:
270  *   Same as MIXTYPE_MULTI, but uses only volume[0].
271  *
272  * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
273  *   Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
274  *
275  */
276 
277 template <int MIXTYPE, int NCHAN,
278         typename TO, typename TI, typename TV, typename TA, typename TAV>
279 inline void volumeRampMulti(TO* out, size_t frameCount,
280         const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
281 {
282 #ifdef ALOGVV
283     ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
284 #endif
285     if (aux != NULL) {
286         do {
287             TA auxaccum = 0;
288             switch (MIXTYPE) {
289             case MIXTYPE_MULTI:
290                 for (int i = 0; i < NCHAN; ++i) {
291                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
292                     vol[i] += volinc[i];
293                 }
294                 break;
295             case MIXTYPE_MONOEXPAND:
296                 for (int i = 0; i < NCHAN; ++i) {
297                     *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
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++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
305                     vol[i] += volinc[i];
306                 }
307                 break;
308             case MIXTYPE_MULTI_MONOVOL:
309                 for (int i = 0; i < NCHAN; ++i) {
310                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
311                 }
312                 vol[0] += volinc[0];
313                 break;
314             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
315                 for (int i = 0; i < NCHAN; ++i) {
316                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
317                 }
318                 vol[0] += volinc[0];
319                 break;
320             default:
321                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
322                 break;
323             }
324             auxaccum /= NCHAN;
325             *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
326             vola[0] += volainc;
327         } while (--frameCount);
328     } else {
329         do {
330             switch (MIXTYPE) {
331             case MIXTYPE_MULTI:
332                 for (int i = 0; i < NCHAN; ++i) {
333                     *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
334                     vol[i] += volinc[i];
335                 }
336                 break;
337             case MIXTYPE_MONOEXPAND:
338                 for (int i = 0; i < NCHAN; ++i) {
339                     *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
340                     vol[i] += volinc[i];
341                 }
342                 in++;
343                 break;
344             case MIXTYPE_MULTI_SAVEONLY:
345                 for (int i = 0; i < NCHAN; ++i) {
346                     *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
347                     vol[i] += volinc[i];
348                 }
349                 break;
350             case MIXTYPE_MULTI_MONOVOL:
351                 for (int i = 0; i < NCHAN; ++i) {
352                     *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
353                 }
354                 vol[0] += volinc[0];
355                 break;
356             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
357                 for (int i = 0; i < NCHAN; ++i) {
358                     *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
359                 }
360                 vol[0] += volinc[0];
361                 break;
362             default:
363                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
364                 break;
365             }
366         } while (--frameCount);
367     }
368 }
369 
370 template <int MIXTYPE, int NCHAN,
371         typename TO, typename TI, typename TV, typename TA, typename TAV>
372 inline void volumeMulti(TO* out, size_t frameCount,
373         const TI* in, TA* aux, const TV *vol, TAV vola)
374 {
375 #ifdef ALOGVV
376     ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
377 #endif
378     if (aux != NULL) {
379         do {
380             TA auxaccum = 0;
381             switch (MIXTYPE) {
382             case MIXTYPE_MULTI:
383                 for (int i = 0; i < NCHAN; ++i) {
384                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
385                 }
386                 break;
387             case MIXTYPE_MONOEXPAND:
388                 for (int i = 0; i < NCHAN; ++i) {
389                     *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
390                 }
391                 in++;
392                 break;
393             case MIXTYPE_MULTI_SAVEONLY:
394                 for (int i = 0; i < NCHAN; ++i) {
395                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
396                 }
397                 break;
398             case MIXTYPE_MULTI_MONOVOL:
399                 for (int i = 0; i < NCHAN; ++i) {
400                     *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
401                 }
402                 break;
403             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
404                 for (int i = 0; i < NCHAN; ++i) {
405                     *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
406                 }
407                 break;
408             default:
409                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
410                 break;
411             }
412             auxaccum /= NCHAN;
413             *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
414         } while (--frameCount);
415     } else {
416         do {
417             switch (MIXTYPE) {
418             case MIXTYPE_MULTI:
419                 for (int i = 0; i < NCHAN; ++i) {
420                     *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
421                 }
422                 break;
423             case MIXTYPE_MONOEXPAND:
424                 for (int i = 0; i < NCHAN; ++i) {
425                     *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
426                 }
427                 in++;
428                 break;
429             case MIXTYPE_MULTI_SAVEONLY:
430                 for (int i = 0; i < NCHAN; ++i) {
431                     *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
432                 }
433                 break;
434             case MIXTYPE_MULTI_MONOVOL:
435                 for (int i = 0; i < NCHAN; ++i) {
436                     *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
437                 }
438                 break;
439             case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
440                 for (int i = 0; i < NCHAN; ++i) {
441                     *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
442                 }
443                 break;
444             default:
445                 LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
446                 break;
447             }
448         } while (--frameCount);
449     }
450 }
451 
452 };
453 
454 #endif /* ANDROID_AUDIO_MIXER_OPS_H */
455