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.
55296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
56296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
57296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <typename TO, typename TI, typename TV>
58296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline TO MixMul(TI value, TV volume) {
59296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(false);
60296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    // should not be here :-).
61296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    // To avoid mistakes, this template is always specialized.
62296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * volume;
63296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
64296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
65296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
66296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) {
67296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * volume;
68296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
69296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
70296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
71296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int32_t, int16_t>(int32_t value, int16_t volume) {
72296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return (value >> 12) * volume;
73296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
74296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
75296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
76296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int16_t, int32_t>(int16_t value, int32_t volume) {
77296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * (volume >> 16);
78296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
79296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
80296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
81296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int32_t MixMul<int32_t, int32_t, int32_t>(int32_t value, int32_t volume) {
82296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return (value >> 12) * (volume >> 16);
83296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
84296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
85296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
86296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, float, int16_t>(float value, int16_t volume) {
87296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 12);
88296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * volume * norm;
89296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
90296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
91296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
92296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, float, int32_t>(float value, int32_t volume) {
93296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 28);
94296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return value * volume * norm;
95296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
96296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
97296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
98296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, float, int16_t>(float value, int16_t volume) {
99296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16_from_float(MixMul<float, float, int16_t>(value, volume));
100296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
101296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
102296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
103296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, float, int32_t>(float value, int32_t volume) {
104296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16_from_float(MixMul<float, float, int32_t>(value, volume));
105296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
106296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
107296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
108296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, int16_t, int16_t>(int16_t value, int16_t volume) {
109296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << (15 + 12));
110296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return static_cast<float>(value) * static_cast<float>(volume) * norm;
111296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
112296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
113296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
114296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline float MixMul<float, int16_t, int32_t>(int16_t value, int32_t volume) {
115296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1ULL << (15 + 28));
116296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return static_cast<float>(value) * static_cast<float>(volume) * norm;
117296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
118296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
119296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
120296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int16_t, int16_t>(int16_t value, int16_t volume) {
121296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int16_t, int16_t>(value, volume) >> 12);
122296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
123296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
124296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
125296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int32_t, int16_t>(int32_t value, int16_t volume) {
126296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int32_t, int16_t>(value, volume) >> 12);
127296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
128296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
129296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
130296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int16_t, int32_t>(int16_t value, int32_t volume) {
131296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int16_t, int32_t>(value, volume) >> 12);
132296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
133296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
134296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <>
135296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) {
136296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12);
137296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
138296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
1395e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung/* Required for floating point volume.  Some are needed for compilation but
1405e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung * are not needed in execution and should be removed from the final build by
1415e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung * an optimizing compiler.
1425e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung */
1435e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1445e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline float MixMul<float, float, float>(float value, float volume) {
1455e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume;
1465e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1475e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1485e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1495e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline float MixMul<float, int16_t, float>(int16_t value, float volume) {
1505e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    static const float float_from_q_15 = 1. / (1 << 15);
1515e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume * float_from_q_15;
1525e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1535e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1545e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1555e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) {
1565e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here");
1575e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume;
1585e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1595e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1605e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1615e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) {
1625e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here");
1635e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    static const float u4_12_from_float = (1 << 12);
1645e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume * u4_12_from_float;
1655e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1665e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1675e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1685e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) {
1695e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here");
1705e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume;
1715e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1725e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
1735e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungtemplate <>
1745e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hunginline int16_t MixMul<int16_t, float, float>(float value, float volume) {
1755e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    static const float q_15_from_float = (1 << 15);
1765e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    return value * volume * q_15_from_float;
1775e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung}
1785e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
179296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/*
180296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MixAccum is used to add into an accumulator register of a possibly different
181296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * type. The TO and TI types are the same as MixMul.
182296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
183296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
184296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <typename TO, typename TI>
185296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum(TO *auxaccum, TI value) {
186296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    if (!is_same<TO, TI>::value) {
187a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten        LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n",
188296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                sizeof(TO), sizeof(TI));
189296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    }
190296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += value;
191296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
192296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
193296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
194296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<float, int16_t>(float *auxaccum, int16_t value) {
195296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 15);
196296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += norm * value;
197296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
198296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
199296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
200296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<float, int32_t>(float *auxaccum, int32_t value) {
201296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static const float norm = 1. / (1 << 27);
202296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += norm * value;
203296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
204296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
205296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
206296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<int32_t, int16_t>(int32_t *auxaccum, int16_t value) {
207296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += value << 12;
208296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
209296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
210296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate<>
211296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void MixAccum<int32_t, float>(int32_t *auxaccum, float value) {
212296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    *auxaccum += clampq4_27_from_float(value);
213296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
214296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
215296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/* MixMulAux is just like MixMul except it combines with
216296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * an accumulator operation MixAccum.
217296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
218296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
219296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <typename TO, typename TI, typename TV, typename TA>
220296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline TO MixMulAux(TI value, TV volume, TA *auxaccum) {
221296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MixAccum<TA, TI>(auxaccum, value);
222296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    return MixMul<TO, TI, TV>(value, volume);
223296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
224296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
225296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/* MIXTYPE is used to determine how the samples in the input frame
226296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * are mixed with volume gain into the output frame.
227296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * See the volumeRampMulti functions below for more details.
228296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
229296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungenum {
230296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MIXTYPE_MULTI,
231296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MIXTYPE_MONOEXPAND,
232296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    MIXTYPE_MULTI_SAVEONLY,
233e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    MIXTYPE_MULTI_MONOVOL,
234e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    MIXTYPE_MULTI_SAVEONLY_MONOVOL,
235296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung};
236296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
237296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung/*
238296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * The volumeRampMulti and volumeRamp functions take a MIXTYPE
239296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * which indicates the per-frame mixing and accumulation strategy.
240296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
241296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MIXTYPE_MULTI:
242296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   NCHAN represents number of input and output channels.
243296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TO: int32_t (Q4.27) or float
244296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
245296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TV: int32_t (U4.28) or int16_t (U4.12) or float
246296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   vol: represents a volume array.
247296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
248296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   This accumulates into the out pointer.
249296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
250296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MIXTYPE_MONOEXPAND:
251296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   Single input channel. NCHAN represents number of output channels.
252296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TO: int32_t (Q4.27) or float
253296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
254296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TV: int32_t (U4.28) or int16_t (U4.12) or float
255296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   Input channel count is 1.
256296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   vol: represents volume array.
257296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
258296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   This accumulates into the out pointer.
259296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
260296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung * MIXTYPE_MULTI_SAVEONLY:
261296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   NCHAN represents number of input and output channels.
262296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TO: int16_t (Q.15) or float
263296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
264296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   TV: int32_t (U4.28) or int16_t (U4.12) or float
265296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   vol: represents a volume array.
266296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *
267296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung *   MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer.
268e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *
269e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung * MIXTYPE_MULTI_MONOVOL:
270e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *   Same as MIXTYPE_MULTI, but uses only volume[0].
271e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *
272e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung * MIXTYPE_MULTI_SAVEONLY_MONOVOL:
273e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *   Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0].
274e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung *
275296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung */
276296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
277296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <int MIXTYPE, int NCHAN,
278296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        typename TO, typename TI, typename TV, typename TA, typename TAV>
279296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void volumeRampMulti(TO* out, size_t frameCount,
280296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
281296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung{
282296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#ifdef ALOGVV
283296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE);
284296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#endif
285296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    if (aux != NULL) {
286296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
287296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            TA auxaccum = 0;
288296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
289296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
290296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
291296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
292296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
293296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
294296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
295e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
296e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
297e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
298e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    vol[i] += volinc[i];
299e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
300e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
301e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
302296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
303296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
304296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
305296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
306296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
307296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
308e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
309296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
310e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
311296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
312e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
313e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
314e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
315e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
316e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
317e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
318e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
319296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
320296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
321296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
322296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
323296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
324296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            auxaccum /= NCHAN;
325296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola);
326296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            vola[0] += volainc;
327296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
328296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    } else {
329296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
330296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
331296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
332296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
333296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
334296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
335296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
336296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
337e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
338e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
339e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
340e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    vol[i] += volinc[i];
341e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
342e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
343e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
344296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
345296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
346296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
347296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    vol[i] += volinc[i];
348296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
349296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
350e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
351296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
352e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
353296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
354e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
355e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
356e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
357e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
358e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
359e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
360e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                vol[0] += volinc[0];
361296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
362296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
363296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
364296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
365296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
366296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
367296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    }
368296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
369296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
370296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hungtemplate <int MIXTYPE, int NCHAN,
371296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        typename TO, typename TI, typename TV, typename TA, typename TAV>
372296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hunginline void volumeMulti(TO* out, size_t frameCount,
373296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        const TI* in, TA* aux, const TV *vol, TAV vola)
374296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung{
375296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#ifdef ALOGVV
376296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE);
377296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#endif
378296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    if (aux != NULL) {
379296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
380296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            TA auxaccum = 0;
381296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
382296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
383296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
384296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
385296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
386296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
387e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
388e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
389e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum);
390e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
391e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
392e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
393296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
394296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
395296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum);
396296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
397296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
398e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
399296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
400e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
401e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
402e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
403e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
404e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
405e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
406296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
407296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
408296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
409296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
410296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
411296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
412296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            auxaccum /= NCHAN;
413296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola);
414296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
415296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    } else {
416296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        do {
417296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            switch (MIXTYPE) {
418296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI:
419296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
420296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[i]);
421296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
422296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
423e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MONOEXPAND:
424e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
425e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in, vol[i]);
426e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
427e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                in++;
428e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
429296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            case MIXTYPE_MULTI_SAVEONLY:
430296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
431296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[i]);
432296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
433296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
434e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_MONOVOL:
435296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                for (int i = 0; i < NCHAN; ++i) {
436e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ += MixMul<TO, TI, TV>(*in++, vol[0]);
437e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                }
438e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                break;
439e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            case MIXTYPE_MULTI_SAVEONLY_MONOVOL:
440e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                for (int i = 0; i < NCHAN; ++i) {
441e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung                    *out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
442296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                }
443296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
444296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            default:
445296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE);
446296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung                break;
447296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            }
448296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        } while (--frameCount);
449296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    }
450296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung}
451296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
452296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung};
453296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
454296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung#endif /* ANDROID_AUDIO_MIXER_OPS_H */
455