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/*                                                                                  */
21/*  Includes                                                                        */
22/*                                                                                  */
23/************************************************************************************/
24
25#include "LVCS.h"
26#include "LVCS_Private.h"
27#include "VectorArithmetic.h"
28#include "CompLim.h"
29
30/************************************************************************************/
31/*                                                                                  */
32/* FUNCTION:                LVCS_Process_CS                                         */
33/*                                                                                  */
34/* DESCRIPTION:                                                                     */
35/*  Process function for the Concert Sound module based on the following block      */
36/*  diagram:                                                                        */
37/*            _________    ________    _____    _______     ___   ______            */
38/*           |         |  |        |  |     |  |       |   |   | |      |           */
39/*     ----->| Stereo  |->| Reverb |->| Equ |->| Alpha |-->| + |-| Gain |---->      */
40/*        |  | Enhance |  |________|  |_____|  |_______|   |___| |______|           */
41/*        |  |_________|                                     |                      */
42/*        |                                 ___________      |                      */
43/*        |                                |           |     |                      */
44/*        |------------------------------->| 1 - Alpha |-----|                      */
45/*                                         |___________|                            */
46/*                                                                                  */
47/*  The Stereo Enhancer, Reverb and Equaliser blocks are each configured to have    */
48/*  their gain to give a near peak to peak output (-0.1dBFS) with a worst case      */
49/*  input signal. The gains of these blocks are re-combined in the Alpha mixer and  */
50/*  the gain block folloing the sum.                                                */
51/*                                                                                  */
52/*  The processing uses the output buffer for data storage after each processing    */
53/*  block. When processing is inplace a copy of the input signal is made in scratch */
54/*  memory for the 1-Alpha path.                                                    */
55/*                                                                                  */
56/*                                                                                  */
57/* PARAMETERS:                                                                      */
58/*  hInstance               Instance handle                                         */
59/*  pInData                 Pointer to the input data                               */
60/*  pOutData                Pointer to the output data                              */
61/*  NumSamples              Number of samples in the input buffer                   */
62/*                                                                                  */
63/* RETURNS:                                                                         */
64/*  LVCS_Success            Succeeded                                               */
65/*                                                                                  */
66/* NOTES:                                                                           */
67/*                                                                                  */
68/************************************************************************************/
69
70LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t              hInstance,
71                                     const LVM_INT16            *pInData,
72                                     LVM_INT16                  *pOutData,
73                                     LVM_UINT16                 NumSamples)
74{
75    const LVM_INT16     *pInput;
76    LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
77    LVM_INT16           *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
78    LVCS_ReturnStatus_en err;
79
80    /*
81     * Check if the processing is inplace
82     */
83    if (pInData == pOutData)
84    {
85        /* Processing inplace */
86        pInput = pScratch + (2*NumSamples);
87        Copy_16((LVM_INT16 *)pInData,           /* Source */
88                (LVM_INT16 *)pInput,            /* Destination */
89                (LVM_INT16)(2*NumSamples));     /* Left and right */
90    }
91    else
92    {
93        /* Processing outplace */
94        pInput = pInData;
95    }
96
97    /*
98     * Call the stereo enhancer
99     */
100    err=LVCS_StereoEnhancer(hInstance,              /* Instance handle */
101                        pInData,                    /* Pointer to the input data */
102                        pOutData,                   /* Pointer to the output data */
103                        NumSamples);                /* Number of samples to process */
104
105    /*
106     * Call the reverb generator
107     */
108    err=LVCS_ReverbGenerator(hInstance,             /* Instance handle */
109                         pOutData,                  /* Pointer to the input data */
110                         pOutData,                  /* Pointer to the output data */
111                         NumSamples);               /* Number of samples to process */
112
113    /*
114     * Call the equaliser
115     */
116    err=LVCS_Equaliser(hInstance,                   /* Instance handle */
117                   pOutData,                        /* Pointer to the input data */
118                   NumSamples);                     /* Number of samples to process */
119
120    /*
121     * Call the bypass mixer
122     */
123    err=LVCS_BypassMixer(hInstance,                 /* Instance handle */
124                     pOutData,                      /* Pointer to the processed data */
125                     pInput,                        /* Pointer to the input (unprocessed) data */
126                     pOutData,                      /* Pointer to the output data */
127                     NumSamples);                   /* Number of samples to process */
128
129    if(err !=LVCS_SUCCESS)
130    {
131        return err;
132    }
133
134    return(LVCS_SUCCESS);
135}
136
137/************************************************************************************/
138/*                                                                                  */
139/* FUNCTION:                LVCS_Process                                            */
140/*                                                                                  */
141/* DESCRIPTION:                                                                     */
142/*  Process function for the Concert Sound module. The implementation supports two  */
143/*  variants of the algorithm, one for headphones and one for mobile speakers.      */
144/*                                                                                  */
145/*  Data can be processed in two formats, stereo or mono-in-stereo. Data in mono    */
146/*  format is not supported, the calling routine must convert the mono stream to    */
147/*  mono-in-stereo.                                                                 */
148/*                                                                                  */
149/*                                                                                  */
150/* PARAMETERS:                                                                      */
151/*  hInstance               Instance handle                                         */
152/*  pInData                 Pointer to the input data                               */
153/*  pOutData                Pointer to the output data                              */
154/*  NumSamples              Number of samples in the input buffer                   */
155/*                                                                                  */
156/* RETURNS:                                                                         */
157/*  LVCS_Success            Succeeded                                               */
158/*  LVCS_TooManySamples     NumSamples was larger than the maximum block size       */
159/*                                                                                  */
160/* NOTES:                                                                           */
161/*                                                                                  */
162/************************************************************************************/
163
164LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t             hInstance,
165                                  const LVM_INT16           *pInData,
166                                  LVM_INT16                 *pOutData,
167                                  LVM_UINT16                NumSamples)
168{
169
170    LVCS_Instance_t *pInstance =(LVCS_Instance_t  *)hInstance;
171    LVCS_ReturnStatus_en err;
172
173    /*
174     * Check the number of samples is not too large
175     */
176    if (NumSamples > pInstance->Capabilities.MaxBlockSize)
177    {
178        return(LVCS_TOOMANYSAMPLES);
179    }
180
181    /*
182     * Check if the algorithm is enabled
183     */
184    if (pInstance->Params.OperatingMode != LVCS_OFF)
185    {
186        /*
187         * Call CS process function
188         */
189            err=LVCS_Process_CS(hInstance,
190                            pInData,
191                            pOutData,
192                            NumSamples);
193
194        /*
195         * Compress to reduce expansion effect of Concert Sound and correct volume
196         * differences for difference settings. Not applied in test modes
197         */
198        if ((pInstance->Params.OperatingMode == LVCS_ON)&&(pInstance->Params.CompressorMode == LVM_MODE_ON))
199        {
200            LVM_INT16 Gain = pInstance->VolCorrect.CompMin;
201            LVM_INT32 Current1;
202
203            Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
204            Gain = (LVM_INT16)(  pInstance->VolCorrect.CompMin
205                               - (((LVM_INT32)pInstance->VolCorrect.CompMin  * (Current1)) >> 15)
206                               + (((LVM_INT32)pInstance->VolCorrect.CompFull * (Current1)) >> 15) );
207
208            if(NumSamples < LVCS_COMPGAINFRAME)
209            {
210                NonLinComp_D16(Gain,                    /* Compressor gain setting */
211                    pOutData,
212                    pOutData,
213                    (LVM_INT32)(2*NumSamples));
214            }
215            else
216            {
217                LVM_INT16  GainStep;
218                LVM_INT16  FinalGain;
219                LVM_INT16  SampleToProcess = NumSamples;
220                LVM_INT16  *pOutPtr;
221
222                /* Large changes in Gain can cause clicks in output
223                   Split data into small blocks and use interpolated gain values */
224
225                GainStep = (LVM_INT16)(((Gain-pInstance->CompressGain) * LVCS_COMPGAINFRAME)/NumSamples);
226
227                if((GainStep ==0)&&(pInstance->CompressGain < Gain))
228                {
229                    GainStep=1;
230                }
231                else
232                {
233                    if((GainStep ==0)&&(pInstance->CompressGain > Gain))
234                    {
235                        GainStep=-1;
236                    }
237                }
238
239                FinalGain = Gain;
240                Gain = pInstance->CompressGain;
241                pOutPtr = pOutData;
242
243                while(SampleToProcess > 0)
244                {
245                    Gain = (LVM_INT16)(Gain + GainStep);
246                    if((GainStep > 0)&& (FinalGain <= Gain))
247                    {
248                        Gain = FinalGain;
249                        GainStep =0;
250                    }
251
252                    if((GainStep < 0)&& (FinalGain > Gain))
253                    {
254                        Gain = FinalGain;
255                        GainStep =0;
256                    }
257
258                    if(SampleToProcess > LVCS_COMPGAINFRAME)
259                    {
260                        NonLinComp_D16(Gain,                    /* Compressor gain setting */
261                            pOutPtr,
262                            pOutPtr,
263                            (LVM_INT32)(2*LVCS_COMPGAINFRAME));
264                        pOutPtr +=(2*LVCS_COMPGAINFRAME);
265                        SampleToProcess = (LVM_INT16)(SampleToProcess-LVCS_COMPGAINFRAME);
266                    }
267                    else
268                    {
269                        NonLinComp_D16(Gain,                    /* Compressor gain setting */
270                            pOutPtr,
271                            pOutPtr,
272                            (LVM_INT32)(2*SampleToProcess));
273
274                        SampleToProcess = 0;
275                    }
276
277                }
278            }
279
280            /* Store gain value*/
281            pInstance->CompressGain = Gain;
282        }
283
284
285        if(pInstance->bInOperatingModeTransition == LVM_TRUE){
286
287            /*
288             * Re-init bypass mix when timer has completed
289             */
290            if ((pInstance->bTimerDone == LVM_TRUE) &&
291                (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
292            {
293                err=LVCS_BypassMixInit(hInstance,
294                                   &pInstance->Params);
295
296                if(err != LVCS_SUCCESS)
297                {
298                    return err;
299                }
300
301            }
302            else{
303                LVM_Timer ( &pInstance->TimerInstance,
304                            (LVM_INT16)NumSamples);
305            }
306        }
307    }
308    else
309    {
310        if (pInData != pOutData)
311        {
312            /*
313             * The algorithm is disabled so just copy the data
314             */
315            Copy_16((LVM_INT16 *)pInData,               /* Source */
316                (LVM_INT16 *)pOutData,                  /* Destination */
317                (LVM_INT16)(2*NumSamples));             /* Left and right */
318        }
319    }
320
321
322    return(LVCS_SUCCESS);
323}
324
325
326
327
328
329
330
331
332
333
334