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 #ifndef BUILD_FLOAT
     74     LVM_UINT32          Gain;
     75     LVM_INT32           Current;
     76 #else
     77     LVM_FLOAT           Gain;
     78     LVM_FLOAT           Current;
     79 #endif
     80     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
     81     LVCS_BypassMix_t    *pConfig   = (LVCS_BypassMix_t *)&pInstance->BypassMix;
     82     const Gain_t        *pOutputGainTable;
     83 
     84 
     85 
     86     /*
     87      * Set the transition gain
     88      */
     89     if ((pParams->OperatingMode == LVCS_ON) &&
     90         (pInstance->bTimerDone == LVM_TRUE)
     91         && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
     92         )
     93     {
     94 #ifndef BUILD_FLOAT
     95         pInstance->TransitionGain = pParams->EffectLevel;
     96 #else
     97         pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767);
     98 #endif
     99     }
    100     else
    101     {
    102         /* Select no effect level */
    103         pInstance->TransitionGain = 0;
    104     }
    105 
    106     /*
    107      * Calculate the output gain table offset
    108      */
    109     Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
    110     pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
    111 
    112     /*
    113      * Setup the mixer gain for the processed path
    114      */
    115 #ifndef BUILD_FLOAT
    116     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
    117 #else
    118     Gain =  (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
    119 #endif
    120 
    121     pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
    122     pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
    123     pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
    124     pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
    125 
    126 #ifndef BUILD_FLOAT
    127     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
    128     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current);
    129     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    130 #else
    131     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
    132     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current);
    133     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
    134                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
    135 #endif
    136 
    137     /*
    138      * Setup the mixer gain for the unprocessed path
    139      */
    140 #ifndef BUILD_FLOAT
    141     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain));
    142     Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
    143     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
    144     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current);
    145     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    146 #else
    147     Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * (1.0 - \
    148                                     (LVM_FLOAT)pInstance->TransitionGain));
    149     Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain;
    150     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
    151     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current);
    152     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
    153                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
    154 #endif
    155     pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
    156     pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
    157     pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
    158     pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
    159 
    160     /*
    161      * Setup the output gain shift
    162      */
    163     pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
    164 
    165 
    166     /*
    167      * Correct gain for the effect level
    168      */
    169     {
    170 #ifndef BUILD_FLOAT
    171         LVM_INT16           GainCorrect;
    172         LVM_INT32           Gain1;
    173         LVM_INT32           Gain2;
    174 
    175         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
    176         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
    177         /*
    178          * Calculate the gain correction
    179          */
    180         if (pInstance->Params.CompressorMode == LVM_MODE_ON)
    181         {
    182         GainCorrect = (LVM_INT16)(  pInstance->VolCorrect.GainMin
    183                                     - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15)
    184                                     + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) );
    185 
    186         /*
    187          * Apply the gain correction and shift, note the result is in Q3.13 format
    188          */
    189         Gain1 = (Gain1 * GainCorrect) << 4;
    190         Gain2 = (Gain2 * GainCorrect) << 4;
    191         }
    192         else
    193         {
    194             Gain1 = Gain1 << 16;
    195             Gain2 = Gain2 << 16;
    196         }
    197 
    198 
    199 
    200         /*
    201          * Set the gain values
    202          */
    203         pConfig->Output_Shift = pConfig->Output_Shift;
    204         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16);
    205         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    206         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16);
    207         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
    208 #else
    209         LVM_FLOAT           GainCorrect;
    210         LVM_FLOAT           Gain1;
    211         LVM_FLOAT           Gain2;
    212 
    213         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
    214         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
    215         /*
    216          * Calculate the gain correction
    217          */
    218         if (pInstance->Params.CompressorMode == LVM_MODE_ON)
    219         {
    220         GainCorrect = (LVM_FLOAT)(  pInstance->VolCorrect.GainMin
    221                                     - (((LVM_FLOAT)pInstance->VolCorrect.GainMin * \
    222                                                          ((LVM_FLOAT)pInstance->TransitionGain)))
    223                                     + (((LVM_FLOAT)pInstance->VolCorrect.GainFull * \
    224                                                         ((LVM_FLOAT)pInstance->TransitionGain))));
    225 
    226         /*
    227          * Apply the gain correction
    228          */
    229         Gain1 = (Gain1 * GainCorrect);
    230         Gain2 = (Gain2 * GainCorrect);
    231 
    232         }
    233 
    234         /*
    235          * Set the gain values
    236          */
    237         pConfig->Output_Shift = pConfig->Output_Shift;
    238         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1);
    239         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
    240                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
    241         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2);
    242         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
    243                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
    244 #endif
    245     }
    246 
    247     return(LVCS_SUCCESS);
    248 
    249 }
    250 
    251 /************************************************************************************/
    252 /*                                                                                  */
    253 /* FUNCTION:                LVCS_BypassMixer                                        */
    254 /*                                                                                  */
    255 /* DESCRIPTION:                                                                     */
    256 /*  Apply Bypass Mix.                                                               */
    257 /*                                                                                  */
    258 /*  This mixes the processed and unprocessed data streams together to correct the   */
    259 /*  overall system gain and allow progressive control of the Concert Sound effect.  */
    260 /*                                                                                  */
    261 /*  When the bypass mixer is enabled the output is the processed signal only and    */
    262 /*  without gain correction.                                                        */
    263 /*                                                                                  */
    264 /* PARAMETERS:                                                                      */
    265 /*  hInstance               Instance Handle                                         */
    266 /*  pProcessed              Pointer to the processed data                           */
    267 /*  pUnprocessed            Pointer to the unprocessed data                         */
    268 /*  pOutData                Pointer to the output data                              */
    269 /*  NumSamples              Number of samples to process                            */
    270 /*                                                                                  */
    271 /* RETURNS:                                                                         */
    272 /*  LVCS_Success            Always succeeds                                         */
    273 /*                                                                                  */
    274 /* NOTES:                                                                           */
    275 /*                                                                                  */
    276 /************************************************************************************/
    277 
    278 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t         hInstance,
    279 #ifndef BUILD_FLOAT
    280                                       const LVM_INT16       *pProcessed,
    281                                       const LVM_INT16       *pUnprocessed,
    282                                       LVM_INT16             *pOutData,
    283 #else
    284                                       const LVM_FLOAT       *pProcessed,
    285                                       const LVM_FLOAT       *pUnprocessed,
    286                                       LVM_FLOAT             *pOutData,
    287 #endif
    288                                       LVM_UINT16            NumSamples)
    289 {
    290 
    291     LVCS_Instance_t     *pInstance      = (LVCS_Instance_t  *)hInstance;
    292     LVCS_BypassMix_t    *pConfig        = (LVCS_BypassMix_t *)&pInstance->BypassMix;
    293 
    294     /*
    295      * Check if the bypass mixer is enabled
    296      */
    297     if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0)
    298     {
    299         /*
    300          * Apply the bypass mix
    301          */
    302 #ifndef BUILD_FLOAT
    303         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
    304                                         pProcessed,
    305                                         (LVM_INT16 *) pUnprocessed,
    306                                         pOutData,
    307                                         (LVM_INT16)(2*NumSamples));
    308 
    309         /*
    310          * Apply output gain correction shift
    311          */
    312         Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift,
    313                           (LVM_INT16*)pOutData,
    314                           (LVM_INT16*)pOutData,
    315                           (LVM_INT16)(2*NumSamples));          /* Left and right*/
    316 #else
    317         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
    318                                    pProcessed,
    319                                    (LVM_FLOAT *) pUnprocessed,
    320                                    pOutData,
    321                                    (LVM_INT16)(2 * NumSamples));
    322         /*
    323          * Apply output gain correction shift
    324          */
    325         Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift,
    326                         (LVM_FLOAT*)pOutData,
    327                         (LVM_FLOAT*)pOutData,
    328                         (LVM_INT16)(2 * NumSamples));          /* Left and right*/
    329 #endif
    330     }
    331 
    332     return(LVCS_SUCCESS);
    333 }
    334 
    335 
    336 /************************************************************************************/
    337 /*                                                                                  */
    338 /* FUNCTION:                LVCS_MixerCallback                                      */
    339 /*                                                                                  */
    340 /************************************************************************************/
    341 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t      hInstance,
    342                             void                *pGeneralPurpose,
    343                             LVM_INT16           CallbackParam)
    344 {
    345     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
    346 
    347    (void)pGeneralPurpose;
    348 
    349     /*
    350      * Off transition has completed in Headphone mode
    351      */
    352     if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
    353         (pInstance->bInOperatingModeTransition)     &&
    354         (pInstance->MSTarget0 == 0x0000)&&  /* this indicates an on->off transition */
    355         (CallbackParam == 0))
    356     {
    357         /* Set operating mode to OFF */
    358         pInstance->Params.OperatingMode = LVCS_OFF;
    359 
    360         /* Exit transition state */
    361         pInstance->bInOperatingModeTransition = LVM_FALSE;
    362 
    363         /* Signal to the bundle */
    364         if((*pInstance->Capabilities.CallBack) != LVM_NULL){
    365             (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
    366                                                 LVM_NULL,
    367                                                 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
    368         }
    369     }
    370 
    371 
    372     if ((pInstance->OutputDevice == LVCS_HEADPHONE)  &&
    373         (pInstance->MSTarget0 == 1) &&
    374         (pInstance->bTimerDone == LVM_TRUE)){
    375 
    376         /* Exit transition state */
    377         pInstance->bInOperatingModeTransition = LVM_FALSE;
    378     }
    379 
    380     return 1;
    381 }
    382 
    383 
    384 
    385