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
24 #include "AGC.h"
25 #include "ScalarArithmetic.h"
26
27
28 /****************************************************************************************/
29 /* */
30 /* Defines */
31 /* */
32 /****************************************************************************************/
33
34 #define VOL_TC_SHIFT 21 /* As a power of 2 */
35 #define DECAY_SHIFT 10 /* As a power of 2 */
36
37
38 /****************************************************************************************/
39 /* */
40 /* FUNCTION: AGC_MIX_VOL_2St1Mon_D32_WRA */
41 /* */
42 /* DESCRIPTION: */
43 /* Apply AGC and mix signals */
44 /* */
45 /* */
46 /* StSrc ------------------| */
47 /* | */
48 /* ______ _|_ ________ */
49 /* | | | | | | */
50 /* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
51 /* | Gain | |___| | Gain | | */
52 /* |______| |________| | */
53 /* /|\ __________ ________ | */
54 /* | | | | | | */
55 /* |-------------------------------| AGC Gain |<--| Peak |<--| */
56 /* | Update | | Detect | */
57 /* |__________| |________| */
58 /* */
59 /* */
60 /* PARAMETERS: */
61 /* pInstance Instance pointer */
62 /* pStereoIn Stereo source */
63 /* pMonoIn Mono band pass source */
64 /* pStereoOut Stereo destination */
65 /* */
66 /* RETURNS: */
67 /* Void */
68 /* */
69 /* NOTES: */
70 /* */
71 /****************************************************************************************/
72
AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t * pInstance,const LVM_INT32 * pStSrc,const LVM_INT32 * pMonoSrc,LVM_INT32 * pDst,LVM_UINT16 NumSamples)73 void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t *pInstance, /* Instance pointer */
74 const LVM_INT32 *pStSrc, /* Stereo source */
75 const LVM_INT32 *pMonoSrc, /* Mono source */
76 LVM_INT32 *pDst, /* Stereo destination */
77 LVM_UINT16 NumSamples) /* Number of samples */
78 {
79
80 /*
81 * General variables
82 */
83 LVM_UINT16 i; /* Sample index */
84 LVM_INT32 Left; /* Left sample */
85 LVM_INT32 Right; /* Right sample */
86 LVM_INT32 Mono; /* Mono sample */
87 LVM_INT32 AbsPeak; /* Absolute peak signal */
88 LVM_INT32 HighWord; /* High word in intermediate calculations */
89 LVM_INT32 LowWord; /* Low word in intermediate calculations */
90 LVM_INT16 AGC_Mult; /* Short AGC gain */
91 LVM_INT16 Vol_Mult; /* Short volume */
92
93
94 /*
95 * Instance control variables
96 */
97 LVM_INT32 AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
98 LVM_INT32 AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
99 LVM_INT16 AGC_GainShift = pInstance->AGC_GainShift; /* Get the AGC shift */
100 LVM_INT16 AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
101 LVM_INT16 AGC_Decay = pInstance->AGC_Decay; /* Decay scaler */
102 LVM_INT32 AGC_Target = pInstance->AGC_Target; /* Get the target level */
103 LVM_INT32 Vol_Current = pInstance->Volume; /* Actual volume setting */
104 LVM_INT32 Vol_Target = pInstance->Target; /* Target volume setting */
105 LVM_INT16 Vol_Shift = pInstance->VolumeShift; /* Volume shift scaling */
106 LVM_INT16 Vol_TC = pInstance->VolumeTC; /* Time constant */
107
108
109 /*
110 * Process on a sample by sample basis
111 */
112 for (i=0;i<NumSamples;i++) /* For each sample */
113 {
114
115 /*
116 * Get the short scalers
117 */
118 AGC_Mult = (LVM_INT16)(AGC_Gain >> 16); /* Get the short AGC gain */
119 Vol_Mult = (LVM_INT16)(Vol_Current >> 16); /* Get the short volume gain */
120
121
122 /*
123 * Get the input samples
124 */
125 Left = *pStSrc++; /* Get the left sample */
126 Right = *pStSrc++; /* Get the right sample */
127 Mono = *pMonoSrc++; /* Get the mono sample */
128
129
130 /*
131 * Apply the AGC gain to the mono input and mix with the stereo signal
132 */
133 HighWord = (AGC_Mult * (Mono >> 16)); /* signed long (Mono) by unsigned short (AGC_Mult) multiply */
134 LowWord = (AGC_Mult * (Mono & 0xffff));
135 Mono = (HighWord + (LowWord >> 16)) << (AGC_GainShift);
136 Left += Mono; /* Mix in the mono signal */
137 Right += Mono;
138
139
140 /*
141 * Apply the volume and write to the output stream
142 */
143 HighWord = (Vol_Mult * (Left >> 16)); /* signed long (Left) by unsigned short (Vol_Mult) multiply */
144 LowWord = (Vol_Mult * (Left & 0xffff));
145 Left = (HighWord + (LowWord >> 16)) << (Vol_Shift);
146 HighWord = (Vol_Mult * (Right >> 16)); /* signed long (Right) by unsigned short (Vol_Mult) multiply */
147 LowWord = (Vol_Mult * (Right & 0xffff));
148 Right = (HighWord + (LowWord >> 16)) << (Vol_Shift);
149 *pDst++ = Left; /* Save the results */
150 *pDst++ = Right;
151
152
153 /*
154 * Update the AGC gain
155 */
156 AbsPeak = (Abs_32(Left)>Abs_32(Right)) ? Abs_32(Left) : Abs_32(Right); /* Get the absolute peak */
157 if (AbsPeak > AGC_Target)
158 {
159 /*
160 * The signal is too large so decrease the gain
161 */
162 HighWord = (AGC_Attack * (AGC_Gain >> 16)); /* signed long (AGC_Gain) by unsigned short (AGC_Attack) multiply */
163 LowWord = (AGC_Attack * (AGC_Gain & 0xffff));
164 AGC_Gain = (HighWord + (LowWord >> 16)) << 1;
165 }
166 else
167 {
168 /*
169 * The signal is too small so increase the gain
170 */
171 if (AGC_Gain > AGC_MaxGain)
172 {
173 AGC_Gain -= (AGC_Decay << DECAY_SHIFT);
174 }
175 else
176 {
177 AGC_Gain += (AGC_Decay << DECAY_SHIFT);
178 }
179 }
180
181 /*
182 * Update the gain
183 */
184 Vol_Current += Vol_TC * ((Vol_Target - Vol_Current) >> VOL_TC_SHIFT);
185 }
186
187
188 /*
189 * Update the parameters
190 */
191 pInstance->Volume = Vol_Current; /* Actual volume setting */
192 pInstance->AGC_Gain = AGC_Gain;
193
194 return;
195 }
196
197