1296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/*
2296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * Copyright (C) 2014 The Android Open Source Project
3296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
4296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * Licensed under the Apache License, Version 2.0 (the "License");
5296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * you may not use this file except in compliance with the License.
6296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * You may obtain a copy of the License at
7296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
8296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *      http://www.apache.org/licenses/LICENSE-2.0
9296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
10296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * Unless required by applicable law or agreed to in writing, software
11296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * distributed under the License is distributed on an "AS IS" BASIS,
12296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * See the License for the specific language governing permissions and
14296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * limitations under the License.
15296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
16296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
17296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#ifndef ANDROID_AUDIO_MIXER_OPS_H
18296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#define ANDROID_AUDIO_MIXER_OPS_H
19296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
20296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungnamespace android {
21296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
22296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/* Behavior of is_same<>::value is true if the types are identical,
23296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * false otherwise. Identical to the STL std::is_same.
24296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
25296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<typename T, typename U>
26296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungstruct is_same
27296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung{
28296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const bool value = false;
29296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung};
30296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
31296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<typename T>
32296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungstruct is_same<T, T>  // partial specialization
33296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung{
34296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const bool value = true;
35296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung};
36296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
37296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
38296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/* MixMul is a multiplication operator to scale an audio input signal
39296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * by a volume gain, with the formula:
40296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
41296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * O(utput) = I(nput) * V(olume)
42296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
43296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * The output, input, and volume may have different types.
44296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * There are 27 variants, of which 14 are actually defined in an
45296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * explicitly templated class.
46296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
47296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * The following type variables and the underlying meaning:
48296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
49296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * Output type       TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
50296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1]
51296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * Volume type       TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1]
52296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
53296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * For high precision audio, only the <TO, TI, TV> = <float, float, float>
54296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * needs to be accelerated. This is perhaps the easiest form to do quickly as well.
55650254065e7c6b5abab5e3d154f720753fe1e1cfChih-Hung Hsieh *
56650254065e7c6b5abab5e3d154f720753fe1e1cfChih-Hung Hsieh * A generic version is NOT defined to catch any mistake of using it.
57296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
58296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
59296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <typename TO, typename TI, typename TV>
60650254065e7c6b5abab5e3d154f720753fe1e1cfChih-Hung HsiehTO MixMul(TI value, TV volume);
61296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
62296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
63296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
64296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * volume;
65296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
66296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
67296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
68296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
69296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return (value >> 12) * volume;
70296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
71296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
72296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
73296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
74296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * (volume >> 16);
75296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
76296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
77296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
78296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
79296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return (value >> 12) * (volume >> 16);
80296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
81296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
82296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
83296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, float, int16_t>(float value, int16_t volume) {
84296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 12);
85296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * volume * norm;
86296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
87296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
88296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
89296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, float, int32_t>(float value, int32_t volume) {
90296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 28);
91296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * volume * norm;
92296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
93296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
94296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
95296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, float, int16_t>(float value, int16_t volume) {
96296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16_from_float(MixMul<float, float, int16_t>(value, volume));
97296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
98296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
99296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
100296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, float, int32_t>(float value, int32_t volume) {
101296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16_from_float(MixMul<float, float, int32_t>(value, volume));
102296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
103296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
104296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
105296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, int16_t, int16_t>(int16_t value, int16_t volume) {
106296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << (15 + 12));
107296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return static_cast<float>(value) * static_cast<float>(volume) * norm;
108296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
109296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
110296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
111296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, int16_t, int32_t>(int16_t value, int32_t volume) {
112296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1ULL << (15 + 28));
113296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return static_cast<float>(value) * static_cast<float>(volume) * norm;
114296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
115296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
116296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
117296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int16_t, int16_t>(int16_t value, int16_t volume) {
118296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int16_t, int16_t>(value, volume) >> 12);
119296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
120296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
121296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
122296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int32_t, int16_t>(int32_t value, int16_t volume) {
123296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int32_t, int16_t>(value, volume) >> 12);
124296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
125296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
126296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
127296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int16_t, int32_t>(int16_t value, int32_t volume) {
128296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int16_t, int32_t>(value, volume) >> 12);
129296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
130296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
131296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
132296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) {
133296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12);
134296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
135296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
1365e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung/* Required for floating point volume.  Some are needed for compilation but
1375e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung * are not needed in execution and should be removed from the final build by
1385e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung * an optimizing compiler.
1395e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung */
1405e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1415e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline float MixMul<float, float, float>(float value, float volume) {
1425e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume;
1435e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1445e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1455e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1465e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline float MixMul<float, int16_t, float>(int16_t value, float volume) {
1475e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    static const float float_from_q_15 = 1. / (1 << 15);
1485e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume * float_from_q_15;
1495e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1505e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1515e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1525e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) {
1535e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here");
1545e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume;
1555e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1565e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1575e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1585e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) {
1595e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here");
1605e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    static const float u4_12_from_float = (1 << 12);
1615e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume * u4_12_from_float;
1625e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1635e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1645e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1655e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) {
1665e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here");
16783ffcfb53b62489de9d2bd0b0277e879c3e57ab6Andy Hung    return clamp16_from_float(MixMul<float, int16_t, float>(value, volume));
1685e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1695e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1705e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1715e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int16_t MixMul<int16_t, float, float>(float value, float volume) {
17283ffcfb53b62489de9d2bd0b0277e879c3e57ab6Andy Hung    return clamp16_from_float(value * volume);
1735e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1745e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
175296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/*
176296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MixAccum is used to add into an accumulator register of a possibly different
177296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * type. The TO and TI types are the same as MixMul.
178296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
179296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
180296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <typename TO, typename TI>
181296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum(TO *auxaccum, TI value) {
182296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    if (!is_same<TO, TI>::value) {
183a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten        LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
184296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                sizeof(TO), sizeof(TI));
185296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    }
186296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += value;
187296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
188296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
189296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
190296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
191296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 15);
192296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += norm * value;
193296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
194296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
195296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
196296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
197296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 27);
198296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += norm * value;
199296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
200296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
201296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
202296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
203296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += value << 12;
204296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
205296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
206296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
207296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<int32_t, float>(int32_t *auxaccum, float value) {
208296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += clampq4_27_from_float(value);
209296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
210296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
211296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/* MixMulAux is just like MixMul except it combines with
212296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * an accumulator operation MixAccum.
213296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
214296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
215296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <typename TO, typename TI, typename TV, typename TA>
216296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline TO MixMulAux(TI value, TV volume, TA *auxaccum) {
217296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MixAccum<TA, TI>(auxaccum, value);
218296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return MixMul<TO, TI, TV>(value, volume);
219296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
220296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
221296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/* MIXTYPE is used to determine how the samples in the input frame
222296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * are mixed with volume gain into the output frame.
223296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * See the volumeRampMulti functions below for more details.
224296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
225296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungenum {
226296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MIXTYPE_MULTI,
227296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MIXTYPE_MONOEXPAND,
228296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MIXTYPE_MULTI_SAVEONLY,
229e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    MIXTYPE_MULTI_MONOVOL,
230e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    MIXTYPE_MULTI_SAVEONLY_MONOVOL,
231296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung};
232296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
233296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/*
234296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * The volumeRampMulti and volumeRamp functions take a MIXTYPE
235296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * which indicates the per-frame mixing and accumulation strategy.
236296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
237296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MIXTYPE_MULTI:
238296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   NCHAN represents number of input and output channels.
239296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TO: int32_t (Q4.27) or float
240296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
241296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TV: int32_t (U4.28) or int16_t (U4.12) or float
242296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   vol: represents a volume array.
243296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
244296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   This accumulates into the out pointer.
245296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
246296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MIXTYPE_MONOEXPAND:
247296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   Single input channel. NCHAN represents number of output channels.
248296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TO: int32_t (Q4.27) or float
249296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
250296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TV: int32_t (U4.28) or int16_t (U4.12) or float
251296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   Input channel count is 1.
252296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   vol: represents volume array.
253296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
254296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   This accumulates into the out pointer.
255296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
256296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MIXTYPE_MULTI_SAVEONLY:
257296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   NCHAN represents number of input and output channels.
258296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TO: int16_t (Q.15) or float
259296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
260296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TV: int32_t (U4.28) or int16_t (U4.12) or float
261296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   vol: represents a volume array.
262296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
263296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
264e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *
265e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung * MIXTYPE_MULTI_MONOVOL:
266e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *   Same as MIXTYPE_MULTI, but uses only volume[0].
267e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *
268e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
269e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *   Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
270e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *
271296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
272296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
273296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <int MIXTYPE, int NCHAN,
274296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        typename TO, typename TI, typename TV, typename TA, typename TAV>
275296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void volumeRampMulti(TO* out, size_t frameCount,
276296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
277296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung{
278296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#ifdef ALOGVV
279296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
280296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#endif
281296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    if (aux != NULL) {
282296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
283296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            TA auxaccum = 0;
284296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
285296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
286296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
287296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
288296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
289296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
290296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
291e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
292e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
293e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
294e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    vol[i] += volinc[i];
295e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
296e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
297e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
298296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
299296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
300296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
301296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
302296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
303296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
304e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
305296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
306e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
307296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
308e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
309e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
310e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
311e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
312e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
313e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
314e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
315296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
316296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
317296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
318296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
319296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
320296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            auxaccum /= NCHAN;
321296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
322296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            vola[0] += volainc;
323296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
324296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    } else {
325296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
326296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
327296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
328296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
329296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
330296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
331296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
332296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
333e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
334e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
335e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
336e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    vol[i] += volinc[i];
337e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
338e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
339e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
340296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
341296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
342296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
343296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
344296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
345296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
346e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
347296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
348e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
349296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
350e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
351e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
352e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
353e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
354e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
355e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
356e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
357296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
358296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
359296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
360296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
361296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
362296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
363296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    }
364296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
365296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
366296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <int MIXTYPE, int NCHAN,
367296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        typename TO, typename TI, typename TV, typename TA, typename TAV>
368296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void volumeMulti(TO* out, size_t frameCount,
369296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        const TI* in, TA* aux, const TV *vol, TAV vola)
370296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung{
371296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#ifdef ALOGVV
372296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
373296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#endif
374296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    if (aux != NULL) {
375296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
376296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            TA auxaccum = 0;
377296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
378296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
379296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
380296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
381296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
382296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
383e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
384e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
385e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
386e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
387e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
388e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
389296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
390296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
391296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
392296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
393296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
394e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
395296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
396e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
397e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
398e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
399e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
400e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
401e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
402296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
403296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
404296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
405296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
406296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
407296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
408296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            auxaccum /= NCHAN;
409296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
410296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
411296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    } else {
412296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
413296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
414296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
415296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
416296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
417296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
418296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
419e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
420e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
421e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
422e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
423e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
424e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
425296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
426296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
427296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
428296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
429296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
430e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
431296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
432e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
433e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
434e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
435e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
436e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
437e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
438296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
439296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
440296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
441296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
442296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
443296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
444296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
445296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    }
446296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
447296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
448296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung};
449296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
450296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#endif /* ANDROID_AUDIO_MIXER_OPS_H */
451