LVCS_StereoEnhancer.c revision 09d5ca3766d4bab91cdaad7206716a5747ebad77
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     $Author: nxp007753 $
21     $Revision: 1315 $
22     $Date: 2010-07-23 11:52:08 +0200 (Fri, 23 Jul 2010) $
23
24*************************************************************************************/
25
26/************************************************************************************/
27/*                                                                                  */
28/*  Includes                                                                        */
29/*                                                                                  */
30/************************************************************************************/
31
32#include "LVCS.h"
33#include "LVCS_Private.h"
34#include "LVCS_StereoEnhancer.h"
35#include "VectorArithmetic.h"
36#include "LVCS_Tables.h"
37
38/************************************************************************************/
39/*                                                                                  */
40/* FUNCTION:                LVCS_StereoEnhanceInit                                  */
41/*                                                                                  */
42/* DESCRIPTION:                                                                     */
43/*  Initialises the stereo enhancement module based on the sample rate.             */
44/*                                                                                  */
45/*  The function selects the coefficients for the filters and clears the data       */
46/*  history. It is also used for re-initialisation when one of the system control   */
47/*  parameters changes but will only change the coefficients and clear the history  */
48/*  if the sample rate or speaker type has changed.                                 */
49/*                                                                                  */
50/* PARAMETERS:                                                                      */
51/*  hInstance               Instance Handle                                         */
52/*  pParams                 Initialisation parameters                               */
53/*                                                                                  */
54/* RETURNS:                                                                         */
55/*  LVCS_Success            Always succeeds                                         */
56/*                                                                                  */
57/* NOTES:                                                                           */
58/*                                                                                  */
59/************************************************************************************/
60
61LVCS_ReturnStatus_en LVCS_SEnhancerInit(LVCS_Handle_t       hInstance,
62                                        LVCS_Params_t       *pParams)
63{
64
65    LVM_UINT16              Offset;
66    LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
67    LVCS_StereoEnhancer_t   *pConfig   = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
68    LVCS_Data_t             *pData     = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
69    LVCS_Coefficient_t      *pCoefficient = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
70    FO_C16_Coefs_t          CoeffsMid;
71    BQ_C16_Coefs_t          CoeffsSide;
72    const BiquadA012B12CoefsSP_t *pSESideCoefs;
73
74    /*
75     * If the sample rate or speaker type has changed update the filters
76     */
77    if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
78        (pInstance->Params.SpeakerType != pParams->SpeakerType))
79    {
80        /*
81         * Set the filter coefficients based on the sample rate
82         */
83        /* Mid filter */
84        Offset = (LVM_UINT16)pParams->SampleRate;
85
86        /* Convert incoming coefficients to the required format/ordering */
87        CoeffsMid.A0 = (LVM_INT16) LVCS_SEMidCoefTable[Offset].A0;
88        CoeffsMid.A1 = (LVM_INT16) LVCS_SEMidCoefTable[Offset].A1;
89        CoeffsMid.B1 = (LVM_INT16)-LVCS_SEMidCoefTable[Offset].B1;
90
91        /* Clear the taps */
92        LoadConst_16(0,                                                                 /* Value */
93                     (void *)&pData->SEBiquadTapsMid,              /* Destination Cast to void:\
94                                                                      no dereferencing in function*/
95                     (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid)/sizeof(LVM_UINT16)));  /* Number of words */
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_INT16) pSESideCoefs[Offset].A0;
113        CoeffsSide.A1 = (LVM_INT16) pSESideCoefs[Offset].A1;
114        CoeffsSide.A2 = (LVM_INT16) pSESideCoefs[Offset].A2;
115        CoeffsSide.B1 = (LVM_INT16)-pSESideCoefs[Offset].B1;
116        CoeffsSide.B2 = (LVM_INT16)-pSESideCoefs[Offset].B2;
117
118        /* Clear the taps */
119        LoadConst_16(0,                                                                 /* Value */
120                     (void *)&pData->SEBiquadTapsSide,             /* Destination Cast to void:\
121                                                                      no dereferencing in function*/
122                     (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide)/sizeof(LVM_UINT16))); /* Number of words */
123
124
125        /* Callbacks */
126        switch(pSESideCoefs[Offset].Scale)
127        {
128            case 14:
129                BQ_1I_D16F32Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
130                                                &pData->SEBiquadTapsSide,
131                                                &CoeffsSide);
132
133                pConfig->pBiquadCallBack_Side  = BQ_1I_D16F32C14_TRC_WRA_01;
134                break;
135            case 15:
136                BQ_1I_D16F16Css_TRC_WRA_01_Init(&pCoefficient->SEBiquadInstanceSide,
137                                                &pData->SEBiquadTapsSide,
138                                                &CoeffsSide);
139
140                pConfig->pBiquadCallBack_Side  = BQ_1I_D16F16C15_TRC_WRA_01;
141                break;
142        }
143
144    }
145
146
147    return(LVCS_SUCCESS);
148}
149
150/************************************************************************************/
151/*                                                                                  */
152/* FUNCTION:                LVCS_StereoEnhance                                      */
153/*                                                                                  */
154/* DESCRIPTION:                                                                     */
155/*  Enhance the stereo image in the input samples based on the following block      */
156/*  diagram:                                                                        */
157/*                                                                                  */
158/*                               ________                                           */
159/*          ________            |        |          ________                        */
160/*         |        |  Middle   | Treble |         |        |                       */
161/*         |        |---------->| Boost  |-------->|        |                       */
162/*         | Stereo |           |________|         | M & S  |                       */
163/*      -->|   to   |            ________          |   to   |-->                    */
164/*         | M & S  |  Side     |        |         | Stereo |                       */
165/*         |        |---------->| Side   |-------->|        |                       */
166/*         |________|           | Boost  |         |________|                       */
167/*                              |________|                                          */
168/*                                                                                  */
169/*                                                                                  */
170/*  If the input signal is a mono signal there will be no side signal and hence     */
171/*  the side filter will not be run. In mobile speaker mode the middle filter is    */
172/*  not required and the Trebble boost filter is replaced by a simple gain block.   */
173/*                                                                                  */
174/*                                                                                  */
175/* PARAMETERS:                                                                      */
176/*  hInstance               Instance Handle                                         */
177/*  pInData                 Pointer to the input data                               */
178/*  pOutData                Pointer to the output data                              */
179/*  NumSamples              Number of samples to process                            */
180/*                                                                                  */
181/* RETURNS:                                                                         */
182/*  LVCS_Success            Always succeeds                                         */
183/*                                                                                  */
184/* NOTES:                                                                           */
185/*  1.  The side filter is not used in Mobile Speaker mode                          */
186/*                                                                                  */
187/************************************************************************************/
188
189LVCS_ReturnStatus_en LVCS_StereoEnhancer(LVCS_Handle_t          hInstance,
190                                         const LVM_INT16        *pInData,
191                                         LVM_INT16              *pOutData,
192                                         LVM_UINT16             NumSamples)
193{
194
195    LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
196    LVCS_StereoEnhancer_t   *pConfig   = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
197    LVCS_Coefficient_t      *pCoefficient = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
198    LVM_INT16               *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
199
200    /*
201     * Check if the Stereo Enhancer is enabled
202     */
203    if ((pInstance->Params.OperatingMode & LVCS_STEREOENHANCESWITCH) != 0)
204        {
205        /*
206         * Convert from stereo to middle and side
207         */
208        From2iToMS_16x16(pInData,
209                         pScratch,
210                         pScratch+NumSamples,
211                         (LVM_INT16)NumSamples);
212
213        /*
214         * Apply filter to the middle signal
215         */
216        if (pInstance->OutputDevice == LVCS_HEADPHONE)
217        {
218            (pConfig->pBiquadCallBack_Mid)((Biquad_Instance_t*)&pCoefficient->SEBiquadInstanceMid,
219                                           (LVM_INT16 *)pScratch,
220                                           (LVM_INT16 *)pScratch,
221                                           (LVM_INT16)NumSamples);
222        }
223        else
224        {
225            Mult3s_16x16(pScratch,              /* Source */
226                         (LVM_INT16)pConfig->MidGain,      /* Gain */
227                         pScratch,              /* Destination */
228                         (LVM_INT16)NumSamples);           /* Number of samples */
229        }
230
231        /*
232         * Apply the filter the side signal only in stereo mode for headphones
233         * and in all modes for mobile speakers
234         */
235        if (pInstance->Params.SourceFormat == LVCS_STEREO)
236        {
237            (pConfig->pBiquadCallBack_Side)((Biquad_Instance_t*)&pCoefficient->SEBiquadInstanceSide,
238                                            (LVM_INT16 *)(pScratch + NumSamples),
239                                            (LVM_INT16 *)(pScratch + NumSamples),
240                                            (LVM_INT16)NumSamples);
241        }
242
243        /*
244         * Convert from middle and side to stereo
245         */
246        MSTo2i_Sat_16x16(pScratch,
247                         pScratch+NumSamples,
248                         pOutData,
249                         (LVM_INT16)NumSamples);
250
251    }
252    else
253    {
254        /*
255         * The stereo enhancer is disabled so just copy the data
256         */
257        Copy_16((LVM_INT16 *)pInData,           /* Source */
258                (LVM_INT16 *)pOutData,          /* Destination */
259                (LVM_INT16)(2*NumSamples));     /* Left and right */
260
261    }
262
263    return(LVCS_SUCCESS);
264}
265
266
267
268
269