• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 const 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 const 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  *   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 
273 template <int MIXTYPE, int NCHAN,
274         typename TO, typename TI, typename TV, typename TA, typename TAV>
275 inline 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 
366 template <int MIXTYPE, int NCHAN,
367         typename TO, typename TI, typename TV, typename TA, typename TAV>
368 inline 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