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 /*                                                                                  */
     21 /*  Includes                                                                        */
     22 /*                                                                                  */
     23 /************************************************************************************/
     24 
     25 #include "LVCS.h"
     26 #include "LVCS_Private.h"
     27 #include "VectorArithmetic.h"
     28 #include "CompLim.h"
     29 
     30 /************************************************************************************/
     31 /*                                                                                  */
     32 /* FUNCTION:                LVCS_Process_CS                                         */
     33 /*                                                                                  */
     34 /* DESCRIPTION:                                                                     */
     35 /*  Process function for the Concert Sound module based on the following block      */
     36 /*  diagram:                                                                        */
     37 /*            _________    ________    _____    _______     ___   ______            */
     38 /*           |         |  |        |  |     |  |       |   |   | |      |           */
     39 /*     ----->| Stereo  |->| Reverb |->| Equ |->| Alpha |-->| + |-| Gain |---->      */
     40 /*        |  | Enhance |  |________|  |_____|  |_______|   |___| |______|           */
     41 /*        |  |_________|                                     |                      */
     42 /*        |                                 ___________      |                      */
     43 /*        |                                |           |     |                      */
     44 /*        |------------------------------->| 1 - Alpha |-----|                      */
     45 /*                                         |___________|                            */
     46 /*                                                                                  */
     47 /*  The Stereo Enhancer, Reverb and Equaliser blocks are each configured to have    */
     48 /*  their gain to give a near peak to peak output (-0.1dBFS) with a worst case      */
     49 /*  input signal. The gains of these blocks are re-combined in the Alpha mixer and  */
     50 /*  the gain block folloing the sum.                                                */
     51 /*                                                                                  */
     52 /*  The processing uses the output buffer for data storage after each processing    */
     53 /*  block. When processing is inplace a copy of the input signal is made in scratch */
     54 /*  memory for the 1-Alpha path.                                                    */
     55 /*                                                                                  */
     56 /*                                                                                  */
     57 /* PARAMETERS:                                                                      */
     58 /*  hInstance               Instance handle                                         */
     59 /*  pInData                 Pointer to the input data                               */
     60 /*  pOutData                Pointer to the output data                              */
     61 /*  NumSamples              Number of samples in the input buffer                   */
     62 /*                                                                                  */
     63 /* RETURNS:                                                                         */
     64 /*  LVCS_Success            Succeeded                                               */
     65 /*                                                                                  */
     66 /* NOTES:                                                                           */
     67 /*                                                                                  */
     68 /************************************************************************************/
     69 
     70 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t              hInstance,
     71                                      const LVM_INT16            *pInData,
     72                                      LVM_INT16                  *pOutData,
     73                                      LVM_UINT16                 NumSamples)
     74 {
     75     const LVM_INT16     *pInput;
     76     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
     77     LVM_INT16           *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
     78     LVCS_ReturnStatus_en err;
     79 
     80     /*
     81      * Check if the processing is inplace
     82      */
     83     if (pInData == pOutData)
     84     {
     85         /* Processing inplace */
     86         pInput = pScratch + (2*NumSamples);
     87         Copy_16((LVM_INT16 *)pInData,           /* Source */
     88                 (LVM_INT16 *)pInput,            /* Destination */
     89                 (LVM_INT16)(2*NumSamples));     /* Left and right */
     90     }
     91     else
     92     {
     93         /* Processing outplace */
     94         pInput = pInData;
     95     }
     96 
     97     /*
     98      * Call the stereo enhancer
     99      */
    100     err=LVCS_StereoEnhancer(hInstance,              /* Instance handle */
    101                         pInData,                    /* Pointer to the input data */
    102                         pOutData,                   /* Pointer to the output data */
    103                         NumSamples);                /* Number of samples to process */
    104 
    105     /*
    106      * Call the reverb generator
    107      */
    108     err=LVCS_ReverbGenerator(hInstance,             /* Instance handle */
    109                          pOutData,                  /* Pointer to the input data */
    110                          pOutData,                  /* Pointer to the output data */
    111                          NumSamples);               /* Number of samples to process */
    112 
    113     /*
    114      * Call the equaliser
    115      */
    116     err=LVCS_Equaliser(hInstance,                   /* Instance handle */
    117                    pOutData,                        /* Pointer to the input data */
    118                    NumSamples);                     /* Number of samples to process */
    119 
    120     /*
    121      * Call the bypass mixer
    122      */
    123     err=LVCS_BypassMixer(hInstance,                 /* Instance handle */
    124                      pOutData,                      /* Pointer to the processed data */
    125                      pInput,                        /* Pointer to the input (unprocessed) data */
    126                      pOutData,                      /* Pointer to the output data */
    127                      NumSamples);                   /* Number of samples to process */
    128 
    129     if(err !=LVCS_SUCCESS)
    130     {
    131         return err;
    132     }
    133 
    134     return(LVCS_SUCCESS);
    135 }
    136 
    137 /************************************************************************************/
    138 /*                                                                                  */
    139 /* FUNCTION:                LVCS_Process                                            */
    140 /*                                                                                  */
    141 /* DESCRIPTION:                                                                     */
    142 /*  Process function for the Concert Sound module. The implementation supports two  */
    143 /*  variants of the algorithm, one for headphones and one for mobile speakers.      */
    144 /*                                                                                  */
    145 /*  Data can be processed in two formats, stereo or mono-in-stereo. Data in mono    */
    146 /*  format is not supported, the calling routine must convert the mono stream to    */
    147 /*  mono-in-stereo.                                                                 */
    148 /*                                                                                  */
    149 /*                                                                                  */
    150 /* PARAMETERS:                                                                      */
    151 /*  hInstance               Instance handle                                         */
    152 /*  pInData                 Pointer to the input data                               */
    153 /*  pOutData                Pointer to the output data                              */
    154 /*  NumSamples              Number of samples in the input buffer                   */
    155 /*                                                                                  */
    156 /* RETURNS:                                                                         */
    157 /*  LVCS_Success            Succeeded                                               */
    158 /*  LVCS_TooManySamples     NumSamples was larger than the maximum block size       */
    159 /*                                                                                  */
    160 /* NOTES:                                                                           */
    161 /*                                                                                  */
    162 /************************************************************************************/
    163 
    164 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t             hInstance,
    165                                   const LVM_INT16           *pInData,
    166                                   LVM_INT16                 *pOutData,
    167                                   LVM_UINT16                NumSamples)
    168 {
    169 
    170     LVCS_Instance_t *pInstance =(LVCS_Instance_t  *)hInstance;
    171     LVCS_ReturnStatus_en err;
    172 
    173     /*
    174      * Check the number of samples is not too large
    175      */
    176     if (NumSamples > pInstance->Capabilities.MaxBlockSize)
    177     {
    178         return(LVCS_TOOMANYSAMPLES);
    179     }
    180 
    181     /*
    182      * Check if the algorithm is enabled
    183      */
    184     if (pInstance->Params.OperatingMode != LVCS_OFF)
    185     {
    186         /*
    187          * Call CS process function
    188          */
    189             err=LVCS_Process_CS(hInstance,
    190                             pInData,
    191                             pOutData,
    192                             NumSamples);
    193 
    194         /*
    195          * Compress to reduce expansion effect of Concert Sound and correct volume
    196          * differences for difference settings. Not applied in test modes
    197          */
    198         if ((pInstance->Params.OperatingMode == LVCS_ON)&&(pInstance->Params.CompressorMode == LVM_MODE_ON))
    199         {
    200             LVM_INT16 Gain = pInstance->VolCorrect.CompMin;
    201             LVM_INT32 Current1;
    202 
    203             Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
    204             Gain = (LVM_INT16)(  pInstance->VolCorrect.CompMin
    205                                - (((LVM_INT32)pInstance->VolCorrect.CompMin  * (Current1)) >> 15)
    206                                + (((LVM_INT32)pInstance->VolCorrect.CompFull * (Current1)) >> 15) );
    207 
    208             if(NumSamples < LVCS_COMPGAINFRAME)
    209             {
    210                 NonLinComp_D16(Gain,                    /* Compressor gain setting */
    211                     pOutData,
    212                     pOutData,
    213                     (LVM_INT32)(2*NumSamples));
    214             }
    215             else
    216             {
    217                 LVM_INT16  GainStep;
    218                 LVM_INT16  FinalGain;
    219                 LVM_INT16  SampleToProcess = NumSamples;
    220                 LVM_INT16  *pOutPtr;
    221 
    222                 /* Large changes in Gain can cause clicks in output
    223                    Split data into small blocks and use interpolated gain values */
    224 
    225                 GainStep = (LVM_INT16)(((Gain-pInstance->CompressGain) * LVCS_COMPGAINFRAME)/NumSamples);
    226 
    227                 if((GainStep ==0)&&(pInstance->CompressGain < Gain))
    228                 {
    229                     GainStep=1;
    230                 }
    231                 else
    232                 {
    233                     if((GainStep ==0)&&(pInstance->CompressGain > Gain))
    234                     {
    235                         GainStep=-1;
    236                     }
    237                 }
    238 
    239                 FinalGain = Gain;
    240                 Gain = pInstance->CompressGain;
    241                 pOutPtr = pOutData;
    242 
    243                 while(SampleToProcess > 0)
    244                 {
    245                     Gain = (LVM_INT16)(Gain + GainStep);
    246                     if((GainStep > 0)&& (FinalGain <= Gain))
    247                     {
    248                         Gain = FinalGain;
    249                         GainStep =0;
    250                     }
    251 
    252                     if((GainStep < 0)&& (FinalGain > Gain))
    253                     {
    254                         Gain = FinalGain;
    255                         GainStep =0;
    256                     }
    257 
    258                     if(SampleToProcess > LVCS_COMPGAINFRAME)
    259                     {
    260                         NonLinComp_D16(Gain,                    /* Compressor gain setting */
    261                             pOutPtr,
    262                             pOutPtr,
    263                             (LVM_INT32)(2*LVCS_COMPGAINFRAME));
    264                         pOutPtr +=(2*LVCS_COMPGAINFRAME);
    265                         SampleToProcess = (LVM_INT16)(SampleToProcess-LVCS_COMPGAINFRAME);
    266                     }
    267                     else
    268                     {
    269                         NonLinComp_D16(Gain,                    /* Compressor gain setting */
    270                             pOutPtr,
    271                             pOutPtr,
    272                             (LVM_INT32)(2*SampleToProcess));
    273 
    274                         SampleToProcess = 0;
    275                     }
    276 
    277                 }
    278             }
    279 
    280             /* Store gain value*/
    281             pInstance->CompressGain = Gain;
    282         }
    283 
    284 
    285         if(pInstance->bInOperatingModeTransition == LVM_TRUE){
    286 
    287             /*
    288              * Re-init bypass mix when timer has completed
    289              */
    290             if ((pInstance->bTimerDone == LVM_TRUE) &&
    291                 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
    292             {
    293                 err=LVCS_BypassMixInit(hInstance,
    294                                    &pInstance->Params);
    295 
    296                 if(err != LVCS_SUCCESS)
    297                 {
    298                     return err;
    299                 }
    300 
    301             }
    302             else{
    303                 LVM_Timer ( &pInstance->TimerInstance,
    304                             (LVM_INT16)NumSamples);
    305             }
    306         }
    307     }
    308     else
    309     {
    310         if (pInData != pOutData)
    311         {
    312             /*
    313              * The algorithm is disabled so just copy the data
    314              */
    315             Copy_16((LVM_INT16 *)pInData,               /* Source */
    316                 (LVM_INT16 *)pOutData,                  /* Destination */
    317                 (LVM_INT16)(2*NumSamples));             /* Left and right */
    318         }
    319     }
    320 
    321 
    322     return(LVCS_SUCCESS);
    323 }
    324 
    325 
    326 
    327 
    328 
    329 
    330 
    331 
    332 
    333 
    334