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 
LVCS_Process_CS(LVCS_Handle_t hInstance,const LVM_INT16 * pInData,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)70 LVCS_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 
LVCS_Process(LVCS_Handle_t hInstance,const LVM_INT16 * pInData,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)164 LVCS_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