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
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.
55 *
56 * A generic version is NOT defined to catch any mistake of using it.
57 */
58
59template <typename TO, typename TI, typename TV>
60TO MixMul(TI value, TV volume);
61
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
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 */
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");
167    return clamp16_from_float(MixMul<float, int16_t, float>(value, volume));
168}
169
170template <>
171inline 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
180template <typename TO, typename TI>
181inline 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
189template<>
190inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
191    static const float norm = 1. / (1 << 15);
192    *auxaccum += norm * value;
193}
194
195template<>
196inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
197    static const float norm = 1. / (1 << 27);
198    *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,
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 *   TV: int32_t (U4.28) or int16_t (U4.12) or float
242 *   vol: represents a volume array.
243 *
244 *   This accumulates into the out pointer.
245 *
246 * MIXTYPE_MONOEXPAND:
247 *   Single input channel. NCHAN represents number of output channels.
248 *   TO: int32_t (Q4.27) or float
249 *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
250 *   TV: int32_t (U4.28) or int16_t (U4.12) or float
251 *   Input channel count is 1.
252 *   vol: represents volume array.
253 *
254 *   This accumulates into the out pointer.
255 *
256 * MIXTYPE_MULTI_SAVEONLY:
257 *   NCHAN represents number of input and output channels.
258 *   TO: int16_t (Q.15) or float
259 *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
260 *   TV: int32_t (U4.28) or int16_t (U4.12) or float
261 *   vol: represents a volume array.
262 *
263 *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
264 *
265 * MIXTYPE_MULTI_MONOVOL:
266 *   Same as MIXTYPE_MULTI, but uses only volume[0].
267 *
268 * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
269 *   Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
270 *
271 */
272
273template <int MIXTYPE, int NCHAN,
274        typename TO, typename TI, typename TV, typename TA, typename TAV>
275inline void volumeRampMulti(TO* out, size_t frameCount,
276        const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
277{
278#ifdef ALOGVV
279    ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
280#endif
281    if (aux != NULL) {
282        do {
283            TA auxaccum = 0;
284            switch (MIXTYPE) {
285            case MIXTYPE_MULTI:
286                for (int i = 0; i < NCHAN; ++i) {
287                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
288                    vol[i] += volinc[i];
289                }
290                break;
291            case MIXTYPE_MONOEXPAND:
292                for (int i = 0; i < NCHAN; ++i) {
293                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
294                    vol[i] += volinc[i];
295                }
296                in++;
297                break;
298            case MIXTYPE_MULTI_SAVEONLY:
299                for (int i = 0; i < NCHAN; ++i) {
300                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
301                    vol[i] += volinc[i];
302                }
303                break;
304            case MIXTYPE_MULTI_MONOVOL:
305                for (int i = 0; i < NCHAN; ++i) {
306                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
307                }
308                vol[0] += volinc[0];
309                break;
310            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
311                for (int i = 0; i < NCHAN; ++i) {
312                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
313                }
314                vol[0] += volinc[0];
315                break;
316            default:
317                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
318                break;
319            }
320            auxaccum /= NCHAN;
321            *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
322            vola[0] += volainc;
323        } while (--frameCount);
324    } else {
325        do {
326            switch (MIXTYPE) {
327            case MIXTYPE_MULTI:
328                for (int i = 0; i < NCHAN; ++i) {
329                    *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
330                    vol[i] += volinc[i];
331                }
332                break;
333            case MIXTYPE_MONOEXPAND:
334                for (int i = 0; i < NCHAN; ++i) {
335                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
336                    vol[i] += volinc[i];
337                }
338                in++;
339                break;
340            case MIXTYPE_MULTI_SAVEONLY:
341                for (int i = 0; i < NCHAN; ++i) {
342                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
343                    vol[i] += volinc[i];
344                }
345                break;
346            case MIXTYPE_MULTI_MONOVOL:
347                for (int i = 0; i < NCHAN; ++i) {
348                    *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
349                }
350                vol[0] += volinc[0];
351                break;
352            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
353                for (int i = 0; i < NCHAN; ++i) {
354                    *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
355                }
356                vol[0] += volinc[0];
357                break;
358            default:
359                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
360                break;
361            }
362        } while (--frameCount);
363    }
364}
365
366template <int MIXTYPE, int NCHAN,
367        typename TO, typename TI, typename TV, typename TA, typename TAV>
368inline void volumeMulti(TO* out, size_t frameCount,
369        const TI* in, TA* aux, const TV *vol, TAV vola)
370{
371#ifdef ALOGVV
372    ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
373#endif
374    if (aux != NULL) {
375        do {
376            TA auxaccum = 0;
377            switch (MIXTYPE) {
378            case MIXTYPE_MULTI:
379                for (int i = 0; i < NCHAN; ++i) {
380                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
381                }
382                break;
383            case MIXTYPE_MONOEXPAND:
384                for (int i = 0; i < NCHAN; ++i) {
385                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
386                }
387                in++;
388                break;
389            case MIXTYPE_MULTI_SAVEONLY:
390                for (int i = 0; i < NCHAN; ++i) {
391                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
392                }
393                break;
394            case MIXTYPE_MULTI_MONOVOL:
395                for (int i = 0; i < NCHAN; ++i) {
396                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
397                }
398                break;
399            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
400                for (int i = 0; i < NCHAN; ++i) {
401                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
402                }
403                break;
404            default:
405                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
406                break;
407            }
408            auxaccum /= NCHAN;
409            *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
410        } while (--frameCount);
411    } else {
412        do {
413            switch (MIXTYPE) {
414            case MIXTYPE_MULTI:
415                for (int i = 0; i < NCHAN; ++i) {
416                    *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
417                }
418                break;
419            case MIXTYPE_MONOEXPAND:
420                for (int i = 0; i < NCHAN; ++i) {
421                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
422                }
423                in++;
424                break;
425            case MIXTYPE_MULTI_SAVEONLY:
426                for (int i = 0; i < NCHAN; ++i) {
427                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
428                }
429                break;
430            case MIXTYPE_MULTI_MONOVOL:
431                for (int i = 0; i < NCHAN; ++i) {
432                    *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
433                }
434                break;
435            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
436                for (int i = 0; i < NCHAN; ++i) {
437                    *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
438                }
439                break;
440            default:
441                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
442                break;
443            }
444        } while (--frameCount);
445    }
446}
447
448};
449
450#endif /* ANDROID_AUDIO_MIXER_OPS_H */
451