blob: a56d9cbf655ff4f325d23a637298d1d2dadba5b3 [file] [log] [blame]
Andy Hung296b7412014-06-17 15:25:47 -07001/*
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
Andy Hung936845a2021-06-08 00:09:06 -070020#include <system/audio.h>
21
Andy Hung296b7412014-06-17 15:25:47 -070022namespace android {
23
Judy Hsiao19e533c2019-08-14 16:52:51 +080024// Hack to make static_assert work in a constexpr
25// https://en.cppreference.com/w/cpp/language/if
26template <int N>
27inline constexpr bool dependent_false = false;
Andy Hung296b7412014-06-17 15:25:47 -070028
29/* MixMul is a multiplication operator to scale an audio input signal
30 * by a volume gain, with the formula:
31 *
32 * O(utput) = I(nput) * V(olume)
33 *
34 * The output, input, and volume may have different types.
35 * There are 27 variants, of which 14 are actually defined in an
36 * explicitly templated class.
37 *
38 * The following type variables and the underlying meaning:
39 *
40 * Output type TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
41 * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
42 * Volume type TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1]
43 *
44 * For high precision audio, only the <TO, TI, TV> = <float, float, float>
45 * needs to be accelerated. This is perhaps the easiest form to do quickly as well.
Chih-Hung Hsieh65025402014-12-11 13:06:46 -080046 *
47 * A generic version is NOT defined to catch any mistake of using it.
Andy Hung296b7412014-06-17 15:25:47 -070048 */
49
50template <typename TO, typename TI, typename TV>
Chih-Hung Hsieh65025402014-12-11 13:06:46 -080051TO MixMul(TI value, TV volume);
Andy Hung296b7412014-06-17 15:25:47 -070052
53template <>
54inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
55 return value * volume;
56}
57
58template <>
59inline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
60 return (value >> 12) * volume;
61}
62
63template <>
64inline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
65 return value * (volume >> 16);
66}
67
68template <>
69inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
70 return (value >> 12) * (volume >> 16);
71}
72
73template <>
74inline float MixMul<float, float, int16_t>(float value, int16_t volume) {
75 static const float norm = 1. / (1 << 12);
76 return value * volume * norm;
77}
78
79template <>
80inline float MixMul<float, float, int32_t>(float value, int32_t volume) {
81 static const float norm = 1. / (1 << 28);
82 return value * volume * norm;
83}
84
85template <>
86inline int16_t MixMul<int16_t, float, int16_t>(float value, int16_t volume) {
87 return clamp16_from_float(MixMul<float, float, int16_t>(value, volume));
88}
89
90template <>
91inline int16_t MixMul<int16_t, float, int32_t>(float value, int32_t volume) {
92 return clamp16_from_float(MixMul<float, float, int32_t>(value, volume));
93}
94
95template <>
96inline float MixMul<float, int16_t, int16_t>(int16_t value, int16_t volume) {
97 static const float norm = 1. / (1 << (15 + 12));
98 return static_cast<float>(value) * static_cast<float>(volume) * norm;
99}
100
101template <>
102inline float MixMul<float, int16_t, int32_t>(int16_t value, int32_t volume) {
103 static const float norm = 1. / (1ULL << (15 + 28));
104 return static_cast<float>(value) * static_cast<float>(volume) * norm;
105}
106
107template <>
108inline int16_t MixMul<int16_t, int16_t, int16_t>(int16_t value, int16_t volume) {
109 return clamp16(MixMul<int32_t, int16_t, int16_t>(value, volume) >> 12);
110}
111
112template <>
113inline int16_t MixMul<int16_t, int32_t, int16_t>(int32_t value, int16_t volume) {
114 return clamp16(MixMul<int32_t, int32_t, int16_t>(value, volume) >> 12);
115}
116
117template <>
118inline int16_t MixMul<int16_t, int16_t, int32_t>(int16_t value, int32_t volume) {
119 return clamp16(MixMul<int32_t, int16_t, int32_t>(value, volume) >> 12);
120}
121
122template <>
123inline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) {
124 return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12);
125}
126
Andy Hung5e58b0a2014-06-23 19:07:29 -0700127/* Required for floating point volume. Some are needed for compilation but
128 * are not needed in execution and should be removed from the final build by
129 * an optimizing compiler.
130 */
131template <>
132inline float MixMul<float, float, float>(float value, float volume) {
133 return value * volume;
134}
135
136template <>
137inline float MixMul<float, int16_t, float>(int16_t value, float volume) {
138 static const float float_from_q_15 = 1. / (1 << 15);
139 return value * volume * float_from_q_15;
140}
141
142template <>
143inline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) {
144 LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here");
145 return value * volume;
146}
147
148template <>
149inline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) {
150 LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here");
151 static const float u4_12_from_float = (1 << 12);
152 return value * volume * u4_12_from_float;
153}
154
155template <>
156inline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) {
157 LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here");
Andy Hung83ffcfb2015-06-18 17:34:40 -0700158 return clamp16_from_float(MixMul<float, int16_t, float>(value, volume));
Andy Hung5e58b0a2014-06-23 19:07:29 -0700159}
160
161template <>
162inline int16_t MixMul<int16_t, float, float>(float value, float volume) {
Andy Hung83ffcfb2015-06-18 17:34:40 -0700163 return clamp16_from_float(value * volume);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700164}
165
Andy Hung296b7412014-06-17 15:25:47 -0700166/*
167 * MixAccum is used to add into an accumulator register of a possibly different
168 * type. The TO and TI types are the same as MixMul.
169 */
170
171template <typename TO, typename TI>
172inline void MixAccum(TO *auxaccum, TI value) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800173 if (!std::is_same_v<TO, TI>) {
Glenn Kastena4daf0b2014-07-28 16:34:45 -0700174 LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
Andy Hung296b7412014-06-17 15:25:47 -0700175 sizeof(TO), sizeof(TI));
176 }
177 *auxaccum += value;
178}
179
180template<>
181inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
Andy Hung116a4982017-11-30 10:15:08 -0800182 static constexpr float norm = 1. / (1 << 15);
Andy Hung296b7412014-06-17 15:25:47 -0700183 *auxaccum += norm * value;
184}
185
186template<>
187inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
Andy Hung116a4982017-11-30 10:15:08 -0800188 static constexpr float norm = 1. / (1 << 27);
Andy Hung296b7412014-06-17 15:25:47 -0700189 *auxaccum += norm * value;
190}
191
192template<>
193inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
194 *auxaccum += value << 12;
195}
196
197template<>
198inline void MixAccum<int32_t, float>(int32_t *auxaccum, float value) {
199 *auxaccum += clampq4_27_from_float(value);
200}
201
202/* MixMulAux is just like MixMul except it combines with
203 * an accumulator operation MixAccum.
204 */
205
206template <typename TO, typename TI, typename TV, typename TA>
207inline TO MixMulAux(TI value, TV volume, TA *auxaccum) {
208 MixAccum<TA, TI>(auxaccum, value);
209 return MixMul<TO, TI, TV>(value, volume);
210}
211
212/* MIXTYPE is used to determine how the samples in the input frame
213 * are mixed with volume gain into the output frame.
214 * See the volumeRampMulti functions below for more details.
215 */
216enum {
217 MIXTYPE_MULTI,
218 MIXTYPE_MONOEXPAND,
219 MIXTYPE_MULTI_SAVEONLY,
Andy Hunge93b6b72014-07-17 21:30:53 -0700220 MIXTYPE_MULTI_MONOVOL,
221 MIXTYPE_MULTI_SAVEONLY_MONOVOL,
Judy Hsiao19e533c2019-08-14 16:52:51 +0800222 MIXTYPE_MULTI_STEREOVOL,
223 MIXTYPE_MULTI_SAVEONLY_STEREOVOL,
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800224 MIXTYPE_STEREOEXPAND,
Andy Hung296b7412014-06-17 15:25:47 -0700225};
226
227/*
Judy Hsiao19e533c2019-08-14 16:52:51 +0800228 * TODO: We should work on non-interleaved streams - the
229 * complexity of working on interleaved streams is now getting
230 * too high, and likely limits compiler optimization.
231 */
232template <int MIXTYPE, int NCHAN,
233 typename TO, typename TI, typename TV,
234 typename F>
235void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) {
Andy Hung936845a2021-06-08 00:09:06 -0700236 static_assert(NCHAN > 0 && NCHAN <= FCC_LIMIT);
Judy Hsiao19e533c2019-08-14 16:52:51 +0800237 static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800238 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700239 || MIXTYPE == MIXTYPE_STEREOEXPAND
240 || MIXTYPE == MIXTYPE_MONOEXPAND);
Judy Hsiao19e533c2019-08-14 16:52:51 +0800241 auto proc = [](auto& a, const auto& b) {
Andy Hunge0c3d792020-06-01 09:41:24 -0700242 if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700243 || MIXTYPE == MIXTYPE_STEREOEXPAND
244 || MIXTYPE == MIXTYPE_MONOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800245 a += b;
246 } else {
247 a = b;
248 }
249 };
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800250 auto inp = [&in]() -> const TI& {
Andy Hung2d8397a2020-07-14 00:56:03 -0700251 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND
252 || MIXTYPE == MIXTYPE_MONOEXPAND) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800253 return *in;
254 } else {
255 return *in++;
256 }
257 };
258
Judy Hsiao19e533c2019-08-14 16:52:51 +0800259 // HALs should only expose the canonical channel masks.
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800260 proc(*out++, f(inp(), vol[0])); // front left
Judy Hsiao19e533c2019-08-14 16:52:51 +0800261 if constexpr (NCHAN == 1) return;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800262 proc(*out++, f(inp(), vol[1])); // front right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800263 if constexpr (NCHAN == 2) return;
264 if constexpr (NCHAN == 4) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800265 proc(*out++, f(inp(), vol[0])); // back left
266 proc(*out++, f(inp(), vol[1])); // back right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800267 return;
268 }
269
270 // TODO: Precompute center volume if not ramping.
271 std::decay_t<TV> center;
272 if constexpr (std::is_floating_point_v<TV>) {
273 center = (vol[0] + vol[1]) * 0.5; // do not use divide
274 } else {
275 center = (vol[0] >> 1) + (vol[1] >> 1); // rounds to 0.
276 }
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800277 proc(*out++, f(inp(), center)); // center (or 2.1 LFE)
Judy Hsiao19e533c2019-08-14 16:52:51 +0800278 if constexpr (NCHAN == 3) return;
279 if constexpr (NCHAN == 5) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800280 proc(*out++, f(inp(), vol[0])); // back left
281 proc(*out++, f(inp(), vol[1])); // back right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800282 return;
283 }
284
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800285 proc(*out++, f(inp(), center)); // lfe
286 proc(*out++, f(inp(), vol[0])); // back left
287 proc(*out++, f(inp(), vol[1])); // back right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800288 if constexpr (NCHAN == 6) return;
289 if constexpr (NCHAN == 7) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800290 proc(*out++, f(inp(), center)); // back center
Judy Hsiao19e533c2019-08-14 16:52:51 +0800291 return;
292 }
293 // NCHAN == 8
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800294 proc(*out++, f(inp(), vol[0])); // side left
295 proc(*out++, f(inp(), vol[1])); // side right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800296}
297
298/*
Andy Hung296b7412014-06-17 15:25:47 -0700299 * The volumeRampMulti and volumeRamp functions take a MIXTYPE
300 * which indicates the per-frame mixing and accumulation strategy.
301 *
302 * MIXTYPE_MULTI:
303 * NCHAN represents number of input and output channels.
304 * TO: int32_t (Q4.27) or float
305 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
Andy Hung116a4982017-11-30 10:15:08 -0800306 * TA: int32_t (Q4.27) or float
Andy Hung296b7412014-06-17 15:25:47 -0700307 * TV: int32_t (U4.28) or int16_t (U4.12) or float
308 * vol: represents a volume array.
309 *
310 * This accumulates into the out pointer.
311 *
312 * MIXTYPE_MONOEXPAND:
313 * Single input channel. NCHAN represents number of output channels.
314 * TO: int32_t (Q4.27) or float
315 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
Andy Hung116a4982017-11-30 10:15:08 -0800316 * TA: int32_t (Q4.27) or float
317 * TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
Andy Hung296b7412014-06-17 15:25:47 -0700318 * Input channel count is 1.
319 * vol: represents volume array.
Andy Hung2d8397a2020-07-14 00:56:03 -0700320 * This uses stereo balanced volume vol[0] and vol[1].
321 * Before R, this was a full volume array but was called only for channels <= 2.
Andy Hung296b7412014-06-17 15:25:47 -0700322 *
323 * This accumulates into the out pointer.
324 *
325 * MIXTYPE_MULTI_SAVEONLY:
326 * NCHAN represents number of input and output channels.
327 * TO: int16_t (Q.15) or float
328 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
Andy Hung116a4982017-11-30 10:15:08 -0800329 * TA: int32_t (Q4.27) or float
330 * TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
Andy Hung296b7412014-06-17 15:25:47 -0700331 * vol: represents a volume array.
332 *
333 * MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
Andy Hunge93b6b72014-07-17 21:30:53 -0700334 *
335 * MIXTYPE_MULTI_MONOVOL:
336 * Same as MIXTYPE_MULTI, but uses only volume[0].
337 *
338 * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
339 * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
340 *
Judy Hsiao19e533c2019-08-14 16:52:51 +0800341 * MIXTYPE_MULTI_STEREOVOL:
342 * Same as MIXTYPE_MULTI, but uses only volume[0] and volume[1].
343 *
344 * MIXTYPE_MULTI_SAVEONLY_STEREOVOL:
345 * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0] and volume[1].
346 *
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800347 * MIXTYPE_STEREOEXPAND:
348 * Stereo input channel. NCHAN represents number of output channels.
349 * Expand size 2 array "in" and "vol" to multi-channel output. Note
350 * that the 2 array is assumed to have replicated L+R.
351 *
Andy Hung296b7412014-06-17 15:25:47 -0700352 */
353
354template <int MIXTYPE, int NCHAN,
355 typename TO, typename TI, typename TV, typename TA, typename TAV>
356inline void volumeRampMulti(TO* out, size_t frameCount,
357 const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
358{
359#ifdef ALOGVV
360 ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
361#endif
362 if (aux != NULL) {
363 do {
364 TA auxaccum = 0;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800365 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700366 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700367 for (int i = 0; i < NCHAN; ++i) {
368 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
369 vol[i] += volinc[i];
370 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800371 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700372 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700373 for (int i = 0; i < NCHAN; ++i) {
374 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
375 vol[i] += volinc[i];
376 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800377 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700378 for (int i = 0; i < NCHAN; ++i) {
379 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
380 }
381 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800382 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700383 for (int i = 0; i < NCHAN; ++i) {
384 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
385 }
386 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800387 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800388 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700389 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800390 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800391 stereoVolumeHelper<MIXTYPE, NCHAN>(
392 out, in, vol, [&auxaccum] (auto &a, const auto &b) {
393 return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
394 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700395 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800396 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800397 vol[0] += volinc[0];
398 vol[1] += volinc[1];
399 } else /* constexpr */ {
400 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700401 }
402 auxaccum /= NCHAN;
403 *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
404 vola[0] += volainc;
405 } while (--frameCount);
406 } else {
407 do {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800408 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700409 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700410 for (int i = 0; i < NCHAN; ++i) {
411 *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
412 vol[i] += volinc[i];
413 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800414 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700415 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700416 for (int i = 0; i < NCHAN; ++i) {
417 *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
418 vol[i] += volinc[i];
419 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800420 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700421 for (int i = 0; i < NCHAN; ++i) {
422 *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
423 }
424 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800425 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700426 for (int i = 0; i < NCHAN; ++i) {
427 *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
428 }
429 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800430 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800431 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700432 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800433 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800434 stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
435 return MixMul<TO, TI, TV>(a, b);
436 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700437 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800438 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800439 vol[0] += volinc[0];
440 vol[1] += volinc[1];
441 } else /* constexpr */ {
442 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700443 }
444 } while (--frameCount);
445 }
446}
447
448template <int MIXTYPE, int NCHAN,
449 typename TO, typename TI, typename TV, typename TA, typename TAV>
450inline void volumeMulti(TO* out, size_t frameCount,
451 const TI* in, TA* aux, const TV *vol, TAV vola)
452{
453#ifdef ALOGVV
454 ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
455#endif
456 if (aux != NULL) {
457 do {
458 TA auxaccum = 0;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800459 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700460 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700461 for (int i = 0; i < NCHAN; ++i) {
462 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
463 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800464 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700465 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700466 for (int i = 0; i < NCHAN; ++i) {
467 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
468 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800469 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700470 for (int i = 0; i < NCHAN; ++i) {
471 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
472 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800473 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700474 for (int i = 0; i < NCHAN; ++i) {
475 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
476 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800477 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800478 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700479 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800480 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800481 stereoVolumeHelper<MIXTYPE, NCHAN>(
482 out, in, vol, [&auxaccum] (auto &a, const auto &b) {
483 return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
484 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700485 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800486 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800487 } else /* constexpr */ {
488 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700489 }
490 auxaccum /= NCHAN;
491 *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
492 } while (--frameCount);
493 } else {
494 do {
Andy Hung2d8397a2020-07-14 00:56:03 -0700495 // ALOGD("Mixtype:%d NCHAN:%d", MIXTYPE, NCHAN);
Judy Hsiao19e533c2019-08-14 16:52:51 +0800496 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700497 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700498 for (int i = 0; i < NCHAN; ++i) {
499 *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
500 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800501 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700502 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700503 for (int i = 0; i < NCHAN; ++i) {
504 *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
505 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800506 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700507 for (int i = 0; i < NCHAN; ++i) {
508 *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
509 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800510 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700511 for (int i = 0; i < NCHAN; ++i) {
512 *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
513 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800514 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800515 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700516 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800517 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800518 stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
519 return MixMul<TO, TI, TV>(a, b);
520 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700521 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800522 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800523 } else /* constexpr */ {
524 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700525 }
526 } while (--frameCount);
527 }
528}
529
530};
531
532#endif /* ANDROID_AUDIO_MIXER_OPS_H */