blob: 8d374c95e5fd7365b13afdeeb4ee4b9b3a417400 [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
20namespace android {
21
Judy Hsiao19e533c2019-08-14 16:52:51 +080022// Hack to make static_assert work in a constexpr
23// https://en.cppreference.com/w/cpp/language/if
24template <int N>
25inline constexpr bool dependent_false = false;
Andy Hung296b7412014-06-17 15:25:47 -070026
27/* MixMul is a multiplication operator to scale an audio input signal
28 * by a volume gain, with the formula:
29 *
30 * O(utput) = I(nput) * V(olume)
31 *
32 * The output, input, and volume may have different types.
33 * There are 27 variants, of which 14 are actually defined in an
34 * explicitly templated class.
35 *
36 * The following type variables and the underlying meaning:
37 *
38 * Output type TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
39 * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
40 * Volume type TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1]
41 *
42 * For high precision audio, only the <TO, TI, TV> = <float, float, float>
43 * needs to be accelerated. This is perhaps the easiest form to do quickly as well.
Chih-Hung Hsieh65025402014-12-11 13:06:46 -080044 *
45 * A generic version is NOT defined to catch any mistake of using it.
Andy Hung296b7412014-06-17 15:25:47 -070046 */
47
48template <typename TO, typename TI, typename TV>
Chih-Hung Hsieh65025402014-12-11 13:06:46 -080049TO MixMul(TI value, TV volume);
Andy Hung296b7412014-06-17 15:25:47 -070050
51template <>
52inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
53 return value * volume;
54}
55
56template <>
57inline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
58 return (value >> 12) * volume;
59}
60
61template <>
62inline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
63 return value * (volume >> 16);
64}
65
66template <>
67inline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
68 return (value >> 12) * (volume >> 16);
69}
70
71template <>
72inline float MixMul<float, float, int16_t>(float value, int16_t volume) {
73 static const float norm = 1. / (1 << 12);
74 return value * volume * norm;
75}
76
77template <>
78inline float MixMul<float, float, int32_t>(float value, int32_t volume) {
79 static const float norm = 1. / (1 << 28);
80 return value * volume * norm;
81}
82
83template <>
84inline int16_t MixMul<int16_t, float, int16_t>(float value, int16_t volume) {
85 return clamp16_from_float(MixMul<float, float, int16_t>(value, volume));
86}
87
88template <>
89inline int16_t MixMul<int16_t, float, int32_t>(float value, int32_t volume) {
90 return clamp16_from_float(MixMul<float, float, int32_t>(value, volume));
91}
92
93template <>
94inline float MixMul<float, int16_t, int16_t>(int16_t value, int16_t volume) {
95 static const float norm = 1. / (1 << (15 + 12));
96 return static_cast<float>(value) * static_cast<float>(volume) * norm;
97}
98
99template <>
100inline float MixMul<float, int16_t, int32_t>(int16_t value, int32_t volume) {
101 static const float norm = 1. / (1ULL << (15 + 28));
102 return static_cast<float>(value) * static_cast<float>(volume) * norm;
103}
104
105template <>
106inline int16_t MixMul<int16_t, int16_t, int16_t>(int16_t value, int16_t volume) {
107 return clamp16(MixMul<int32_t, int16_t, int16_t>(value, volume) >> 12);
108}
109
110template <>
111inline int16_t MixMul<int16_t, int32_t, int16_t>(int32_t value, int16_t volume) {
112 return clamp16(MixMul<int32_t, int32_t, int16_t>(value, volume) >> 12);
113}
114
115template <>
116inline int16_t MixMul<int16_t, int16_t, int32_t>(int16_t value, int32_t volume) {
117 return clamp16(MixMul<int32_t, int16_t, int32_t>(value, volume) >> 12);
118}
119
120template <>
121inline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) {
122 return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12);
123}
124
Andy Hung5e58b0a2014-06-23 19:07:29 -0700125/* Required for floating point volume. Some are needed for compilation but
126 * are not needed in execution and should be removed from the final build by
127 * an optimizing compiler.
128 */
129template <>
130inline float MixMul<float, float, float>(float value, float volume) {
131 return value * volume;
132}
133
134template <>
135inline float MixMul<float, int16_t, float>(int16_t value, float volume) {
136 static const float float_from_q_15 = 1. / (1 << 15);
137 return value * volume * float_from_q_15;
138}
139
140template <>
141inline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) {
142 LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here");
143 return value * volume;
144}
145
146template <>
147inline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) {
148 LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here");
149 static const float u4_12_from_float = (1 << 12);
150 return value * volume * u4_12_from_float;
151}
152
153template <>
154inline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) {
155 LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here");
Andy Hung83ffcfb2015-06-18 17:34:40 -0700156 return clamp16_from_float(MixMul<float, int16_t, float>(value, volume));
Andy Hung5e58b0a2014-06-23 19:07:29 -0700157}
158
159template <>
160inline int16_t MixMul<int16_t, float, float>(float value, float volume) {
Andy Hung83ffcfb2015-06-18 17:34:40 -0700161 return clamp16_from_float(value * volume);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700162}
163
Andy Hung296b7412014-06-17 15:25:47 -0700164/*
165 * MixAccum is used to add into an accumulator register of a possibly different
166 * type. The TO and TI types are the same as MixMul.
167 */
168
169template <typename TO, typename TI>
170inline void MixAccum(TO *auxaccum, TI value) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800171 if (!std::is_same_v<TO, TI>) {
Glenn Kastena4daf0b2014-07-28 16:34:45 -0700172 LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
Andy Hung296b7412014-06-17 15:25:47 -0700173 sizeof(TO), sizeof(TI));
174 }
175 *auxaccum += value;
176}
177
178template<>
179inline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
Andy Hung116a4982017-11-30 10:15:08 -0800180 static constexpr float norm = 1. / (1 << 15);
Andy Hung296b7412014-06-17 15:25:47 -0700181 *auxaccum += norm * value;
182}
183
184template<>
185inline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
Andy Hung116a4982017-11-30 10:15:08 -0800186 static constexpr float norm = 1. / (1 << 27);
Andy Hung296b7412014-06-17 15:25:47 -0700187 *auxaccum += norm * value;
188}
189
190template<>
191inline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
192 *auxaccum += value << 12;
193}
194
195template<>
196inline void MixAccum<int32_t, float>(int32_t *auxaccum, float value) {
197 *auxaccum += clampq4_27_from_float(value);
198}
199
200/* MixMulAux is just like MixMul except it combines with
201 * an accumulator operation MixAccum.
202 */
203
204template <typename TO, typename TI, typename TV, typename TA>
205inline TO MixMulAux(TI value, TV volume, TA *auxaccum) {
206 MixAccum<TA, TI>(auxaccum, value);
207 return MixMul<TO, TI, TV>(value, volume);
208}
209
210/* MIXTYPE is used to determine how the samples in the input frame
211 * are mixed with volume gain into the output frame.
212 * See the volumeRampMulti functions below for more details.
213 */
214enum {
215 MIXTYPE_MULTI,
216 MIXTYPE_MONOEXPAND,
217 MIXTYPE_MULTI_SAVEONLY,
Andy Hunge93b6b72014-07-17 21:30:53 -0700218 MIXTYPE_MULTI_MONOVOL,
219 MIXTYPE_MULTI_SAVEONLY_MONOVOL,
Judy Hsiao19e533c2019-08-14 16:52:51 +0800220 MIXTYPE_MULTI_STEREOVOL,
221 MIXTYPE_MULTI_SAVEONLY_STEREOVOL,
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800222 MIXTYPE_STEREOEXPAND,
Andy Hung296b7412014-06-17 15:25:47 -0700223};
224
225/*
Judy Hsiao19e533c2019-08-14 16:52:51 +0800226 * TODO: We should work on non-interleaved streams - the
227 * complexity of working on interleaved streams is now getting
228 * too high, and likely limits compiler optimization.
229 */
230template <int MIXTYPE, int NCHAN,
231 typename TO, typename TI, typename TV,
232 typename F>
233void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) {
234 static_assert(NCHAN > 0 && NCHAN <= 8);
235 static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800236 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700237 || MIXTYPE == MIXTYPE_STEREOEXPAND
238 || MIXTYPE == MIXTYPE_MONOEXPAND);
Judy Hsiao19e533c2019-08-14 16:52:51 +0800239 auto proc = [](auto& a, const auto& b) {
Andy Hunge0c3d792020-06-01 09:41:24 -0700240 if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700241 || MIXTYPE == MIXTYPE_STEREOEXPAND
242 || MIXTYPE == MIXTYPE_MONOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800243 a += b;
244 } else {
245 a = b;
246 }
247 };
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800248 auto inp = [&in]() -> const TI& {
Andy Hung2d8397a2020-07-14 00:56:03 -0700249 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND
250 || MIXTYPE == MIXTYPE_MONOEXPAND) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800251 return *in;
252 } else {
253 return *in++;
254 }
255 };
256
Judy Hsiao19e533c2019-08-14 16:52:51 +0800257 // HALs should only expose the canonical channel masks.
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800258 proc(*out++, f(inp(), vol[0])); // front left
Judy Hsiao19e533c2019-08-14 16:52:51 +0800259 if constexpr (NCHAN == 1) return;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800260 proc(*out++, f(inp(), vol[1])); // front right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800261 if constexpr (NCHAN == 2) return;
262 if constexpr (NCHAN == 4) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800263 proc(*out++, f(inp(), vol[0])); // back left
264 proc(*out++, f(inp(), vol[1])); // back right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800265 return;
266 }
267
268 // TODO: Precompute center volume if not ramping.
269 std::decay_t<TV> center;
270 if constexpr (std::is_floating_point_v<TV>) {
271 center = (vol[0] + vol[1]) * 0.5; // do not use divide
272 } else {
273 center = (vol[0] >> 1) + (vol[1] >> 1); // rounds to 0.
274 }
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800275 proc(*out++, f(inp(), center)); // center (or 2.1 LFE)
Judy Hsiao19e533c2019-08-14 16:52:51 +0800276 if constexpr (NCHAN == 3) return;
277 if constexpr (NCHAN == 5) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800278 proc(*out++, f(inp(), vol[0])); // back left
279 proc(*out++, f(inp(), vol[1])); // back right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800280 return;
281 }
282
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800283 proc(*out++, f(inp(), center)); // lfe
284 proc(*out++, f(inp(), vol[0])); // back left
285 proc(*out++, f(inp(), vol[1])); // back right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800286 if constexpr (NCHAN == 6) return;
287 if constexpr (NCHAN == 7) {
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800288 proc(*out++, f(inp(), center)); // back center
Judy Hsiao19e533c2019-08-14 16:52:51 +0800289 return;
290 }
291 // NCHAN == 8
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800292 proc(*out++, f(inp(), vol[0])); // side left
293 proc(*out++, f(inp(), vol[1])); // side right
Judy Hsiao19e533c2019-08-14 16:52:51 +0800294}
295
296/*
Andy Hung296b7412014-06-17 15:25:47 -0700297 * The volumeRampMulti and volumeRamp functions take a MIXTYPE
298 * which indicates the per-frame mixing and accumulation strategy.
299 *
300 * MIXTYPE_MULTI:
301 * NCHAN represents number of input and output channels.
302 * TO: int32_t (Q4.27) or float
303 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
Andy Hung116a4982017-11-30 10:15:08 -0800304 * TA: int32_t (Q4.27) or float
Andy Hung296b7412014-06-17 15:25:47 -0700305 * TV: int32_t (U4.28) or int16_t (U4.12) or float
306 * vol: represents a volume array.
307 *
308 * This accumulates into the out pointer.
309 *
310 * MIXTYPE_MONOEXPAND:
311 * Single input channel. NCHAN represents number of output channels.
312 * TO: int32_t (Q4.27) or float
313 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
Andy Hung116a4982017-11-30 10:15:08 -0800314 * TA: int32_t (Q4.27) or float
315 * TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
Andy Hung296b7412014-06-17 15:25:47 -0700316 * Input channel count is 1.
317 * vol: represents volume array.
Andy Hung2d8397a2020-07-14 00:56:03 -0700318 * This uses stereo balanced volume vol[0] and vol[1].
319 * Before R, this was a full volume array but was called only for channels <= 2.
Andy Hung296b7412014-06-17 15:25:47 -0700320 *
321 * This accumulates into the out pointer.
322 *
323 * MIXTYPE_MULTI_SAVEONLY:
324 * NCHAN represents number of input and output channels.
325 * TO: int16_t (Q.15) or float
326 * TI: int32_t (Q4.27) or int16_t (Q0.15) or float
Andy Hung116a4982017-11-30 10:15:08 -0800327 * TA: int32_t (Q4.27) or float
328 * TV/TAV: int32_t (U4.28) or int16_t (U4.12) or float
Andy Hung296b7412014-06-17 15:25:47 -0700329 * vol: represents a volume array.
330 *
331 * MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
Andy Hunge93b6b72014-07-17 21:30:53 -0700332 *
333 * MIXTYPE_MULTI_MONOVOL:
334 * Same as MIXTYPE_MULTI, but uses only volume[0].
335 *
336 * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
337 * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
338 *
Judy Hsiao19e533c2019-08-14 16:52:51 +0800339 * MIXTYPE_MULTI_STEREOVOL:
340 * Same as MIXTYPE_MULTI, but uses only volume[0] and volume[1].
341 *
342 * MIXTYPE_MULTI_SAVEONLY_STEREOVOL:
343 * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0] and volume[1].
344 *
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800345 * MIXTYPE_STEREOEXPAND:
346 * Stereo input channel. NCHAN represents number of output channels.
347 * Expand size 2 array "in" and "vol" to multi-channel output. Note
348 * that the 2 array is assumed to have replicated L+R.
349 *
Andy Hung296b7412014-06-17 15:25:47 -0700350 */
351
352template <int MIXTYPE, int NCHAN,
353 typename TO, typename TI, typename TV, typename TA, typename TAV>
354inline void volumeRampMulti(TO* out, size_t frameCount,
355 const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
356{
357#ifdef ALOGVV
358 ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
359#endif
360 if (aux != NULL) {
361 do {
362 TA auxaccum = 0;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800363 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700364 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700365 for (int i = 0; i < NCHAN; ++i) {
366 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
367 vol[i] += volinc[i];
368 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800369 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700370 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700371 for (int i = 0; i < NCHAN; ++i) {
372 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
373 vol[i] += volinc[i];
374 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800375 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700376 for (int i = 0; i < NCHAN; ++i) {
377 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
378 }
379 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800380 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700381 for (int i = 0; i < NCHAN; ++i) {
382 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
383 }
384 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800385 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800386 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700387 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800388 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800389 stereoVolumeHelper<MIXTYPE, NCHAN>(
390 out, in, vol, [&auxaccum] (auto &a, const auto &b) {
391 return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
392 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700393 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800394 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800395 vol[0] += volinc[0];
396 vol[1] += volinc[1];
397 } else /* constexpr */ {
398 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700399 }
400 auxaccum /= NCHAN;
401 *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
402 vola[0] += volainc;
403 } while (--frameCount);
404 } else {
405 do {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800406 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700407 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700408 for (int i = 0; i < NCHAN; ++i) {
409 *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
410 vol[i] += volinc[i];
411 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800412 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700413 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700414 for (int i = 0; i < NCHAN; ++i) {
415 *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
416 vol[i] += volinc[i];
417 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800418 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700419 for (int i = 0; i < NCHAN; ++i) {
420 *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
421 }
422 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800423 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700424 for (int i = 0; i < NCHAN; ++i) {
425 *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
426 }
427 vol[0] += volinc[0];
Judy Hsiao19e533c2019-08-14 16:52:51 +0800428 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800429 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700430 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800431 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800432 stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
433 return MixMul<TO, TI, TV>(a, b);
434 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700435 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800436 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800437 vol[0] += volinc[0];
438 vol[1] += volinc[1];
439 } else /* constexpr */ {
440 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700441 }
442 } while (--frameCount);
443 }
444}
445
446template <int MIXTYPE, int NCHAN,
447 typename TO, typename TI, typename TV, typename TA, typename TAV>
448inline void volumeMulti(TO* out, size_t frameCount,
449 const TI* in, TA* aux, const TV *vol, TAV vola)
450{
451#ifdef ALOGVV
452 ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
453#endif
454 if (aux != NULL) {
455 do {
456 TA auxaccum = 0;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800457 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700458 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700459 for (int i = 0; i < NCHAN; ++i) {
460 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
461 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800462 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700463 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700464 for (int i = 0; i < NCHAN; ++i) {
465 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
466 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800467 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700468 for (int i = 0; i < NCHAN; ++i) {
469 *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
470 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800471 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700472 for (int i = 0; i < NCHAN; ++i) {
473 *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
474 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800475 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800476 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700477 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800478 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800479 stereoVolumeHelper<MIXTYPE, NCHAN>(
480 out, in, vol, [&auxaccum] (auto &a, const auto &b) {
481 return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
482 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700483 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800484 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800485 } else /* constexpr */ {
486 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700487 }
488 auxaccum /= NCHAN;
489 *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
490 } while (--frameCount);
491 } else {
492 do {
Andy Hung2d8397a2020-07-14 00:56:03 -0700493 // ALOGD("Mixtype:%d NCHAN:%d", MIXTYPE, NCHAN);
Judy Hsiao19e533c2019-08-14 16:52:51 +0800494 if constexpr (MIXTYPE == MIXTYPE_MULTI) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700495 static_assert(NCHAN <= 2);
Andy Hung296b7412014-06-17 15:25:47 -0700496 for (int i = 0; i < NCHAN; ++i) {
497 *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
498 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800499 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) {
Andy Hung2d8397a2020-07-14 00:56:03 -0700500 static_assert(NCHAN <= 2);
Andy Hunge93b6b72014-07-17 21:30:53 -0700501 for (int i = 0; i < NCHAN; ++i) {
502 *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
503 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800504 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700505 for (int i = 0; i < NCHAN; ++i) {
506 *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
507 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800508 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700509 for (int i = 0; i < NCHAN; ++i) {
510 *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
511 }
Judy Hsiao19e533c2019-08-14 16:52:51 +0800512 } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800513 || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
Andy Hung2d8397a2020-07-14 00:56:03 -0700514 || MIXTYPE == MIXTYPE_MONOEXPAND
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800515 || MIXTYPE == MIXTYPE_STEREOEXPAND) {
Judy Hsiao19e533c2019-08-14 16:52:51 +0800516 stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
517 return MixMul<TO, TI, TV>(a, b);
518 });
Andy Hung2d8397a2020-07-14 00:56:03 -0700519 if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) in += 1;
Judy Hsiaoc5cf9e22019-08-15 11:32:02 +0800520 if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
Judy Hsiao19e533c2019-08-14 16:52:51 +0800521 } else /* constexpr */ {
522 static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
Andy Hung296b7412014-06-17 15:25:47 -0700523 }
524 } while (--frameCount);
525 }
526}
527
528};
529
530#endif /* ANDROID_AUDIO_MIXER_OPS_H */