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
73void 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