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 
     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     = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
     70     LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
     71     BQ_C16_Coefs_t          Coeffs;
     72     const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
     73 
     74     /*
     75      * Initialise the delay and filters if:
     76      *  - the sample rate has changed
     77      *  - the speaker type has changed to or from the mobile speaker
     78      */
     79     if(pInstance->Params.SampleRate != pParams->SampleRate )      /* Sample rate change test */
     80 
     81     {
     82         /*
     83          * Setup the delay
     84          */
     85         Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
     86 
     87 
     88         pConfig->DelaySize      = (LVM_INT16)(2 * Delay);
     89         pConfig->DelayOffset    = 0;
     90         LoadConst_16(0,                                                                 /* Value */
     91                      (LVM_INT16 *)&pConfig->StereoSamples[0],                           /* Destination */
     92                      (LVM_UINT16)(sizeof(pConfig->StereoSamples)/sizeof(LVM_INT16)));   /* Number of words */
     93 
     94         /*
     95          * Setup the filters
     96          */
     97         Offset = (LVM_UINT16)pParams->SampleRate;
     98         pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
     99 
    100         /* Convert incoming coefficients to the required format/ordering */
    101         Coeffs.A0 = (LVM_INT16)pReverbCoefTable[Offset].A0;
    102         Coeffs.A1 = (LVM_INT16)pReverbCoefTable[Offset].A1;
    103         Coeffs.A2 = (LVM_INT16)pReverbCoefTable[Offset].A2;
    104         Coeffs.B1 = (LVM_INT16)-pReverbCoefTable[Offset].B1;
    105         Coeffs.B2 = (LVM_INT16)-pReverbCoefTable[Offset].B2;
    106 
    107         LoadConst_16(0,                                                                 /* Value */
    108                      (void *)&pData->ReverbBiquadTaps,                             /* Destination Cast to void: no dereferencing in function*/
    109                      (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps)/sizeof(LVM_INT16)));  /* Number of words */
    110 
    111         BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
    112                                         &pData->ReverbBiquadTaps,
    113                                         &Coeffs);
    114 
    115         /* Callbacks */
    116         switch(pReverbCoefTable[Offset].Scale)
    117         {
    118             case 14:
    119                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C14_TRC_WRA_01;
    120                 break;
    121             case 15:
    122                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C15_TRC_WRA_01;
    123                 break;
    124         }
    125 
    126 
    127         /*
    128          * Setup the mixer
    129          */
    130         pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
    131         pConfig->UnprocGain  = (LVM_UINT16)(HEADPHONEGAINUNPROC);
    132     }
    133 
    134     if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
    135     {
    136         LVM_INT32   ReverbPercentage=83886;                     // 1 Percent Reverb i.e 1/100 in Q 23 format
    137         ReverbPercentage*=pParams->ReverbLevel;                 // Actual Reverb Level in Q 23 format
    138         pConfig->ReverbLevel=(LVM_INT16)(ReverbPercentage>>8);  // Reverb Level in Q 15 format
    139     }
    140 
    141     return(LVCS_SUCCESS);
    142 }
    143 
    144 /************************************************************************************/
    145 /*                                                                                  */
    146 /* FUNCTION:                LVCS_Reverb                                             */
    147 /*                                                                                  */
    148 /* DESCRIPTION:                                                                     */
    149 /*  Create reverb using the block of input samples based on the following block     */
    150 /*  diagram:                                                                        */
    151 /*                           ________              ________                         */
    152 /*                          |        |            |        |                        */
    153 /*     _____     _______    |        |----------->|        |    ______     ___      */
    154 /*    |     |   |       |   | Stereo |            | L & R  |   |      |   |   |     */
    155 /* -->| LPF |-->| Delay |-->|   to   |    ____    |   to   |-->| Gain |-->| + |-->  */
    156 /*  | |_____|   |_______|   | L & R  |   |    |   | Stereo |   |______|   |___|     */
    157 /*  |                       |        |-->| -1 |-->|        |                |       */
    158 /*  |                       |________|   |____|   |________|                |       */
    159 /*  |                                                                       |       */
    160 /*  |-----------------------------------------------------------------------|       */
    161 /*                                                                                  */
    162 /*  The input buffer is broken in to sub-blocks of the size of the delay or less.   */
    163 /*  This allows the delay buffer to be treated as a circular buffer but processed   */
    164 /*  as a linear buffer.                                                             */
    165 /*                                                                                  */
    166 /*                                                                                  */
    167 /* PARAMETERS:                                                                      */
    168 /*  hInstance               Instance Handle                                         */
    169 /*  pInData                 Pointer to the input buffer                             */
    170 /*  pOutData                Pointer to the output buffer                            */
    171 /*  NumSamples              Number of samples to process                            */
    172 /*                                                                                  */
    173 /* RETURNS:                                                                         */
    174 /*  LVCS_Success            Always succeeds                                         */
    175 /*                                                                                  */
    176 /* NOTES:                                                                           */
    177 /*  1.  Process in blocks of samples the size of the delay where possible, if not   */
    178 /*      the number of samples left over                                             */
    179 /*  2.  The Gain is combined with the LPF and incorporated in to the coefficients   */
    180 /*                                                                                  */
    181 /************************************************************************************/
    182 
    183 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t         hInstance,
    184                                           const LVM_INT16       *pInData,
    185                                           LVM_INT16             *pOutData,
    186                                           LVM_UINT16            NumSamples)
    187 {
    188 
    189     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
    190     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
    191     LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
    192     LVM_INT16               *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
    193 
    194 
    195     /*
    196      * Copy the data to the output in outplace processing
    197      */
    198     if (pInData != pOutData)
    199     {
    200         /*
    201          * Reverb not required so just copy the data
    202          */
    203         Copy_16((LVM_INT16 *)pInData,                                       /* Source */
    204                 (LVM_INT16 *)pOutData,                                      /* Destination */
    205                 (LVM_INT16)(2*NumSamples));                                 /* Left and right */
    206     }
    207 
    208 
    209     /*
    210      * Check if the reverb is required
    211      */
    212     if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) ||           /* Disable when CS4MS in stereo mode */
    213          (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
    214          (pInstance->Params.SourceFormat != LVCS_STEREO))  &&
    215         ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))    /* For validation testing */
    216     {
    217         /********************************************************************************/
    218         /*                                                                              */
    219         /* Copy the input data to scratch memory and filter it                          */
    220         /*                                                                              */
    221         /********************************************************************************/
    222 
    223         /*
    224          * Copy the input data to the scratch memory
    225          */
    226         Copy_16((LVM_INT16 *)pInData,                                     /* Source */
    227                 (LVM_INT16 *)pScratch,                                    /* Destination */
    228                 (LVM_INT16)(2*NumSamples));                               /* Left and right */
    229 
    230 
    231         /*
    232          * Filter the data
    233          */
    234         (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->ReverbBiquadInstance,
    235                                    (LVM_INT16 *)pScratch,
    236                                    (LVM_INT16 *)pScratch,
    237                                    (LVM_INT16)NumSamples);
    238 
    239         Mult3s_16x16( (LVM_INT16 *)pScratch,
    240                       pConfig->ReverbLevel,
    241                       (LVM_INT16 *)pScratch,
    242                       (LVM_INT16)(2*NumSamples));
    243 
    244 
    245         /*
    246          * Apply the delay mix
    247          */
    248         DelayMix_16x16((LVM_INT16 *)pScratch,
    249                        &pConfig->StereoSamples[0],
    250                        pConfig->DelaySize,
    251                        pOutData,
    252                        &pConfig->DelayOffset,
    253                        (LVM_INT16)NumSamples);
    254 
    255 
    256     }
    257 
    258     return(LVCS_SUCCESS);
    259 }
    260 
    261 
    262 
    263 
    264 
    265