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_ReverbGenerator.h"
     27 #include "LVC_Mixer.h"
     28 #include "VectorArithmetic.h"
     29 #include "BIQUAD.h"
     30 #include "LVCS_Tables.h"
     31 
     32 /************************************************************************************/
     33 /*                                                                                  */
     34 /* FUNCTION:                LVCS_ReverbGeneratorInit                                */
     35 /*                                                                                  */
     36 /* DESCRIPTION:                                                                     */
     37 /*  Initialises the reverb module. The delay buffer size is configured for the      */
     38 /*  sample rate and the speaker type.                                               */
     39 /*                                                                                  */
     40 /*  The routine may also be called for re-initialisation, i.e. when one of the      */
     41 /*  control parameters has changed. In this case the delay and filters are only     */
     42 /*  re-initialised if one of the following two conditions is met:                   */
     43 /*      -   the sample rate has changed                                             */
     44 /*      -   the speaker type changes to/from the mobile speaker                     */
     45 /*                                                                                  */
     46 /*                                                                                  */
     47 /* PARAMETERS:                                                                      */
     48 /*  hInstance               Instance Handle                                         */
     49 /*  pParams                 Pointer to the inialisation parameters                  */
     50 /*                                                                                  */
     51 /* RETURNS:                                                                         */
     52 /*  LVCS_Success            Always succeeds                                         */
     53 /*                                                                                  */
     54 /* NOTES:                                                                           */
     55 /*  1.  In the delay settings 'Samples' is the number of samples to the end of the  */
     56 /*      buffer.                                                                     */
     57 /*  2.  The numerator coefficients of the filter are negated to cause an inversion. */
     58 /*                                                                                  */
     59 /************************************************************************************/
     60 #ifdef BUILD_FLOAT
     61 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t     hInstance,
     62                                               LVCS_Params_t     *pParams)
     63 {
     64 
     65     LVM_UINT16              Delay;
     66     LVM_UINT16              Offset;
     67     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
     68     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
     69     LVCS_Data_t             *pData;
     70     LVCS_Coefficient_t      *pCoefficients;
     71     BQ_FLOAT_Coefs_t         Coeffs;
     72     const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
     73 
     74 
     75     pData = (LVCS_Data_t *) \
     76                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
     77 
     78     pCoefficients = (LVCS_Coefficient_t *) \
     79                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
     80 
     81     /*
     82      * Initialise the delay and filters if:
     83      *  - the sample rate has changed
     84      *  - the speaker type has changed to or from the mobile speaker
     85      */
     86     if(pInstance->Params.SampleRate != pParams->SampleRate )      /* Sample rate change test */
     87 
     88     {
     89         /*
     90          * Setup the delay
     91          */
     92         Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
     93 
     94 
     95         pConfig->DelaySize      = (LVM_INT16)(2 * Delay);
     96         pConfig->DelayOffset    = 0;
     97         LoadConst_Float(0,                                            /* Value */
     98                         (LVM_FLOAT *)&pConfig->StereoSamples[0],      /* Destination */
     99                         /* Number of words */
    100                         (LVM_UINT16)(sizeof(pConfig->StereoSamples) / sizeof(LVM_FLOAT)));
    101         /*
    102          * Setup the filters
    103          */
    104         Offset = (LVM_UINT16)pParams->SampleRate;
    105         pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
    106 
    107         /* Convert incoming coefficients to the required format/ordering */
    108         Coeffs.A0 = (LVM_FLOAT)pReverbCoefTable[Offset].A0;
    109         Coeffs.A1 = (LVM_FLOAT)pReverbCoefTable[Offset].A1;
    110         Coeffs.A2 = (LVM_FLOAT)pReverbCoefTable[Offset].A2;
    111         Coeffs.B1 = (LVM_FLOAT)-pReverbCoefTable[Offset].B1;
    112         Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2;
    113 
    114         LoadConst_Float(0,                                 /* Value */
    115                         (void *)&pData->ReverbBiquadTaps,  /* Destination Cast to void:
    116                                                              no dereferencing in function*/
    117                         /* Number of words */
    118                         (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT)));
    119 
    120         BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
    121                                         &pData->ReverbBiquadTaps,
    122                                         &Coeffs);
    123 
    124         /* Callbacks */
    125         switch(pReverbCoefTable[Offset].Scale)
    126         {
    127             case 14:
    128                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C14_TRC_WRA_01;
    129                 break;
    130             case 15:
    131                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C15_TRC_WRA_01;
    132                 break;
    133         }
    134 
    135 
    136         /*
    137          * Setup the mixer
    138          */
    139         pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
    140         pConfig->UnprocGain  = (LVM_UINT16)(HEADPHONEGAINUNPROC);
    141     }
    142 
    143     if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
    144     {
    145         LVM_INT32   ReverbPercentage = 83886;      // 1 Percent Reverb i.e 1/100 in Q 23 format
    146         ReverbPercentage *= pParams->ReverbLevel;  // Actual Reverb Level in Q 23 format
    147         pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage>>8)) / 32767.0f;
    148     }
    149     return(LVCS_SUCCESS);
    150 }
    151 #else
    152 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t     hInstance,
    153                                               LVCS_Params_t     *pParams)
    154 {
    155 
    156     LVM_UINT16              Delay;
    157     LVM_UINT16              Offset;
    158     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
    159     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
    160     LVCS_Data_t             *pData     = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
    161     LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
    162     BQ_C16_Coefs_t          Coeffs;
    163     const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
    164 
    165     /*
    166      * Initialise the delay and filters if:
    167      *  - the sample rate has changed
    168      *  - the speaker type has changed to or from the mobile speaker
    169      */
    170     if(pInstance->Params.SampleRate != pParams->SampleRate )      /* Sample rate change test */
    171 
    172     {
    173         /*
    174          * Setup the delay
    175          */
    176         Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
    177 
    178 
    179         pConfig->DelaySize      = (LVM_INT16)(2 * Delay);
    180         pConfig->DelayOffset    = 0;
    181         LoadConst_16(0,                                                                 /* Value */
    182                      (LVM_INT16 *)&pConfig->StereoSamples[0],                           /* Destination */
    183                      (LVM_UINT16)(sizeof(pConfig->StereoSamples)/sizeof(LVM_INT16)));   /* Number of words */
    184 
    185         /*
    186          * Setup the filters
    187          */
    188         Offset = (LVM_UINT16)pParams->SampleRate;
    189         pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
    190 
    191         /* Convert incoming coefficients to the required format/ordering */
    192         Coeffs.A0 = (LVM_INT16)pReverbCoefTable[Offset].A0;
    193         Coeffs.A1 = (LVM_INT16)pReverbCoefTable[Offset].A1;
    194         Coeffs.A2 = (LVM_INT16)pReverbCoefTable[Offset].A2;
    195         Coeffs.B1 = (LVM_INT16)-pReverbCoefTable[Offset].B1;
    196         Coeffs.B2 = (LVM_INT16)-pReverbCoefTable[Offset].B2;
    197 
    198         LoadConst_16(0,                                                                 /* Value */
    199                      (void *)&pData->ReverbBiquadTaps,                             /* Destination Cast to void: no dereferencing in function*/
    200                      (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps)/sizeof(LVM_INT16)));  /* Number of words */
    201 
    202         BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
    203                                         &pData->ReverbBiquadTaps,
    204                                         &Coeffs);
    205 
    206         /* Callbacks */
    207         switch(pReverbCoefTable[Offset].Scale)
    208         {
    209             case 14:
    210                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C14_TRC_WRA_01;
    211                 break;
    212             case 15:
    213                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C15_TRC_WRA_01;
    214                 break;
    215         }
    216 
    217 
    218         /*
    219          * Setup the mixer
    220          */
    221         pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
    222         pConfig->UnprocGain  = (LVM_UINT16)(HEADPHONEGAINUNPROC);
    223     }
    224 
    225     if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
    226     {
    227         LVM_INT32   ReverbPercentage=83886;                     // 1 Percent Reverb i.e 1/100 in Q 23 format
    228         ReverbPercentage*=pParams->ReverbLevel;                 // Actual Reverb Level in Q 23 format
    229         pConfig->ReverbLevel=(LVM_INT16)(ReverbPercentage>>8);  // Reverb Level in Q 15 format
    230     }
    231 
    232     return(LVCS_SUCCESS);
    233 }
    234 #endif
    235 /************************************************************************************/
    236 /*                                                                                  */
    237 /* FUNCTION:                LVCS_Reverb                                             */
    238 /*                                                                                  */
    239 /* DESCRIPTION:                                                                     */
    240 /*  Create reverb using the block of input samples based on the following block     */
    241 /*  diagram:                                                                        */
    242 /*                           ________              ________                         */
    243 /*                          |        |            |        |                        */
    244 /*     _____     _______    |        |----------->|        |    ______     ___      */
    245 /*    |     |   |       |   | Stereo |            | L & R  |   |      |   |   |     */
    246 /* -->| LPF |-->| Delay |-->|   to   |    ____    |   to   |-->| Gain |-->| + |-->  */
    247 /*  | |_____|   |_______|   | L & R  |   |    |   | Stereo |   |______|   |___|     */
    248 /*  |                       |        |-->| -1 |-->|        |                |       */
    249 /*  |                       |________|   |____|   |________|                |       */
    250 /*  |                                                                       |       */
    251 /*  |-----------------------------------------------------------------------|       */
    252 /*                                                                                  */
    253 /*  The input buffer is broken in to sub-blocks of the size of the delay or less.   */
    254 /*  This allows the delay buffer to be treated as a circular buffer but processed   */
    255 /*  as a linear buffer.                                                             */
    256 /*                                                                                  */
    257 /*                                                                                  */
    258 /* PARAMETERS:                                                                      */
    259 /*  hInstance               Instance Handle                                         */
    260 /*  pInData                 Pointer to the input buffer                             */
    261 /*  pOutData                Pointer to the output buffer                            */
    262 /*  NumSamples              Number of samples to process                            */
    263 /*                                                                                  */
    264 /* RETURNS:                                                                         */
    265 /*  LVCS_Success            Always succeeds                                         */
    266 /*                                                                                  */
    267 /* NOTES:                                                                           */
    268 /*  1.  Process in blocks of samples the size of the delay where possible, if not   */
    269 /*      the number of samples left over                                             */
    270 /*  2.  The Gain is combined with the LPF and incorporated in to the coefficients   */
    271 /*                                                                                  */
    272 /************************************************************************************/
    273 #ifdef BUILD_FLOAT
    274 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t         hInstance,
    275                                           const LVM_FLOAT       *pInData,
    276                                           LVM_FLOAT             *pOutData,
    277                                           LVM_UINT16            NumSamples)
    278 {
    279 
    280     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
    281     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
    282     LVCS_Coefficient_t      *pCoefficients;
    283     LVM_FLOAT               *pScratch;
    284 
    285     pCoefficients = (LVCS_Coefficient_t *)\
    286                    pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
    287 
    288     pScratch  = (LVM_FLOAT *)\
    289                     pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
    290 
    291     /*
    292      * Copy the data to the output in outplace processing
    293      */
    294     if (pInData != pOutData)
    295     {
    296         /*
    297          * Reverb not required so just copy the data
    298          */
    299         Copy_Float((LVM_FLOAT *)pInData,                                       /* Source */
    300                    (LVM_FLOAT *)pOutData,                                      /* Destination */
    301                    (LVM_INT16)(2 * NumSamples));                                 /* Left and right */
    302     }
    303 
    304 
    305     /*
    306      * Check if the reverb is required
    307      */
    308     /* Disable when CS4MS in stereo mode */
    309     if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || \
    310          (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
    311          (pInstance->Params.SourceFormat != LVCS_STEREO))  &&
    312                                     /* For validation testing */
    313         ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))
    314     {
    315         /********************************************************************************/
    316         /*                                                                              */
    317         /* Copy the input data to scratch memory and filter it                          */
    318         /*                                                                              */
    319         /********************************************************************************/
    320 
    321         /*
    322          * Copy the input data to the scratch memory
    323          */
    324         Copy_Float((LVM_FLOAT *)pInData,                                     /* Source */
    325                    (LVM_FLOAT *)pScratch,                                    /* Destination */
    326                    (LVM_INT16)(2 * NumSamples));                               /* Left and right */
    327 
    328         /*
    329          * Filter the data
    330          */
    331         (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*)&pCoefficients->ReverbBiquadInstance,
    332                                    (LVM_FLOAT *)pScratch,
    333                                    (LVM_FLOAT *)pScratch,
    334                                    (LVM_INT16)NumSamples);
    335 
    336         Mult3s_Float( (LVM_FLOAT *)pScratch,
    337                       pConfig->ReverbLevel,
    338                       (LVM_FLOAT *)pScratch,
    339                       (LVM_INT16)(2 * NumSamples));
    340 
    341 
    342         /*
    343          * Apply the delay mix
    344          */
    345         DelayMix_Float((LVM_FLOAT *)pScratch,
    346                        &pConfig->StereoSamples[0],
    347                        pConfig->DelaySize,
    348                        pOutData,
    349                        &pConfig->DelayOffset,
    350                        (LVM_INT16)NumSamples);
    351 
    352 
    353     }
    354 
    355     return(LVCS_SUCCESS);
    356 }
    357 #else
    358 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t         hInstance,
    359                                           const LVM_INT16       *pInData,
    360                                           LVM_INT16             *pOutData,
    361                                           LVM_UINT16            NumSamples)
    362 {
    363 
    364     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
    365     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
    366     LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
    367     LVM_INT16               *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
    368 
    369 
    370     /*
    371      * Copy the data to the output in outplace processing
    372      */
    373     if (pInData != pOutData)
    374     {
    375         /*
    376          * Reverb not required so just copy the data
    377          */
    378         Copy_16((LVM_INT16 *)pInData,                                       /* Source */
    379                 (LVM_INT16 *)pOutData,                                      /* Destination */
    380                 (LVM_INT16)(2*NumSamples));                                 /* Left and right */
    381     }
    382 
    383 
    384     /*
    385      * Check if the reverb is required
    386      */
    387     if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) ||           /* Disable when CS4MS in stereo mode */
    388          (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
    389          (pInstance->Params.SourceFormat != LVCS_STEREO))  &&
    390         ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))    /* For validation testing */
    391     {
    392         /********************************************************************************/
    393         /*                                                                              */
    394         /* Copy the input data to scratch memory and filter it                          */
    395         /*                                                                              */
    396         /********************************************************************************/
    397 
    398         /*
    399          * Copy the input data to the scratch memory
    400          */
    401         Copy_16((LVM_INT16 *)pInData,                                     /* Source */
    402                 (LVM_INT16 *)pScratch,                                    /* Destination */
    403                 (LVM_INT16)(2*NumSamples));                               /* Left and right */
    404 
    405 
    406         /*
    407          * Filter the data
    408          */
    409         (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->ReverbBiquadInstance,
    410                                    (LVM_INT16 *)pScratch,
    411                                    (LVM_INT16 *)pScratch,
    412                                    (LVM_INT16)NumSamples);
    413 
    414         Mult3s_16x16( (LVM_INT16 *)pScratch,
    415                       pConfig->ReverbLevel,
    416                       (LVM_INT16 *)pScratch,
    417                       (LVM_INT16)(2*NumSamples));
    418 
    419 
    420         /*
    421          * Apply the delay mix
    422          */
    423         DelayMix_16x16((LVM_INT16 *)pScratch,
    424                        &pConfig->StereoSamples[0],
    425                        pConfig->DelaySize,
    426                        pOutData,
    427                        &pConfig->DelayOffset,
    428                        (LVM_INT16)NumSamples);
    429 
    430 
    431     }
    432 
    433     return(LVCS_SUCCESS);
    434 }
    435 #endif
    436