1 /*
2 * Copyright (C) 2004-2010 NXP Software
3 * Copyright (C) 2010 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /****************************************************************************************/
19 /* */
20 /* Includes */
21 /* */
22 /****************************************************************************************/
23 #include "AGC.h"
24 #include "ScalarArithmetic.h"
25
26 /****************************************************************************************/
27 /* */
28 /* Defines */
29 /* */
30 /****************************************************************************************/
31
32 #define VOL_TC_SHIFT 21 /* As a power of 2 */
33 #define DECAY_SHIFT 10 /* As a power of 2 */
34 #define VOL_TC_FLOAT 2.0f /* As a power of 2 */
35 #define DECAY_FAC_FLOAT 64.0f /* As a power of 2 */
36
37 /****************************************************************************************/
38 /* */
39 /* FUNCTION: AGC_MIX_VOL_Mc1Mon_D32_WRA */
40 /* */
41 /* DESCRIPTION: */
42 /* Apply AGC and mix signals */
43 /* */
44 /* */
45 /* McSrc ------------------| */
46 /* | */
47 /* ______ _|_ ________ */
48 /* | | | | | | */
49 /* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
50 /* | Gain | |___| | Gain | | */
51 /* |______| |________| | */
52 /* /|\ __________ ________ | */
53 /* | | | | | | */
54 /* |-------------------------------| AGC Gain |<--| Peak |<--| */
55 /* | Update | | Detect | */
56 /* |__________| |________| */
57 /* */
58 /* */
59 /* PARAMETERS: */
60 /* pInstance Instance pointer */
61 /* pMcSrc Multichannel source */
62 /* pMonoSrc Mono band pass source */
63 /* pDst Multichannel destination */
64 /* NrFrames Number of frames */
65 /* NrChannels Number of channels */
66 /* */
67 /* RETURNS: */
68 /* Void */
69 /* */
70 /* NOTES: */
71 /* */
72 /****************************************************************************************/
AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t * pInstance,const LVM_FLOAT * pMcSrc,const LVM_FLOAT * pMonoSrc,LVM_FLOAT * pDst,LVM_UINT16 NrFrames,LVM_UINT16 NrChannels)73 void AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t* pInstance, const LVM_FLOAT* pMcSrc,
74 const LVM_FLOAT* pMonoSrc, LVM_FLOAT* pDst, LVM_UINT16 NrFrames,
75 LVM_UINT16 NrChannels) {
76 /*
77 * General variables
78 */
79 LVM_UINT16 i, jj; /* Sample index */
80 LVM_FLOAT SampleVal; /* Sample value */
81 LVM_FLOAT Mono; /* Mono sample */
82 LVM_FLOAT AbsPeak; /* Absolute peak signal */
83 LVM_FLOAT AGC_Mult; /* Short AGC gain */
84 LVM_FLOAT Vol_Mult; /* Short volume */
85
86 /*
87 * Instance control variables
88 */
89 LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
90 LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
91 LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
92 /* Decay scaler */
93 LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));
94 LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
95 LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
96 LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
97 LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
98
99 /*
100 * Process on a sample by sample basis
101 */
102 for (i = 0; i < NrFrames; i++) /* For each frame */
103 {
104 /*
105 * Get the scalers
106 */
107 AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the AGC gain */
108 Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the volume gain */
109
110 AbsPeak = 0.0f;
111 /*
112 * Get the input samples
113 */
114 for (jj = 0; jj < NrChannels; jj++) {
115 SampleVal = *pMcSrc++; /* Get the sample value of jj Channel*/
116 Mono = *pMonoSrc; /* Get the mono sample */
117
118 /*
119 * Apply the AGC gain to the mono input and mix with the input signal
120 */
121 SampleVal += (Mono * AGC_Mult); /* Mix in the mono signal */
122
123 /*
124 * Apply the volume and write to the output stream
125 */
126 SampleVal = SampleVal * Vol_Mult;
127
128 *pDst++ = LVM_Clamp(SampleVal); /* Save the results */
129
130 /*
131 * Update the AGC gain
132 */
133 AbsPeak = Abs_Float(SampleVal) > AbsPeak ? Abs_Float(SampleVal) : AbsPeak;
134 }
135 if (AbsPeak > AGC_Target) {
136 /*
137 * The signal is too large so decrease the gain
138 */
139 AGC_Gain = AGC_Gain * AGC_Attack;
140 } else {
141 /*
142 * The signal is too small so increase the gain
143 */
144 if (AGC_Gain > AGC_MaxGain) {
145 AGC_Gain -= (AGC_Decay);
146 } else {
147 AGC_Gain += (AGC_Decay);
148 }
149 }
150 pMonoSrc++;
151 /*
152 * Update the gain
153 */
154 Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
155 }
156
157 /*
158 * Update the parameters
159 */
160 pInstance->Volume = Vol_Current; /* Actual volume setting */
161 pInstance->AGC_Gain = AGC_Gain;
162
163 return;
164 }
165