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_StereoEnhancer.h"
     27 #include "VectorArithmetic.h"
     28 #include "LVCS_Tables.h"
     29 
     30 /************************************************************************************/
     31 /*                                                                                  */
     32 /* FUNCTION:                LVCS_StereoEnhanceInit                                  */
     33 /*                                                                                  */
     34 /* DESCRIPTION:                                                                     */
     35 /*  Initialises the stereo enhancement module based on the sample rate.             */
     36 /*                                                                                  */
     37 /*  The function selects the coefficients for the filters and clears the data       */
     38 /*  history. It is also used for re-initialisation when one of the system control   */
     39 /*  parameters changes but will only change the coefficients and clear the history  */
     40 /*  if the sample rate or speaker type has changed.                                 */
     41 /*                                                                                  */
     42 /* PARAMETERS:                                                                      */
     43 /*  hInstance               Instance Handle                                         */
     44 /*  pParams                 Initialisation parameters                               */
     45 /*                                                                                  */
     46 /* RETURNS:                                                                         */
     47 /*  LVCS_Success            Always succeeds                                         */
     48 /*                                                                                  */
     49 /* NOTES:                                                                           */
     50 /*                                                                                  */
     51 /************************************************************************************/
     52 #ifdef BUILD_FLOAT
     53 LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t       hInstance,
     54                                         LVCS_Params_t       *pParams)
     55 {
     56 
     57     LVM_UINT16              Offset;
     58     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
     59     LVCS_StereoEnhancer_t   *pConfig   = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
     60     LVCS_Data_t             *pData;
     61     LVCS_Coefficient_t      *pCoefficient;
     62     FO_FLOAT_Coefs_t          CoeffsMid;
     63     BQ_FLOAT_Coefs_t          CoeffsSide;
     64     const BiquadA012B12CoefsSP_t *pSESideCoefs;
     65 
     66 
     67     pData     = (LVCS_Data_t *) \
     68                   pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
     69 
     70     pCoefficient = (LVCS_Coefficient_t *) \
     71                   pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
     72 
     73     /*
     74      * If the sample rate or speaker type has changed update the filters
     75      */
     76     if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
     77         (pInstance->Params.SpeakerType != pParams->SpeakerType))
     78     {
     79         /*
     80          * Set the filter coefficients based on the sample rate
     81          */
     82         /* Mid filter */
     83         Offset = (LVM_UINT16)pParams->SampleRate;
     84 
     85         /* Convert incoming coefficients to the required format/ordering */
     86         CoeffsMid.A0 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A0;
     87         CoeffsMid.A1 = (LVM_FLOAT) LVCS_SEMidCoefTable[Offset].A1;
     88         CoeffsMid.B1 = (LVM_FLOAT)-LVCS_SEMidCoefTable[Offset].B1;
     89 
     90         /* Clear the taps */
     91         LoadConst_Float(0,                                  /* Value */
     92                         (void *)&pData->SEBiquadTapsMid,    /* Destination Cast to void:\
     93                                                               no dereferencing in function*/
     94                         /* Number of words */
     95                         (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid) / sizeof(LVM_FLOAT)));
     96 
     97         FO_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceMid,
     98                                         &pData->SEBiquadTapsMid,
     99                                         &CoeffsMid);
    100 
    101         /* Callbacks */
    102         if(LVCS_SEMidCoefTable[Offset].Scale == 15)
    103         {
    104             pConfig->pBiquadCallBack_Mid  = FO_1I_D16F16C15_TRC_WRA_01;
    105         }
    106 
    107         Offset = (LVM_UINT16)(pParams->SampleRate);
    108         pSESideCoefs = (BiquadA012B12CoefsSP_t*)&LVCS_SESideCoefTable[0];
    109 
    110         /* Side filter */
    111         /* Convert incoming coefficients to the required format/ordering */
    112         CoeffsSide.A0 = (LVM_FLOAT) pSESideCoefs[Offset].A0;
    113         CoeffsSide.A1 = (LVM_FLOAT) pSESideCoefs[Offset].A1;
    114         CoeffsSide.A2 = (LVM_FLOAT) pSESideCoefs[Offset].A2;
    115         CoeffsSide.B1 = (LVM_FLOAT)-pSESideCoefs[Offset].B1;
    116         CoeffsSide.B2 = (LVM_FLOAT)-pSESideCoefs[Offset].B2;
    117 
    118         /* Clear the taps */
    119         LoadConst_Float(0,                                /* Value */
    120                         (void *)&pData->SEBiquadTapsSide, /* Destination Cast to void:\
    121                                                              no dereferencing in function*/
    122                         /* Number of words */
    123                         (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide) / sizeof(LVM_FLOAT)));
    124         /* Callbacks */
    125         switch(pSESideCoefs[Offset].Scale)
    126         {
    127             case 14:
    128                 BQ_1I_D16F32Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
    129                                                 &pData->SEBiquadTapsSide,
    130                                                 &CoeffsSide);
    131 
    132                 pConfig->pBiquadCallBack_Side  = BQ_1I_D16F32C14_TRC_WRA_01;
    133                 break;
    134             case 15:
    135                 BQ_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
    136                                                 &pData->SEBiquadTapsSide,
    137                                                 &CoeffsSide);
    138 
    139                 pConfig->pBiquadCallBack_Side  = BQ_1I_D16F16C15_TRC_WRA_01;
    140                 break;
    141         }
    142 
    143     }
    144 
    145 
    146     return(LVCS_SUCCESS);
    147 }
    148 #else
    149 LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t       hInstance,
    150                                         LVCS_Params_t       *pParams)
    151 {
    152 
    153     LVM_UINT16              Offset;
    154     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
    155     LVCS_StereoEnhancer_t   *pConfig   = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
    156     LVCS_Data_t             *pData     = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
    157     LVCS_Coefficient_t      *pCoefficient = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
    158     FO_C16_Coefs_t          CoeffsMid;
    159     BQ_C16_Coefs_t          CoeffsSide;
    160     const BiquadA012B12CoefsSP_t *pSESideCoefs;
    161 
    162     /*
    163      * If the sample rate or speaker type has changed update the filters
    164      */
    165     if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
    166         (pInstance->Params.SpeakerType != pParams->SpeakerType))
    167     {
    168         /*
    169          * Set the filter coefficients based on the sample rate
    170          */
    171         /* Mid filter */
    172         Offset = (LVM_UINT16)pParams->SampleRate;
    173 
    174         /* Convert incoming coefficients to the required format/ordering */
    175         CoeffsMid.A0 = (LVM_INT16) LVCS_SEMidCoefTable[Offset].A0;
    176         CoeffsMid.A1 = (LVM_INT16) LVCS_SEMidCoefTable[Offset].A1;
    177         CoeffsMid.B1 = (LVM_INT16)-LVCS_SEMidCoefTable[Offset].B1;
    178 
    179         /* Clear the taps */
    180         LoadConst_16(0,                                                                 /* Value */
    181                      (void *)&pData->SEBiquadTapsMid,              /* Destination Cast to void:\
    182                                                                       no dereferencing in function*/
    183                      (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid)/sizeof(LVM_UINT16)));  /* Number of words */
    184 
    185         FO_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceMid,
    186                                         &pData->SEBiquadTapsMid,
    187                                         &CoeffsMid);
    188 
    189         /* Callbacks */
    190         if(LVCS_SEMidCoefTable[Offset].Scale==15)
    191         {
    192             pConfig->pBiquadCallBack_Mid  = FO_1I_D16F16C15_TRC_WRA_01;
    193         }
    194 
    195         Offset = (LVM_UINT16)(pParams->SampleRate);
    196         pSESideCoefs = (BiquadA012B12CoefsSP_t*)&LVCS_SESideCoefTable[0];
    197 
    198         /* Side filter */
    199         /* Convert incoming coefficients to the required format/ordering */
    200         CoeffsSide.A0 = (LVM_INT16) pSESideCoefs[Offset].A0;
    201         CoeffsSide.A1 = (LVM_INT16) pSESideCoefs[Offset].A1;
    202         CoeffsSide.A2 = (LVM_INT16) pSESideCoefs[Offset].A2;
    203         CoeffsSide.B1 = (LVM_INT16)-pSESideCoefs[Offset].B1;
    204         CoeffsSide.B2 = (LVM_INT16)-pSESideCoefs[Offset].B2;
    205 
    206         /* Clear the taps */
    207         LoadConst_16(0,                                                                 /* Value */
    208                      (void *)&pData->SEBiquadTapsSide,             /* Destination Cast to void:\
    209                                                                       no dereferencing in function*/
    210                      (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide)/sizeof(LVM_UINT16))); /* Number of words */
    211 
    212 
    213         /* Callbacks */
    214         switch(pSESideCoefs[Offset].Scale)
    215         {
    216             case 14:
    217                 BQ_1I_D16F32Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
    218                                                 &pData->SEBiquadTapsSide,
    219                                                 &CoeffsSide);
    220 
    221                 pConfig->pBiquadCallBack_Side  = BQ_1I_D16F32C14_TRC_WRA_01;
    222                 break;
    223             case 15:
    224                 BQ_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
    225                                                 &pData->SEBiquadTapsSide,
    226                                                 &CoeffsSide);
    227 
    228                 pConfig->pBiquadCallBack_Side  = BQ_1I_D16F16C15_TRC_WRA_01;
    229                 break;
    230         }
    231 
    232     }
    233 
    234 
    235     return(LVCS_SUCCESS);
    236 }
    237 #endif
    238 /************************************************************************************/
    239 /*                                                                                  */
    240 /* FUNCTION:                LVCS_StereoEnhance                                      */
    241 /*                                                                                  */
    242 /* DESCRIPTION:                                                                     */
    243 /*  Enhance the stereo image in the input samples based on the following block      */
    244 /*  diagram:                                                                        */
    245 /*                                                                                  */
    246 /*                               ________                                           */
    247 /*          ________            |        |          ________                        */
    248 /*         |        |  Middle   | Treble |         |        |                       */
    249 /*         |        |---------->| Boost  |-------->|        |                       */
    250 /*         | Stereo |           |________|         | M & S  |                       */
    251 /*      -->|   to   |            ________          |   to   |-->                    */
    252 /*         | M & S  |  Side     |        |         | Stereo |                       */
    253 /*         |        |---------->| Side   |-------->|        |                       */
    254 /*         |________|           | Boost  |         |________|                       */
    255 /*                              |________|                                          */
    256 /*                                                                                  */
    257 /*                                                                                  */
    258 /*  If the input signal is a mono signal there will be no side signal and hence     */
    259 /*  the side filter will not be run. In mobile speaker mode the middle filter is    */
    260 /*  not required and the Trebble boost filter is replaced by a simple gain block.   */
    261 /*                                                                                  */
    262 /*                                                                                  */
    263 /* PARAMETERS:                                                                      */
    264 /*  hInstance               Instance Handle                                         */
    265 /*  pInData                 Pointer to the input data                               */
    266 /*  pOutData                Pointer to the output data                              */
    267 /*  NumSamples              Number of samples to process                            */
    268 /*                                                                                  */
    269 /* RETURNS:                                                                         */
    270 /*  LVCS_Success            Always succeeds                                         */
    271 /*                                                                                  */
    272 /* NOTES:                                                                           */
    273 /*  1.  The side filter is not used in Mobile Speaker mode                          */
    274 /*                                                                                  */
    275 /************************************************************************************/
    276 #ifdef BUILD_FLOAT
    277 LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t          hInstance,
    278                                          const LVM_FLOAT        *pInData,
    279                                          LVM_FLOAT              *pOutData,
    280                                          LVM_UINT16             NumSamples)
    281 {
    282 
    283     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
    284     LVCS_StereoEnhancer_t   *pConfig   = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
    285     LVCS_Coefficient_t      *pCoefficient;
    286     LVM_FLOAT               *pScratch;
    287 
    288     pCoefficient = (LVCS_Coefficient_t *) \
    289                    pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
    290 
    291     pScratch  = (LVM_FLOAT *) \
    292                     pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
    293     /*
    294      * Check if the Stereo Enhancer is enabled
    295      */
    296     if ((pInstance->Params.OperatingMode & LVCS_STEREOENHANCESWITCH) != 0)
    297         {
    298         /*
    299          * Convert from stereo to middle and side
    300          */
    301         From2iToMS_Float(pInData,
    302                          pScratch,
    303                          pScratch + NumSamples,
    304                          (LVM_INT16)NumSamples);
    305 
    306         /*
    307          * Apply filter to the middle signal
    308          */
    309         if (pInstance->OutputDevice == LVCS_HEADPHONE)
    310         {
    311             (pConfig->pBiquadCallBack_Mid)((Biquad_FLOAT_Instance_t*)\
    312                                             &pCoefficient->SEBiquadInstanceMid,
    313                                             (LVM_FLOAT *)pScratch,
    314                                             (LVM_FLOAT *)pScratch,
    315                                             (LVM_INT16)NumSamples);
    316         }
    317         else
    318         {
    319             Mult3s_Float(pScratch,              /* Source */
    320                          (LVM_FLOAT)pConfig->MidGain,      /* Gain */
    321                          pScratch,              /* Destination */
    322                          (LVM_INT16)NumSamples);           /* Number of samples */
    323         }
    324 
    325         /*
    326          * Apply the filter the side signal only in stereo mode for headphones
    327          * and in all modes for mobile speakers
    328          */
    329         if (pInstance->Params.SourceFormat == LVCS_STEREO)
    330         {
    331             (pConfig->pBiquadCallBack_Side)((Biquad_FLOAT_Instance_t*) \
    332                                             &pCoefficient->SEBiquadInstanceSide,
    333                                             (LVM_FLOAT *)(pScratch + NumSamples),
    334                                             (LVM_FLOAT *)(pScratch + NumSamples),
    335                                             (LVM_INT16)NumSamples);
    336         }
    337 
    338         /*
    339          * Convert from middle and side to stereo
    340          */
    341         MSTo2i_Sat_Float(pScratch,
    342                          pScratch + NumSamples,
    343                          pOutData,
    344                          (LVM_INT16)NumSamples);
    345 
    346     }
    347     else
    348     {
    349         /*
    350          * The stereo enhancer is disabled so just copy the data
    351          */
    352         Copy_Float((LVM_FLOAT *)pInData,           /* Source */
    353                    (LVM_FLOAT *)pOutData,          /* Destination */
    354                    (LVM_INT16)(2 * NumSamples));     /* Left and right */
    355     }
    356 
    357     return(LVCS_SUCCESS);
    358 }
    359 #else
    360 LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t          hInstance,
    361                                          const LVM_INT16        *pInData,
    362                                          LVM_INT16              *pOutData,
    363                                          LVM_UINT16             NumSamples)
    364 {
    365 
    366     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
    367     LVCS_StereoEnhancer_t   *pConfig   = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
    368     LVCS_Coefficient_t      *pCoefficient = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
    369     LVM_INT16               *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
    370 
    371     /*
    372      * Check if the Stereo Enhancer is enabled
    373      */
    374     if ((pInstance->Params.OperatingMode & LVCS_STEREOENHANCESWITCH) != 0)
    375         {
    376         /*
    377          * Convert from stereo to middle and side
    378          */
    379         From2iToMS_16x16(pInData,
    380                          pScratch,
    381                          pScratch+NumSamples,
    382                          (LVM_INT16)NumSamples);
    383 
    384         /*
    385          * Apply filter to the middle signal
    386          */
    387         if (pInstance->OutputDevice == LVCS_HEADPHONE)
    388         {
    389             (pConfig->pBiquadCallBack_Mid)((Biquad_Instance_t*)&pCoefficient->SEBiquadInstanceMid,
    390                                            (LVM_INT16 *)pScratch,
    391                                            (LVM_INT16 *)pScratch,
    392                                            (LVM_INT16)NumSamples);
    393         }
    394         else
    395         {
    396             Mult3s_16x16(pScratch,              /* Source */
    397                          (LVM_INT16)pConfig->MidGain,      /* Gain */
    398                          pScratch,              /* Destination */
    399                          (LVM_INT16)NumSamples);           /* Number of samples */
    400         }
    401 
    402         /*
    403          * Apply the filter the side signal only in stereo mode for headphones
    404          * and in all modes for mobile speakers
    405          */
    406         if (pInstance->Params.SourceFormat == LVCS_STEREO)
    407         {
    408             (pConfig->pBiquadCallBack_Side)((Biquad_Instance_t*)&pCoefficient->SEBiquadInstanceSide,
    409                                             (LVM_INT16 *)(pScratch + NumSamples),
    410                                             (LVM_INT16 *)(pScratch + NumSamples),
    411                                             (LVM_INT16)NumSamples);
    412         }
    413 
    414         /*
    415          * Convert from middle and side to stereo
    416          */
    417         MSTo2i_Sat_16x16(pScratch,
    418                          pScratch+NumSamples,
    419                          pOutData,
    420                          (LVM_INT16)NumSamples);
    421 
    422     }
    423     else
    424     {
    425         /*
    426          * The stereo enhancer is disabled so just copy the data
    427          */
    428         Copy_16((LVM_INT16 *)pInData,           /* Source */
    429                 (LVM_INT16 *)pOutData,          /* Destination */
    430                 (LVM_INT16)(2*NumSamples));     /* Left and right */
    431 
    432     }
    433 
    434     return(LVCS_SUCCESS);
    435 }
    436 #endif
    437