12c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*
22c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Copyright (C) 2004-2010 NXP Software
32c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Copyright (C) 2010 The Android Open Source Project
42c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *
52c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Licensed under the Apache License, Version 2.0 (the "License");
62c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * you may not use this file except in compliance with the License.
72c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * You may obtain a copy of the License at
82c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *
92c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *      http://www.apache.org/licenses/LICENSE-2.0
102c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *
112c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Unless required by applicable law or agreed to in writing, software
122c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * distributed under the License is distributed on an "AS IS" BASIS,
132c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
142c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * See the License for the specific language governing permissions and
152c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * limitations under the License.
162c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent */
172c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
182c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/****************************************************************************************/
192c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
202c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*    Includes                                                                          */
212c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
222c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/****************************************************************************************/
232c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
242c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent#include "AGC.h"
252c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent#include "ScalarArithmetic.h"
262c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
272c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
282c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/****************************************************************************************/
292c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
302c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*    Defines                                                                           */
312c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
322c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/****************************************************************************************/
332c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
342c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent#define VOL_TC_SHIFT                                        21          /* As a power of 2 */
352c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent#define DECAY_SHIFT                                        10           /* As a power of 2 */
36d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri#ifdef BUILD_FLOAT
37d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri#define VOL_TC_FLOAT                                      2.0f          /* As a power of 2 */
38d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri#define DECAY_FAC_FLOAT                                  64.0f          /* As a power of 2 */
39d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri#endif
402c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
412c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/****************************************************************************************/
422c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
432c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* FUNCTION:                  AGC_MIX_VOL_2St1Mon_D32_WRA                               */
442c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
452c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* DESCRIPTION:                                                                         */
462c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*    Apply AGC and mix signals                                                         */
472c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
482c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
492c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*  StSrc   ------------------|                                                         */
502c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                            |                                                         */
512c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*              ______       _|_        ________                                        */
522c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*             |      |     |   |      |        |                                       */
532c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*  MonoSrc -->| AGC  |---->| + |----->| Volume |------------------------------+--->    */
542c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*             | Gain |     |___|      | Gain   |                              |        */
552c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*             |______|                |________|                              |        */
562c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                /|\                               __________     ________    |        */
572c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                 |                               |          |   |        |   |        */
582c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                 |-------------------------------| AGC Gain |<--| Peak   |<--|        */
592c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                 | Update   |   | Detect |            */
602c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                 |__________|   |________|            */
612c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
622c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
632c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* PARAMETERS:                                                                          */
642c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*  pInstance               Instance pointer                                            */
652c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*  pStereoIn               Stereo source                                               */
662c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*  pMonoIn                 Mono band pass source                                       */
672c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*  pStereoOut              Stereo destination                                          */
682c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
692c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* RETURNS:                                                                             */
702c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*  Void                                                                                */
712c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
722c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* NOTES:                                                                               */
732c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/*                                                                                      */
742c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/****************************************************************************************/
75d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri#ifndef BUILD_FLOAT
762c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurentvoid AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t  *pInstance,     /* Instance pointer */
772c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent                                 const LVM_INT32            *pStSrc,        /* Stereo source */
782c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent                                 const LVM_INT32            *pMonoSrc,      /* Mono source */
792c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent                                 LVM_INT32                  *pDst,          /* Stereo destination */
802c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent                                 LVM_UINT16                 NumSamples)     /* Number of samples */
812c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent{
822c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
832c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    /*
842c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     * General variables
852c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     */
862c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_UINT16      i;                                          /* Sample index */
872c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32       Left;                                       /* Left sample */
882c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32       Right;                                      /* Right sample */
892c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32       Mono;                                       /* Mono sample */
902c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32       AbsPeak;                                    /* Absolute peak signal */
912c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32       HighWord;                                   /* High word in intermediate calculations */
922c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32       LowWord;                                    /* Low word in intermediate calculations */
932c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT16       AGC_Mult;                                   /* Short AGC gain */
942c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT16       Vol_Mult;                                   /* Short volume */
952c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
962c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
972c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    /*
982c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     * Instance control variables
992c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     */
1002c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32      AGC_Gain      = pInstance->AGC_Gain;         /* Get the current AGC gain */
1012c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32      AGC_MaxGain   = pInstance->AGC_MaxGain;      /* Get maximum AGC gain */
1022c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT16      AGC_GainShift = pInstance->AGC_GainShift;    /* Get the AGC shift */
1032c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT16      AGC_Attack    = pInstance->AGC_Attack;       /* Attack scaler */
1042c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT16      AGC_Decay     = pInstance->AGC_Decay;        /* Decay scaler */
1052c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32      AGC_Target    = pInstance->AGC_Target;       /* Get the target level */
1062c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32      Vol_Current   = pInstance->Volume;           /* Actual volume setting */
1072c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT32      Vol_Target    = pInstance->Target;           /* Target volume setting */
1082c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT16      Vol_Shift     = pInstance->VolumeShift;      /* Volume shift scaling */
1092c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    LVM_INT16      Vol_TC        = pInstance->VolumeTC;         /* Time constant */
1102c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1112c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1122c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    /*
1132c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     * Process on a sample by sample basis
1142c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     */
1152c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    for (i=0;i<NumSamples;i++)                                  /* For each sample */
1162c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    {
1172c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1182c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        /*
1192c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         * Get the short scalers
1202c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         */
1212c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        AGC_Mult    = (LVM_INT16)(AGC_Gain >> 16);              /* Get the short AGC gain */
1222c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Vol_Mult    = (LVM_INT16)(Vol_Current >> 16);           /* Get the short volume gain */
1232c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1242c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1252c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        /*
1262c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         * Get the input samples
1272c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         */
1282c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Left  = *pStSrc++;                                      /* Get the left sample */
1292c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Right = *pStSrc++;                                      /* Get the right sample */
1302c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Mono  = *pMonoSrc++;                                    /* Get the mono sample */
1312c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1322c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1332c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        /*
1342c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         * Apply the AGC gain to the mono input and mix with the stereo signal
1352c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         */
1362c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        HighWord = (AGC_Mult * (Mono >> 16));                   /* signed long (Mono) by unsigned short (AGC_Mult) multiply */
1372c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        LowWord = (AGC_Mult * (Mono & 0xffff));
1382c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Mono = (HighWord + (LowWord >> 16)) << (AGC_GainShift);
1392c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Left  += Mono;                                          /* Mix in the mono signal */
1402c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Right += Mono;
1412c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1422c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1432c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        /*
1442c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         * Apply the volume and write to the output stream
1452c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         */
1462c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        HighWord = (Vol_Mult * (Left >> 16));                   /* signed long (Left) by unsigned short (Vol_Mult) multiply */
1472c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        LowWord = (Vol_Mult * (Left & 0xffff));
1482c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Left = (HighWord + (LowWord >> 16)) << (Vol_Shift);
1492c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        HighWord = (Vol_Mult * (Right >> 16));                  /* signed long (Right) by unsigned short (Vol_Mult) multiply */
1502c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        LowWord = (Vol_Mult * (Right & 0xffff));
1512c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Right = (HighWord + (LowWord >> 16)) << (Vol_Shift);
1522c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        *pDst++ = Left;                                         /* Save the results */
1532c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        *pDst++ = Right;
1542c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1552c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1562c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        /*
1572c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         * Update the AGC gain
1582c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         */
1592c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        AbsPeak = (Abs_32(Left)>Abs_32(Right)) ? Abs_32(Left) : Abs_32(Right);  /* Get the absolute peak */
1602c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        if (AbsPeak > AGC_Target)
1612c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        {
1622c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            /*
1632c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent             * The signal is too large so decrease the gain
1642c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent             */
1652c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            HighWord = (AGC_Attack * (AGC_Gain >> 16));         /* signed long (AGC_Gain) by unsigned short (AGC_Attack) multiply */
1662c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            LowWord = (AGC_Attack * (AGC_Gain & 0xffff));
1672c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            AGC_Gain = (HighWord + (LowWord >> 16)) << 1;
1682c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        }
1692c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        else
1702c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        {
1712c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            /*
1722c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent             * The signal is too small so increase the gain
1732c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent             */
1742c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            if (AGC_Gain > AGC_MaxGain)
1752c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            {
1762c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent                AGC_Gain -= (AGC_Decay << DECAY_SHIFT);
1772c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            }
1782c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            else
1792c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            {
1802c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent                AGC_Gain += (AGC_Decay << DECAY_SHIFT);
1812c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent            }
1822c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        }
1832c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1842c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        /*
1852c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         * Update the gain
1862c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent         */
1872c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent        Vol_Current += Vol_TC * ((Vol_Target - Vol_Current) >> VOL_TC_SHIFT);
1882c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    }
1892c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1902c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1912c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    /*
1922c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     * Update the parameters
1932c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent     */
1942c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    pInstance->Volume = Vol_Current;                            /* Actual volume setting */
1952c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    pInstance->AGC_Gain = AGC_Gain;
1962c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
1972c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent    return;
1982c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent}
199d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri#else
200d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katurivoid AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t  *pInstance,     /* Instance pointer */
201d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri                                 const LVM_FLOAT            *pStSrc,        /* Stereo source */
202d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri                                 const LVM_FLOAT            *pMonoSrc,      /* Mono source */
203d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri                                 LVM_FLOAT                  *pDst,          /* Stereo destination */
204d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri                                 LVM_UINT16                 NumSamples)     /* Number of samples */
205d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri{
206d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
207d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    /*
208d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     * General variables
209d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     */
210d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_UINT16      i;                                          /* Sample index */
211d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT       Left;                                       /* Left sample */
212d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT       Right;                                      /* Right sample */
213d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT       Mono;                                       /* Mono sample */
214d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT       AbsPeak;                                    /* Absolute peak signal */
215d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT       AGC_Mult;                                   /* Short AGC gain */
216d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT       Vol_Mult;                                   /* Short volume */
217d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
218d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
219d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    /*
220d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     * Instance control variables
221d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     */
222d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      AGC_Gain      = pInstance->AGC_Gain;         /* Get the current AGC gain */
223d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      AGC_MaxGain   = pInstance->AGC_MaxGain;      /* Get maximum AGC gain */
224d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      AGC_Attack    = pInstance->AGC_Attack;       /* Attack scaler */
225d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      AGC_Decay     = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));/* Decay scaler */
226d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      AGC_Target    = pInstance->AGC_Target;       /* Get the target level */
227d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      Vol_Current   = pInstance->Volume;           /* Actual volume setting */
228d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      Vol_Target    = pInstance->Target;           /* Target volume setting */
229d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    LVM_FLOAT      Vol_TC        = pInstance->VolumeTC;         /* Time constant */
230d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
231d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
232d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    /*
233d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     * Process on a sample by sample basis
234d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     */
235d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    for (i = 0; i < NumSamples; i++)                                  /* For each sample */
236d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    {
2372c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent
238d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        /*
239d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         * Get the short scalers
240d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         */
241d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        AGC_Mult    = (LVM_FLOAT)(AGC_Gain);              /* Get the short AGC gain */
242d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Vol_Mult    = (LVM_FLOAT)(Vol_Current);           /* Get the short volume gain */
243d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
244d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
245d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        /*
246d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         * Get the input samples
247d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         */
248d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Left  = *pStSrc++;                                      /* Get the left sample */
249d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Right = *pStSrc++;                                      /* Get the right sample */
250d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Mono  = *pMonoSrc++;                                    /* Get the mono sample */
251d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
252d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
253d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        /*
254d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         * Apply the AGC gain to the mono input and mix with the stereo signal
255d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         */
256d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Left  += (Mono * AGC_Mult);                               /* Mix in the mono signal */
257d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Right += (Mono * AGC_Mult);
258d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
259d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        /*
260d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         * Apply the volume and write to the output stream
261d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         */
262d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Left  = Left  * Vol_Mult;
263d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Right = Right * Vol_Mult;
264d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        *pDst++ = Left;                                         /* Save the results */
265d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        *pDst++ = Right;
266d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
267d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        /*
268d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         * Update the AGC gain
269d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         */
270d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        AbsPeak = Abs_Float(Left) > Abs_Float(Right) ? Abs_Float(Left) : Abs_Float(Right);
271d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        if (AbsPeak > AGC_Target)
272d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        {
273d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            /*
274d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri             * The signal is too large so decrease the gain
275d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri             */
276d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            AGC_Gain = AGC_Gain * AGC_Attack;
277d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        }
278d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        else
279d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        {
280d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            /*
281d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri             * The signal is too small so increase the gain
282d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri             */
283d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            if (AGC_Gain > AGC_MaxGain)
284d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            {
285d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri                AGC_Gain -= (AGC_Decay);
286d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            }
287d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            else
288d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            {
289d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri                AGC_Gain += (AGC_Decay);
290d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri            }
291d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        }
292d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
293d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        /*
294d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         * Update the gain
295d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri         */
296d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri        Vol_Current +=  (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
297d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    }
298d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
299d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
300d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    /*
301d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     * Update the parameters
302d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri     */
303d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    pInstance->Volume = Vol_Current;                            /* Actual volume setting */
304d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    pInstance->AGC_Gain = AGC_Gain;
305d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri
306d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri    return;
307d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri}
308d7d013446a64c6de9f0f2dfe098a721b140e0b48Ramesh Katuri#endif /*BUILD_FLOAT*/
309