LVCS_BypassMix.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: beq06068 $
21     $Revision: 1307 $
22     $Date: 2010-07-22 17:41:25 +0200 (Thu, 22 Jul 2010) $
23
24*************************************************************************************/
25
26/************************************************************************************/
27/*                                                                                  */
28/*  Includes                                                                        */
29/*                                                                                  */
30/************************************************************************************/
31
32#include "LVCS.h"
33#include "LVCS_Private.h"
34#include "LVCS_BypassMix.h"
35#include "VectorArithmetic.h"
36#include "LVCS_Tables.h"
37
38/****************************************************************************************/
39/*                                                                                      */
40/*  Function Prototypes                                                                 */
41/*                                                                                      */
42/****************************************************************************************/
43LVM_INT32 LVCS_MixerCallback(   LVCS_Handle_t   hInstance,
44                                void            *pGeneralPurpose,
45                                LVM_INT16       CallbackParam);
46
47/************************************************************************************/
48/*                                                                                  */
49/* FUNCTION:                LVCS_BypassMixInit                                      */
50/*                                                                                  */
51/* DESCRIPTION:                                                                     */
52/*  Initialises the bypass mixer module                                             */
53/*                                                                                  */
54/*  The overall gain of the processed path is set by the gains in the individual    */
55/*  processing blocks and by the effect level gain.                                 */
56/*                                                                                  */
57/*  The unprocessed path must have matching gain for the processed path to ensure   */
58/*  as they are mixed together the correct effect is achieved, this is the value    */
59/*  UnprocLoss.                                                                     */
60/*                                                                                  */
61/*  The overall gain is corrected by a combination of a shift with saturation and a */
62/*  linear scaler, loss. The loss ensures the sum in the mixer does not saturate    */
63/*  and also corrects for any excess gain in the shift.                             */
64/*                                                                                  */
65/* PARAMETERS:                                                                      */
66/*  hInstance               Instance Handle                                         */
67/*  pParams                 Initialisation parameters                               */
68/*                                                                                  */
69/* RETURNS:                                                                         */
70/*  LVCS_Success            Always succeeds                                         */
71/*                                                                                  */
72/* NOTES:                                                                           */
73/*                                                                                  */
74/************************************************************************************/
75
76LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t       hInstance,
77                                        LVCS_Params_t       *pParams)
78{
79
80    LVM_UINT16          Offset;
81    LVM_UINT32          Gain;
82    LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
83    LVCS_BypassMix_t    *pConfig   = (LVCS_BypassMix_t *)&pInstance->BypassMix;
84    const Gain_t        *pOutputGainTable;
85    LVM_INT32           Current;
86
87
88    /*
89     * Set the transition gain
90     */
91    if ((pParams->OperatingMode == LVCS_ON) &&
92        (pInstance->bTimerDone == LVM_TRUE)
93        && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
94        )
95    {
96        pInstance->TransitionGain = pParams->EffectLevel;
97    }
98    else
99    {
100        /* Select no effect level */
101        pInstance->TransitionGain = 0;
102    }
103
104    /*
105     * Calculate the output gain table offset
106     */
107    Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
108    pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
109
110    /*
111     * Setup the mixer gain for the processed path
112     */
113    Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
114
115    pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
116    pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
117    pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
118    pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
119    Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
120    LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current);
121    LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
122    /*
123     * Setup the mixer gain for the unprocessed path
124     */
125    Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain));
126    Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
127    Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
128    LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current);
129    LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
130    pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
131    pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
132    pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
133    pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
134
135    /*
136     * Setup the output gain shift
137     */
138    pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
139
140
141    /*
142     * Correct gain for the effect level
143     */
144    {
145
146        LVM_INT16           GainCorrect;
147        LVM_INT32           Gain1;
148        LVM_INT32           Gain2;
149
150        Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
151        Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
152        /*
153         * Calculate the gain correction
154         */
155        if (pInstance->Params.CompressorMode == LVM_MODE_ON)
156        {
157        GainCorrect = (LVM_INT16)(  pInstance->VolCorrect.GainMin
158                                    - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15)
159                                    + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) );
160
161        /*
162         * Apply the gain correction and shift, note the result is in Q3.13 format
163         */
164        Gain1 = (Gain1 * GainCorrect) << 4;
165        Gain2 = (Gain2 * GainCorrect) << 4;
166        }
167        else
168        {
169            Gain1 = Gain1 << 16;
170            Gain2 = Gain2 << 16;
171        }
172
173
174
175        /*
176         * Set the gain values
177         */
178        pConfig->Output_Shift = pConfig->Output_Shift;
179        LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16);
180        LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
181        LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16);
182        LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
183    }
184
185    return(LVCS_SUCCESS);
186
187}
188
189/************************************************************************************/
190/*                                                                                  */
191/* FUNCTION:                LVCS_BypassMixer                                        */
192/*                                                                                  */
193/* DESCRIPTION:                                                                     */
194/*  Apply Bypass Mix.                                                               */
195/*                                                                                  */
196/*  This mixes the processed and unprocessed data streams together to correct the   */
197/*  overall system gain and allow progressive control of the Concert Sound effect.  */
198/*                                                                                  */
199/*  When the bypass mixer is enabled the output is the processed signal only and    */
200/*  without gain correction.                                                        */
201/*                                                                                  */
202/* PARAMETERS:                                                                      */
203/*  hInstance               Instance Handle                                         */
204/*  pProcessed              Pointer to the processed data                           */
205/*  pUnprocessed            Pointer to the unprocessed data                         */
206/*  pOutData                Pointer to the output data                              */
207/*  NumSamples              Number of samples to process                            */
208/*                                                                                  */
209/* RETURNS:                                                                         */
210/*  LVCS_Success            Always succeeds                                         */
211/*                                                                                  */
212/* NOTES:                                                                           */
213/*                                                                                  */
214/************************************************************************************/
215
216LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t         hInstance,
217                                      const LVM_INT16       *pProcessed,
218                                      const LVM_INT16       *pUnprocessed,
219                                      LVM_INT16             *pOutData,
220                                      LVM_UINT16            NumSamples)
221{
222
223    LVCS_Instance_t     *pInstance      = (LVCS_Instance_t  *)hInstance;
224    LVCS_BypassMix_t    *pConfig        = (LVCS_BypassMix_t *)&pInstance->BypassMix;
225
226    /*
227     * Check if the bypass mixer is enabled
228     */
229    if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0)
230    {
231        /*
232         * Apply the bypass mix
233         */
234        LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
235                                        pProcessed,
236                                        (LVM_INT16 *) pUnprocessed,
237                                        pOutData,
238                                        (LVM_INT16)(2*NumSamples));
239
240        /*
241         * Apply output gain correction shift
242         */
243        Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift,
244                          (LVM_INT16*)pOutData,
245                          (LVM_INT16*)pOutData,
246                          (LVM_INT16)(2*NumSamples));          /* Left and right*/
247    }
248
249    return(LVCS_SUCCESS);
250}
251
252
253/************************************************************************************/
254/*                                                                                  */
255/* FUNCTION:                LVCS_MixerCallback                                      */
256/*                                                                                  */
257/************************************************************************************/
258LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t      hInstance,
259                            void                *pGeneralPurpose,
260                            LVM_INT16           CallbackParam)
261{
262    LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
263
264   (void)pGeneralPurpose;
265
266    /*
267     * Off transition has completed in Headphone mode
268     */
269    if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
270        (pInstance->bInOperatingModeTransition)     &&
271        (pInstance->MSTarget0 == 0x0000)&&  /* this indicates an on->off transition */
272        (CallbackParam == 0))
273    {
274        /* Set operating mode to OFF */
275        pInstance->Params.OperatingMode = LVCS_OFF;
276
277        /* Exit transition state */
278        pInstance->bInOperatingModeTransition = LVM_FALSE;
279
280        /* Signal to the bundle */
281        if((*pInstance->Capabilities.CallBack) != LVM_NULL){
282            (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
283                                                LVM_NULL,
284                                                (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
285        }
286    }
287
288
289    if ((pInstance->OutputDevice == LVCS_HEADPHONE)  &&
290        (pInstance->MSTarget0 == 1) &&
291        (pInstance->bTimerDone == LVM_TRUE)){
292
293        /* Exit transition state */
294        pInstance->bInOperatingModeTransition = LVM_FALSE;
295    }
296
297    return 1;
298}
299
300
301
302