Home | History | Annotate | Download | only in src
      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 "LVCS.h"
     25 #include "LVCS_Private.h"
     26 #include "LVCS_BypassMix.h"
     27 #include "VectorArithmetic.h"
     28 #include "LVCS_Tables.h"
     29 
     30 /****************************************************************************************/
     31 /*                                                                                      */
     32 /*  Function Prototypes                                                                 */
     33 /*                                                                                      */
     34 /****************************************************************************************/
     35 LVM_INT32 LVCS_MixerCallback(   LVCS_Handle_t   hInstance,
     36                                 void            *pGeneralPurpose,
     37                                 LVM_INT16       CallbackParam);
     38 
     39 /************************************************************************************/
     40 /*                                                                                  */
     41 /* FUNCTION:                LVCS_BypassMixInit                                      */
     42 /*                                                                                  */
     43 /* DESCRIPTION:                                                                     */
     44 /*  Initialises the bypass mixer module                                             */
     45 /*                                                                                  */
     46 /*  The overall gain of the processed path is set by the gains in the individual    */
     47 /*  processing blocks and by the effect level gain.                                 */
     48 /*                                                                                  */
     49 /*  The unprocessed path must have matching gain for the processed path to ensure   */
     50 /*  as they are mixed together the correct effect is achieved, this is the value    */
     51 /*  UnprocLoss.                                                                     */
     52 /*                                                                                  */
     53 /*  The overall gain is corrected by a combination of a shift with saturation and a */
     54 /*  linear scaler, loss. The loss ensures the sum in the mixer does not saturate    */
     55 /*  and also corrects for any excess gain in the shift.                             */
     56 /*                                                                                  */
     57 /* PARAMETERS:                                                                      */
     58 /*  hInstance               Instance Handle                                         */
     59 /*  pParams                 Initialisation parameters                               */
     60 /*                                                                                  */
     61 /* RETURNS:                                                                         */
     62 /*  LVCS_Success            Always succeeds                                         */
     63 /*                                                                                  */
     64 /* NOTES:                                                                           */
     65 /*                                                                                  */
     66 /************************************************************************************/
     67 
     68 LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t       hInstance,
     69                                         LVCS_Params_t       *pParams)
     70 {
     71 
     72     LVM_UINT16          Offset;
     73     LVM_UINT32          Gain;
     74     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
     75     LVCS_BypassMix_t    *pConfig   = (LVCS_BypassMix_t *)&pInstance->BypassMix;
     76     const Gain_t        *pOutputGainTable;
     77     LVM_INT32           Current;
     78 
     79 
     80     /*
     81      * Set the transition gain
     82      */
     83     if ((pParams->OperatingMode == LVCS_ON) &&
     84         (pInstance->bTimerDone == LVM_TRUE)
     85         && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
     86         )
     87     {
     88         pInstance->TransitionGain = pParams->EffectLevel;
     89     }
     90     else
     91     {
     92         /* Select no effect level */
     93         pInstance->TransitionGain = 0;
     94     }
     95 
     96     /*
     97      * Calculate the output gain table offset
     98      */
     99     Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
    100     pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
    101 
    102     /*
    103      * Setup the mixer gain for the processed path
    104      */
    105     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
    106 
    107     pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
    108     pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
    109     pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
    110     pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
    111     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
    112     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current);
    113     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    114     /*
    115      * Setup the mixer gain for the unprocessed path
    116      */
    117     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain));
    118     Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
    119     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
    120     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current);
    121     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    122     pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
    123     pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
    124     pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
    125     pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
    126 
    127     /*
    128      * Setup the output gain shift
    129      */
    130     pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
    131 
    132 
    133     /*
    134      * Correct gain for the effect level
    135      */
    136     {
    137 
    138         LVM_INT16           GainCorrect;
    139         LVM_INT32           Gain1;
    140         LVM_INT32           Gain2;
    141 
    142         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
    143         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
    144         /*
    145          * Calculate the gain correction
    146          */
    147         if (pInstance->Params.CompressorMode == LVM_MODE_ON)
    148         {
    149         GainCorrect = (LVM_INT16)(  pInstance->VolCorrect.GainMin
    150                                     - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15)
    151                                     + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) );
    152 
    153         /*
    154          * Apply the gain correction and shift, note the result is in Q3.13 format
    155          */
    156         Gain1 = (Gain1 * GainCorrect) << 4;
    157         Gain2 = (Gain2 * GainCorrect) << 4;
    158         }
    159         else
    160         {
    161             Gain1 = Gain1 << 16;
    162             Gain2 = Gain2 << 16;
    163         }
    164 
    165 
    166 
    167         /*
    168          * Set the gain values
    169          */
    170         pConfig->Output_Shift = pConfig->Output_Shift;
    171         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16);
    172         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    173         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16);
    174         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    175     }
    176 
    177     return(LVCS_SUCCESS);
    178 
    179 }
    180 
    181 /************************************************************************************/
    182 /*                                                                                  */
    183 /* FUNCTION:                LVCS_BypassMixer                                        */
    184 /*                                                                                  */
    185 /* DESCRIPTION:                                                                     */
    186 /*  Apply Bypass Mix.                                                               */
    187 /*                                                                                  */
    188 /*  This mixes the processed and unprocessed data streams together to correct the   */
    189 /*  overall system gain and allow progressive control of the Concert Sound effect.  */
    190 /*                                                                                  */
    191 /*  When the bypass mixer is enabled the output is the processed signal only and    */
    192 /*  without gain correction.                                                        */
    193 /*                                                                                  */
    194 /* PARAMETERS:                                                                      */
    195 /*  hInstance               Instance Handle                                         */
    196 /*  pProcessed              Pointer to the processed data                           */
    197 /*  pUnprocessed            Pointer to the unprocessed data                         */
    198 /*  pOutData                Pointer to the output data                              */
    199 /*  NumSamples              Number of samples to process                            */
    200 /*                                                                                  */
    201 /* RETURNS:                                                                         */
    202 /*  LVCS_Success            Always succeeds                                         */
    203 /*                                                                                  */
    204 /* NOTES:                                                                           */
    205 /*                                                                                  */
    206 /************************************************************************************/
    207 
    208 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t         hInstance,
    209                                       const LVM_INT16       *pProcessed,
    210                                       const LVM_INT16       *pUnprocessed,
    211                                       LVM_INT16             *pOutData,
    212                                       LVM_UINT16            NumSamples)
    213 {
    214 
    215     LVCS_Instance_t     *pInstance      = (LVCS_Instance_t  *)hInstance;
    216     LVCS_BypassMix_t    *pConfig        = (LVCS_BypassMix_t *)&pInstance->BypassMix;
    217 
    218     /*
    219      * Check if the bypass mixer is enabled
    220      */
    221     if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0)
    222     {
    223         /*
    224          * Apply the bypass mix
    225          */
    226         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
    227                                         pProcessed,
    228                                         (LVM_INT16 *) pUnprocessed,
    229                                         pOutData,
    230                                         (LVM_INT16)(2*NumSamples));
    231 
    232         /*
    233          * Apply output gain correction shift
    234          */
    235         Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift,
    236                           (LVM_INT16*)pOutData,
    237                           (LVM_INT16*)pOutData,
    238                           (LVM_INT16)(2*NumSamples));          /* Left and right*/
    239     }
    240 
    241     return(LVCS_SUCCESS);
    242 }
    243 
    244 
    245 /************************************************************************************/
    246 /*                                                                                  */
    247 /* FUNCTION:                LVCS_MixerCallback                                      */
    248 /*                                                                                  */
    249 /************************************************************************************/
    250 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t      hInstance,
    251                             void                *pGeneralPurpose,
    252                             LVM_INT16           CallbackParam)
    253 {
    254     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
    255 
    256    (void)pGeneralPurpose;
    257 
    258     /*
    259      * Off transition has completed in Headphone mode
    260      */
    261     if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
    262         (pInstance->bInOperatingModeTransition)     &&
    263         (pInstance->MSTarget0 == 0x0000)&&  /* this indicates an on->off transition */
    264         (CallbackParam == 0))
    265     {
    266         /* Set operating mode to OFF */
    267         pInstance->Params.OperatingMode = LVCS_OFF;
    268 
    269         /* Exit transition state */
    270         pInstance->bInOperatingModeTransition = LVM_FALSE;
    271 
    272         /* Signal to the bundle */
    273         if((*pInstance->Capabilities.CallBack) != LVM_NULL){
    274             (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
    275                                                 LVM_NULL,
    276                                                 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
    277         }
    278     }
    279 
    280 
    281     if ((pInstance->OutputDevice == LVCS_HEADPHONE)  &&
    282         (pInstance->MSTarget0 == 1) &&
    283         (pInstance->bTimerDone == LVM_TRUE)){
    284 
    285         /* Exit transition state */
    286         pInstance->bInOperatingModeTransition = LVM_FALSE;
    287     }
    288 
    289     return 1;
    290 }
    291 
    292 
    293 
    294