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