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 #ifdef BUILD_FLOAT
     70 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t              hInstance,
     71                                      const LVM_FLOAT            *pInData,
     72                                      LVM_FLOAT                  *pOutData,
     73                                      LVM_UINT16                 NumSamples)
     74 {
     75     const LVM_FLOAT     *pInput;
     76     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
     77     LVM_FLOAT           *pScratch;
     78     LVCS_ReturnStatus_en err;
     79 
     80     pScratch  = (LVM_FLOAT *) \
     81                   pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
     82 
     83     /*
     84      * Check if the processing is inplace
     85      */
     86     if (pInData == pOutData)
     87     {
     88         /* Processing inplace */
     89         pInput = pScratch + (2 * NumSamples);
     90         Copy_Float((LVM_FLOAT *)pInData,           /* Source */
     91                    (LVM_FLOAT *)pInput,            /* Destination */
     92                    (LVM_INT16)(2 * NumSamples));     /* Left and right */
     93     }
     94     else
     95     {
     96         /* Processing outplace */
     97         pInput = pInData;
     98     }
     99 
    100     /*
    101      * Call the stereo enhancer
    102      */
    103     err = LVCS_StereoEnhancer(hInstance,              /* Instance handle */
    104                               pInData,                    /* Pointer to the input data */
    105                               pOutData,                   /* Pointer to the output data */
    106                               NumSamples);                /* Number of samples to process */
    107 
    108     /*
    109      * Call the reverb generator
    110      */
    111     err = LVCS_ReverbGenerator(hInstance,             /* Instance handle */
    112                                pOutData,                  /* Pointer to the input data */
    113                                pOutData,                  /* Pointer to the output data */
    114                                NumSamples);               /* Number of samples to process */
    115 
    116     /*
    117      * Call the equaliser
    118      */
    119     err = LVCS_Equaliser(hInstance,                   /* Instance handle */
    120                          pOutData,                        /* Pointer to the input data */
    121                          NumSamples);                     /* Number of samples to process */
    122 
    123     /*
    124      * Call the bypass mixer
    125      */
    126     err = LVCS_BypassMixer(hInstance,                 /* Instance handle */
    127                            pOutData,                      /* Pointer to the processed data */
    128                            pInput,                        /* Pointer to the input (unprocessed) data */
    129                            pOutData,                      /* Pointer to the output data */
    130                            NumSamples);                   /* Number of samples to process */
    131 
    132     if(err != LVCS_SUCCESS)
    133     {
    134         return err;
    135     }
    136 
    137     return(LVCS_SUCCESS);
    138 }
    139 #else
    140 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t              hInstance,
    141                                      const LVM_INT16            *pInData,
    142                                      LVM_INT16                  *pOutData,
    143                                      LVM_UINT16                 NumSamples)
    144 {
    145     const LVM_INT16     *pInput;
    146     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
    147     LVM_INT16           *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
    148     LVCS_ReturnStatus_en err;
    149 
    150     /*
    151      * Check if the processing is inplace
    152      */
    153     if (pInData == pOutData)
    154     {
    155         /* Processing inplace */
    156         pInput = pScratch + (2*NumSamples);
    157         Copy_16((LVM_INT16 *)pInData,           /* Source */
    158                 (LVM_INT16 *)pInput,            /* Destination */
    159                 (LVM_INT16)(2*NumSamples));     /* Left and right */
    160     }
    161     else
    162     {
    163         /* Processing outplace */
    164         pInput = pInData;
    165     }
    166 
    167     /*
    168      * Call the stereo enhancer
    169      */
    170     err=LVCS_StereoEnhancer(hInstance,              /* Instance handle */
    171                         pInData,                    /* Pointer to the input data */
    172                         pOutData,                   /* Pointer to the output data */
    173                         NumSamples);                /* Number of samples to process */
    174 
    175     /*
    176      * Call the reverb generator
    177      */
    178     err=LVCS_ReverbGenerator(hInstance,             /* Instance handle */
    179                          pOutData,                  /* Pointer to the input data */
    180                          pOutData,                  /* Pointer to the output data */
    181                          NumSamples);               /* Number of samples to process */
    182 
    183     /*
    184      * Call the equaliser
    185      */
    186     err=LVCS_Equaliser(hInstance,                   /* Instance handle */
    187                    pOutData,                        /* Pointer to the input data */
    188                    NumSamples);                     /* Number of samples to process */
    189 
    190     /*
    191      * Call the bypass mixer
    192      */
    193     err=LVCS_BypassMixer(hInstance,                 /* Instance handle */
    194                      pOutData,                      /* Pointer to the processed data */
    195                      pInput,                        /* Pointer to the input (unprocessed) data */
    196                      pOutData,                      /* Pointer to the output data */
    197                      NumSamples);                   /* Number of samples to process */
    198 
    199     if(err !=LVCS_SUCCESS)
    200     {
    201         return err;
    202     }
    203 
    204     return(LVCS_SUCCESS);
    205 }
    206 #endif
    207 /************************************************************************************/
    208 /*                                                                                  */
    209 /* FUNCTION:                LVCS_Process                                            */
    210 /*                                                                                  */
    211 /* DESCRIPTION:                                                                     */
    212 /*  Process function for the Concert Sound module. The implementation supports two  */
    213 /*  variants of the algorithm, one for headphones and one for mobile speakers.      */
    214 /*                                                                                  */
    215 /*  Data can be processed in two formats, stereo or mono-in-stereo. Data in mono    */
    216 /*  format is not supported, the calling routine must convert the mono stream to    */
    217 /*  mono-in-stereo.                                                                 */
    218 /*                                                                                  */
    219 /*                                                                                  */
    220 /* PARAMETERS:                                                                      */
    221 /*  hInstance               Instance handle                                         */
    222 /*  pInData                 Pointer to the input data                               */
    223 /*  pOutData                Pointer to the output data                              */
    224 /*  NumSamples              Number of samples in the input buffer                   */
    225 /*                                                                                  */
    226 /* RETURNS:                                                                         */
    227 /*  LVCS_Success            Succeeded                                               */
    228 /*  LVCS_TooManySamples     NumSamples was larger than the maximum block size       */
    229 /*                                                                                  */
    230 /* NOTES:                                                                           */
    231 /*                                                                                  */
    232 /************************************************************************************/
    233 #ifdef BUILD_FLOAT
    234 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t             hInstance,
    235                                   const LVM_FLOAT           *pInData,
    236                                   LVM_FLOAT                 *pOutData,
    237                                   LVM_UINT16                NumSamples)
    238 {
    239 
    240     LVCS_Instance_t *pInstance = (LVCS_Instance_t  *)hInstance;
    241     LVCS_ReturnStatus_en err;
    242 
    243     /*
    244      * Check the number of samples is not too large
    245      */
    246     if (NumSamples > pInstance->Capabilities.MaxBlockSize)
    247     {
    248         return(LVCS_TOOMANYSAMPLES);
    249     }
    250 
    251     /*
    252      * Check if the algorithm is enabled
    253      */
    254     if (pInstance->Params.OperatingMode != LVCS_OFF)
    255     {
    256         /*
    257          * Call CS process function
    258          */
    259             err = LVCS_Process_CS(hInstance,
    260                                   pInData,
    261                                   pOutData,
    262                                   NumSamples);
    263 
    264 
    265         /*
    266          * Compress to reduce expansion effect of Concert Sound and correct volume
    267          * differences for difference settings. Not applied in test modes
    268          */
    269         if ((pInstance->Params.OperatingMode == LVCS_ON)&& \
    270                                         (pInstance->Params.CompressorMode == LVM_MODE_ON))
    271         {
    272             LVM_FLOAT Gain = pInstance->VolCorrect.CompMin;
    273             LVM_FLOAT Current1;
    274 
    275             Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
    276             Gain = (LVM_FLOAT)(  pInstance->VolCorrect.CompMin
    277                                - (((LVM_FLOAT)pInstance->VolCorrect.CompMin  * (Current1)))
    278                                + (((LVM_FLOAT)pInstance->VolCorrect.CompFull * (Current1))));
    279 
    280             if(NumSamples < LVCS_COMPGAINFRAME)
    281             {
    282                 NonLinComp_Float(Gain,                    /* Compressor gain setting */
    283                                  pOutData,
    284                                  pOutData,
    285                                  (LVM_INT32)(2 * NumSamples));
    286             }
    287             else
    288             {
    289                 LVM_FLOAT  GainStep;
    290                 LVM_FLOAT  FinalGain;
    291                 LVM_INT16  SampleToProcess = NumSamples;
    292                 LVM_FLOAT  *pOutPtr;
    293 
    294                 /* Large changes in Gain can cause clicks in output
    295                    Split data into small blocks and use interpolated gain values */
    296 
    297                 GainStep = (LVM_FLOAT)(((Gain-pInstance->CompressGain) * \
    298                                                 LVCS_COMPGAINFRAME) / NumSamples);
    299 
    300                 if((GainStep == 0) && (pInstance->CompressGain < Gain))
    301                 {
    302                     GainStep = 1;
    303                 }
    304                 else
    305                 {
    306                     if((GainStep == 0) && (pInstance->CompressGain > Gain))
    307                     {
    308                         GainStep = -1;
    309                     }
    310                 }
    311 
    312                 FinalGain = Gain;
    313                 Gain = pInstance->CompressGain;
    314                 pOutPtr = pOutData;
    315 
    316                 while(SampleToProcess > 0)
    317                 {
    318                     Gain = (LVM_FLOAT)(Gain + GainStep);
    319                     if((GainStep > 0) && (FinalGain <= Gain))
    320                     {
    321                         Gain = FinalGain;
    322                         GainStep = 0;
    323                     }
    324 
    325                     if((GainStep < 0) && (FinalGain > Gain))
    326                     {
    327                         Gain = FinalGain;
    328                         GainStep = 0;
    329                     }
    330 
    331                     if(SampleToProcess > LVCS_COMPGAINFRAME)
    332                     {
    333                         NonLinComp_Float(Gain,                    /* Compressor gain setting */
    334                                          pOutPtr,
    335                                          pOutPtr,
    336                                          (LVM_INT32)(2 * LVCS_COMPGAINFRAME));
    337                         pOutPtr += (2 * LVCS_COMPGAINFRAME);
    338                         SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
    339                     }
    340                     else
    341                     {
    342                         NonLinComp_Float(Gain,                    /* Compressor gain setting */
    343                                          pOutPtr,
    344                                          pOutPtr,
    345                                          (LVM_INT32)(2 * SampleToProcess));
    346                         SampleToProcess = 0;
    347                     }
    348 
    349                 }
    350             }
    351 
    352             /* Store gain value*/
    353             pInstance->CompressGain = Gain;
    354         }
    355 
    356 
    357         if(pInstance->bInOperatingModeTransition == LVM_TRUE){
    358 
    359             /*
    360              * Re-init bypass mix when timer has completed
    361              */
    362             if ((pInstance->bTimerDone == LVM_TRUE) &&
    363                 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
    364             {
    365                 err = LVCS_BypassMixInit(hInstance,
    366                                          &pInstance->Params);
    367 
    368                 if(err != LVCS_SUCCESS)
    369                 {
    370                     return err;
    371                 }
    372 
    373             }
    374             else{
    375                 LVM_Timer ( &pInstance->TimerInstance,
    376                             (LVM_INT16)NumSamples);
    377             }
    378         }
    379     }
    380     else
    381     {
    382         if (pInData != pOutData)
    383         {
    384             /*
    385              * The algorithm is disabled so just copy the data
    386              */
    387             Copy_Float((LVM_FLOAT *)pInData,               /* Source */
    388                        (LVM_FLOAT *)pOutData,                  /* Destination */
    389                        (LVM_INT16)(2 * NumSamples));             /* Left and right */
    390         }
    391     }
    392 
    393 
    394     return(LVCS_SUCCESS);
    395 }
    396 #else
    397 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t             hInstance,
    398                                   const LVM_INT16           *pInData,
    399                                   LVM_INT16                 *pOutData,
    400                                   LVM_UINT16                NumSamples)
    401 {
    402 
    403     LVCS_Instance_t *pInstance =(LVCS_Instance_t  *)hInstance;
    404     LVCS_ReturnStatus_en err;
    405 
    406     /*
    407      * Check the number of samples is not too large
    408      */
    409     if (NumSamples > pInstance->Capabilities.MaxBlockSize)
    410     {
    411         return(LVCS_TOOMANYSAMPLES);
    412     }
    413 
    414     /*
    415      * Check if the algorithm is enabled
    416      */
    417     if (pInstance->Params.OperatingMode != LVCS_OFF)
    418     {
    419         /*
    420          * Call CS process function
    421          */
    422             err=LVCS_Process_CS(hInstance,
    423                             pInData,
    424                             pOutData,
    425                             NumSamples);
    426 
    427         /*
    428          * Compress to reduce expansion effect of Concert Sound and correct volume
    429          * differences for difference settings. Not applied in test modes
    430          */
    431         if ((pInstance->Params.OperatingMode == LVCS_ON)&&(pInstance->Params.CompressorMode == LVM_MODE_ON))
    432         {
    433             LVM_INT16 Gain = pInstance->VolCorrect.CompMin;
    434             LVM_INT32 Current1;
    435 
    436             Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
    437             Gain = (LVM_INT16)(  pInstance->VolCorrect.CompMin
    438                                - (((LVM_INT32)pInstance->VolCorrect.CompMin  * (Current1)) >> 15)
    439                                + (((LVM_INT32)pInstance->VolCorrect.CompFull * (Current1)) >> 15) );
    440 
    441             if(NumSamples < LVCS_COMPGAINFRAME)
    442             {
    443                 NonLinComp_D16(Gain,                    /* Compressor gain setting */
    444                     pOutData,
    445                     pOutData,
    446                     (LVM_INT32)(2*NumSamples));
    447             }
    448             else
    449             {
    450                 LVM_INT16  GainStep;
    451                 LVM_INT16  FinalGain;
    452                 LVM_INT16  SampleToProcess = NumSamples;
    453                 LVM_INT16  *pOutPtr;
    454 
    455                 /* Large changes in Gain can cause clicks in output
    456                    Split data into small blocks and use interpolated gain values */
    457 
    458                 GainStep = (LVM_INT16)(((Gain-pInstance->CompressGain) * LVCS_COMPGAINFRAME)/NumSamples);
    459 
    460                 if((GainStep ==0)&&(pInstance->CompressGain < Gain))
    461                 {
    462                     GainStep=1;
    463                 }
    464                 else
    465                 {
    466                     if((GainStep ==0)&&(pInstance->CompressGain > Gain))
    467                     {
    468                         GainStep=-1;
    469                     }
    470                 }
    471 
    472                 FinalGain = Gain;
    473                 Gain = pInstance->CompressGain;
    474                 pOutPtr = pOutData;
    475 
    476                 while(SampleToProcess > 0)
    477                 {
    478                     Gain = (LVM_INT16)(Gain + GainStep);
    479                     if((GainStep > 0)&& (FinalGain <= Gain))
    480                     {
    481                         Gain = FinalGain;
    482                         GainStep =0;
    483                     }
    484 
    485                     if((GainStep < 0)&& (FinalGain > Gain))
    486                     {
    487                         Gain = FinalGain;
    488                         GainStep =0;
    489                     }
    490 
    491                     if(SampleToProcess > LVCS_COMPGAINFRAME)
    492                     {
    493                         NonLinComp_D16(Gain,                    /* Compressor gain setting */
    494                             pOutPtr,
    495                             pOutPtr,
    496                             (LVM_INT32)(2*LVCS_COMPGAINFRAME));
    497                         pOutPtr +=(2*LVCS_COMPGAINFRAME);
    498                         SampleToProcess = (LVM_INT16)(SampleToProcess-LVCS_COMPGAINFRAME);
    499                     }
    500                     else
    501                     {
    502                         NonLinComp_D16(Gain,                    /* Compressor gain setting */
    503                             pOutPtr,
    504                             pOutPtr,
    505                             (LVM_INT32)(2*SampleToProcess));
    506 
    507                         SampleToProcess = 0;
    508                     }
    509 
    510                 }
    511             }
    512 
    513             /* Store gain value*/
    514             pInstance->CompressGain = Gain;
    515         }
    516 
    517 
    518         if(pInstance->bInOperatingModeTransition == LVM_TRUE){
    519 
    520             /*
    521              * Re-init bypass mix when timer has completed
    522              */
    523             if ((pInstance->bTimerDone == LVM_TRUE) &&
    524                 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
    525             {
    526                 err=LVCS_BypassMixInit(hInstance,
    527                                    &pInstance->Params);
    528 
    529                 if(err != LVCS_SUCCESS)
    530                 {
    531                     return err;
    532                 }
    533 
    534             }
    535             else{
    536                 LVM_Timer ( &pInstance->TimerInstance,
    537                             (LVM_INT16)NumSamples);
    538             }
    539         }
    540     }
    541     else
    542     {
    543         if (pInData != pOutData)
    544         {
    545             /*
    546              * The algorithm is disabled so just copy the data
    547              */
    548             Copy_16((LVM_INT16 *)pInData,               /* Source */
    549                 (LVM_INT16 *)pOutData,                  /* Destination */
    550                 (LVM_INT16)(2*NumSamples));             /* Left and right */
    551         }
    552     }
    553 
    554 
    555     return(LVCS_SUCCESS);
    556 }
    557 #endif
    558