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