AudioMixerOps.h revision 5e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020
1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/*
2c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Copyright (C) 2014 The Android Open Source Project
3c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
4c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Licensed under the Apache License, Version 2.0 (the "License");
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * you may not use this file except in compliance with the License.
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * You may obtain a copy of the License at
7c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *      http://www.apache.org/licenses/LICENSE-2.0
9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Unless required by applicable law or agreed to in writing, software
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * distributed under the License is distributed on an "AS IS" BASIS,
12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * See the License for the specific language governing permissions and
1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * limitations under the License.
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch */
16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
17c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#ifndef ANDROID_AUDIO_MIXER_OPS_H
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#define ANDROID_AUDIO_MIXER_OPS_H
19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace android {
21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/* Behavior of is_same<>::value is true if the types are identical,
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * false otherwise. Identical to the STL std::is_same.
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch */
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate<typename T, typename U>
26c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstruct is_same
27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch{
28c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    static const bool value = false;
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch};
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate<typename T>
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstruct is_same<T, T>  // partial specialization
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    static const bool value = true;
35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch};
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/* MixMul is a multiplication operator to scale an audio input signal
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * by a volume gain, with the formula:
40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * O(utput) = I(nput) * V(olume)
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * The output, input, and volume may have different types.
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * There are 27 variants, of which 14 are actually defined in an
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * explicitly templated class.
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * The following type variables and the underlying meaning:
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Output type       TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Volume type       TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1]
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch *
53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * For high precision audio, only the <TO, TI, TV> = <float, float, float>
54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * needs to be accelerated. This is perhaps the easiest form to do quickly as well.
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <typename TO, typename TI, typename TV>
58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline TO MixMul(TI value, TV volume) {
59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(false);
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // should not be here :-).
61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // To avoid mistakes, this template is always specialized.
62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return value * volume;
63c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
64c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
65c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <>
66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return value * volume;
68c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <>
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
72c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return (value >> 12) * volume;
73c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtemplate <>
76c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochinline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return value * (volume >> 16);
78c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
80template <>
81inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
82    return (value >> 12) * (volume >> 16);
83}
84
85template <>
86inline 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
91template <>
92inline 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
97template <>
98inline 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
102template <>
103inline 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
107template <>
108inline 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
113template <>
114inline 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
119template <>
120inline 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
124template <>
125inline 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
129template <>
130inline 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
134template <>
135inline 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 */
143template <>
144inline float MixMul<float, float, float>(float value, float volume) {
145    return value * volume;
146}
147
148template <>
149inline 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
154template <>
155inline 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
160template <>
161inline 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
167template <>
168inline 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
173template <>
174inline 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
184template <typename TO, typename TI>
185inline void MixAccum(TO *auxaccum, TI value) {
186    if (!is_same<TO, TI>::value) {
187        LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %d %d\n",
188                sizeof(TO), sizeof(TI));
189    }
190    *auxaccum += value;
191}
192
193template<>
194inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
195    static const float norm = 1. / (1 << 15);
196    *auxaccum += norm * value;
197}
198
199template<>
200inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
201    static const float norm = 1. / (1 << 27);
202    *auxaccum += norm * value;
203}
204
205template<>
206inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
207    *auxaccum += value << 12;
208}
209
210template<>
211inline 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
219template <typename TO, typename TI, typename TV, typename TA>
220inline 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 */
229enum {
230    MIXTYPE_MULTI,
231    MIXTYPE_MONOEXPAND,
232    MIXTYPE_MULTI_SAVEONLY,
233};
234
235/*
236 * The volumeRampMulti and volumeRamp functions take a MIXTYPE
237 * which indicates the per-frame mixing and accumulation strategy.
238 *
239 * MIXTYPE_MULTI:
240 *   NCHAN represents number of input and output channels.
241 *   TO: int32_t (Q4.27) or float
242 *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
243 *   TV: int32_t (U4.28) or int16_t (U4.12) or float
244 *   vol: represents a volume array.
245 *
246 *   This accumulates into the out pointer.
247 *
248 * MIXTYPE_MONOEXPAND:
249 *   Single input channel. NCHAN represents number of output channels.
250 *   TO: int32_t (Q4.27) or float
251 *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
252 *   TV: 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 *   TV: int32_t (U4.28) or int16_t (U4.12) or float
263 *   vol: represents a volume array.
264 *
265 *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
266 */
267
268template <int MIXTYPE, int NCHAN,
269        typename TO, typename TI, typename TV, typename TA, typename TAV>
270inline void volumeRampMulti(TO* out, size_t frameCount,
271        const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
272{
273#ifdef ALOGVV
274    ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
275#endif
276    if (aux != NULL) {
277        do {
278            TA auxaccum = 0;
279            switch (MIXTYPE) {
280            case MIXTYPE_MULTI:
281                for (int i = 0; i < NCHAN; ++i) {
282                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
283                    vol[i] += volinc[i];
284                }
285                break;
286            case MIXTYPE_MULTI_SAVEONLY:
287                for (int i = 0; i < NCHAN; ++i) {
288                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
289                    vol[i] += volinc[i];
290                }
291                break;
292            case MIXTYPE_MONOEXPAND:
293                for (int i = 0; i < NCHAN; ++i) {
294                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
295                    vol[i] += volinc[i];
296                }
297                in++;
298                break;
299            default:
300                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
301                break;
302            }
303            auxaccum /= NCHAN;
304            *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
305            vola[0] += volainc;
306        } while (--frameCount);
307    } else {
308        do {
309            switch (MIXTYPE) {
310            case MIXTYPE_MULTI:
311                for (int i = 0; i < NCHAN; ++i) {
312                    *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
313                    vol[i] += volinc[i];
314                }
315                break;
316            case MIXTYPE_MULTI_SAVEONLY:
317                for (int i = 0; i < NCHAN; ++i) {
318                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
319                    vol[i] += volinc[i];
320                }
321                break;
322            case MIXTYPE_MONOEXPAND:
323                for (int i = 0; i < NCHAN; ++i) {
324                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
325                    vol[i] += volinc[i];
326                }
327                in++;
328                break;
329            default:
330                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
331                break;
332            }
333        } while (--frameCount);
334    }
335}
336
337template <int MIXTYPE, int NCHAN,
338        typename TO, typename TI, typename TV, typename TA, typename TAV>
339inline void volumeMulti(TO* out, size_t frameCount,
340        const TI* in, TA* aux, const TV *vol, TAV vola)
341{
342#ifdef ALOGVV
343    ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
344#endif
345    if (aux != NULL) {
346        do {
347            TA auxaccum = 0;
348            switch (MIXTYPE) {
349            case MIXTYPE_MULTI:
350                for (int i = 0; i < NCHAN; ++i) {
351                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
352                }
353                break;
354            case MIXTYPE_MULTI_SAVEONLY:
355                for (int i = 0; i < NCHAN; ++i) {
356                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
357                }
358                break;
359            case MIXTYPE_MONOEXPAND:
360                for (int i = 0; i < NCHAN; ++i) {
361                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
362                }
363                in++;
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_MULTI_SAVEONLY:
381                for (int i = 0; i < NCHAN; ++i) {
382                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
383                }
384                break;
385            case MIXTYPE_MONOEXPAND:
386                for (int i = 0; i < NCHAN; ++i) {
387                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
388                }
389                in++;
390                break;
391            default:
392                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
393                break;
394            }
395        } while (--frameCount);
396    }
397}
398
399};
400
401#endif /* ANDROID_AUDIO_MIXER_OPS_H */
402