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 "VectorArithmetic.h"
27 #include "CompLim.h"
28 
29 /************************************************************************************/
30 /*                                                                                  */
31 /* FUNCTION:                LVCS_Process_CS                                         */
32 /*                                                                                  */
33 /* DESCRIPTION:                                                                     */
34 /*  Process function for the Concert Sound module based on the following block      */
35 /*  diagram:                                                                        */
36 /*            _________    ________    _____    _______     ___   ______            */
37 /*           |         |  |        |  |     |  |       |   |   | |      |           */
38 /*     ----->| Stereo  |->| Reverb |->| Equ |->| Alpha |-->| + |-| Gain |---->      */
39 /*        |  | Enhance |  |________|  |_____|  |_______|   |___| |______|           */
40 /*        |  |_________|                                     |                      */
41 /*        |                                 ___________      |                      */
42 /*        |                                |           |     |                      */
43 /*        |------------------------------->| 1 - Alpha |-----|                      */
44 /*                                         |___________|                            */
45 /*                                                                                  */
46 /*  The Stereo Enhancer, Reverb and Equaliser blocks are each configured to have    */
47 /*  their gain to give a near peak to peak output (-0.1dBFS) with a worst case      */
48 /*  input signal. The gains of these blocks are re-combined in the Alpha mixer and  */
49 /*  the gain block folloing the sum.                                                */
50 /*                                                                                  */
51 /*  The processing uses the output buffer for data storage after each processing    */
52 /*  block. When processing is inplace a copy of the input signal is made in scratch */
53 /*  memory for the 1-Alpha path.                                                    */
54 /*                                                                                  */
55 /*                                                                                  */
56 /* PARAMETERS:                                                                      */
57 /*  hInstance               Instance handle                                         */
58 /*  pInData                 Pointer to the input data                               */
59 /*  pOutData                Pointer to the output data                              */
60 /*  NumSamples              Number of samples in the input buffer                   */
61 /*                                                                                  */
62 /* RETURNS:                                                                         */
63 /*  LVCS_Success            Succeeded                                               */
64 /*                                                                                  */
65 /* NOTES:                                                                           */
66 /*                                                                                  */
67 /************************************************************************************/
LVCS_Process_CS(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)68 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t              hInstance,
69                                      const LVM_FLOAT            *pInData,
70                                      LVM_FLOAT                  *pOutData,
71                                      LVM_UINT16                 NumSamples)
72 {
73     const LVM_FLOAT     *pInput;
74     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
75     LVM_FLOAT           *pScratch;
76     LVCS_ReturnStatus_en err;
77 #ifdef SUPPORT_MC
78     LVM_FLOAT           *pStIn;
79     LVM_INT32           channels = pInstance->Params.NrChannels;
80 #define NrFrames NumSamples  // alias for clarity
81 
82     /*In case of mono processing, stereo input is created from mono
83      *and stored in pInData before applying any of the effects.
84      *However we do not update the value pInstance->Params.NrChannels
85      *at this point.
86      *So to treat the pInData as stereo we are setting channels to 2
87      */
88     if (channels == 1)
89     {
90         channels = 2;
91     }
92 #endif
93 
94     pScratch  = (LVM_FLOAT *) \
95                   pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
96 
97     /*
98      * Check if the processing is inplace
99      */
100 #ifdef SUPPORT_MC
101     /*
102      * The pInput buffer holds the first 2 (Left, Right) channels information.
103      * Hence the memory required by this buffer is 2 * NumFrames.
104      * The Concert Surround module carries out processing only on L, R.
105      */
106     pInput = pScratch + (2 * NrFrames);
107     pStIn  = pScratch + ((LVCS_SCRATCHBUFFERS - 2) * NrFrames);
108     /* The first two channel data is extracted from the input data and
109      * copied into pInput buffer
110      */
111     Copy_Float_Mc_Stereo((LVM_FLOAT *)pInData,
112                          (LVM_FLOAT *)pInput,
113                          NrFrames,
114                          channels);
115     Copy_Float((LVM_FLOAT *)pInput,
116                (LVM_FLOAT *)pStIn,
117                (LVM_INT16)(2 * NrFrames));
118 #else
119     if (pInData == pOutData)
120     {
121         /* Processing inplace */
122         pInput = pScratch + (2 * NumSamples);
123         Copy_Float((LVM_FLOAT *)pInData,           /* Source */
124                    (LVM_FLOAT *)pInput,            /* Destination */
125                    (LVM_INT16)(2 * NumSamples));     /* Left and right */
126     }
127     else
128     {
129         /* Processing outplace */
130         pInput = pInData;
131     }
132 #endif
133     /*
134      * Call the stereo enhancer
135      */
136 #ifdef SUPPORT_MC
137     err = LVCS_StereoEnhancer(hInstance,              /* Instance handle */
138                               pStIn,                  /* Pointer to the input data */
139                               pOutData,               /* Pointer to the output data */
140                               NrFrames);              /* Number of frames to process */
141 #else
142     err = LVCS_StereoEnhancer(hInstance,              /* Instance handle */
143                               pInData,                    /* Pointer to the input data */
144                               pOutData,                   /* Pointer to the output data */
145                               NumSamples);                /* Number of samples to process */
146 #endif
147 
148     /*
149      * Call the reverb generator
150      */
151     err = LVCS_ReverbGenerator(hInstance,             /* Instance handle */
152                                pOutData,                  /* Pointer to the input data */
153                                pOutData,                  /* Pointer to the output data */
154                                NumSamples);               /* Number of samples to process */
155 
156     /*
157      * Call the equaliser
158      */
159     err = LVCS_Equaliser(hInstance,                   /* Instance handle */
160                          pOutData,                        /* Pointer to the input data */
161                          NumSamples);                     /* Number of samples to process */
162 
163     /*
164      * Call the bypass mixer
165      */
166     err = LVCS_BypassMixer(hInstance,                 /* Instance handle */
167                            pOutData,                      /* Pointer to the processed data */
168                            pInput,                        /* Pointer to the input (unprocessed) data */
169                            pOutData,                      /* Pointer to the output data */
170                            NumSamples);                   /* Number of samples to process */
171 
172     if(err != LVCS_SUCCESS)
173     {
174         return err;
175     }
176 
177     return(LVCS_SUCCESS);
178 }
179 /************************************************************************************/
180 /*                                                                                  */
181 /* FUNCTION:                LVCS_Process                                            */
182 /*                                                                                  */
183 /* DESCRIPTION:                                                                     */
184 /*  Process function for the Concert Sound module. The implementation supports two  */
185 /*  variants of the algorithm, one for headphones and one for mobile speakers.      */
186 /*                                                                                  */
187 /*  Data can be processed in two formats, stereo or mono-in-stereo. Data in mono    */
188 /*  format is not supported, the calling routine must convert the mono stream to    */
189 /*  mono-in-stereo.                                                                 */
190 /*                                                                                  */
191 /*                                                                                  */
192 /* PARAMETERS:                                                                      */
193 /*  hInstance               Instance handle                                         */
194 /*  pInData                 Pointer to the input data                               */
195 /*  pOutData                Pointer to the output data                              */
196 /*  NumSamples              Number of samples in the input buffer                   */
197 /*                                                                                  */
198 /* RETURNS:                                                                         */
199 /*  LVCS_Success            Succeeded                                               */
200 /*  LVCS_TooManySamples     NumSamples was larger than the maximum block size       */
201 /*                                                                                  */
202 /* NOTES:                                                                           */
203 /*                                                                                  */
204 /************************************************************************************/
LVCS_Process(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)205 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t             hInstance,
206                                   const LVM_FLOAT           *pInData,
207                                   LVM_FLOAT                 *pOutData,
208                                   LVM_UINT16                NumSamples)
209 {
210 
211     LVCS_Instance_t *pInstance = (LVCS_Instance_t  *)hInstance;
212     LVCS_ReturnStatus_en err;
213 #ifdef SUPPORT_MC
214     /*Extract number of Channels info*/
215     LVM_INT32 channels = pInstance->Params.NrChannels;
216 #define NrFrames NumSamples  // alias for clarity
217     if (channels == 1)
218     {
219         channels = 2;
220     }
221 #endif
222     /*
223      * Check the number of samples is not too large
224      */
225     if (NumSamples > pInstance->Capabilities.MaxBlockSize)
226     {
227         return(LVCS_TOOMANYSAMPLES);
228     }
229 
230     /*
231      * Check if the algorithm is enabled
232      */
233     if (pInstance->Params.OperatingMode != LVCS_OFF)
234     {
235 #ifdef SUPPORT_MC
236         LVM_FLOAT *pStereoOut;
237         /*
238          * LVCS_Process_CS uses output buffer to store intermediate outputs of StereoEnhancer,
239          * Equalizer, ReverbGenerator and BypassMixer.
240          * So, to avoid i/o data overlapping, when i/o buffers are common, use scratch buffer
241          * to store intermediate outputs.
242          */
243         if (pOutData == pInData)
244         {
245           /*
246            * Scratch memory is used in 4 chunks of (2 * NrFrames) size.
247            * First chunk of memory is used by LVCS_StereoEnhancer and LVCS_ReverbGenerator,
248            * second and fourth are used as input buffers by pInput and pStIn in LVCS_Process_CS.
249            * Hence, pStereoOut is pointed to use unused third portion of scratch memory.
250            */
251             pStereoOut = (LVM_FLOAT *) \
252                           pInstance->MemoryTable. \
253                           Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress +
254                           ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
255         }
256         else
257         {
258             pStereoOut = pOutData;
259         }
260 
261         /*
262          * Call CS process function
263          */
264             err = LVCS_Process_CS(hInstance,
265                                   pInData,
266                                   pStereoOut,
267                                   NrFrames);
268 #else
269             err = LVCS_Process_CS(hInstance,
270                                   pInData,
271                                   pOutData,
272                                   NumSamples);
273 #endif
274 
275         /*
276          * Compress to reduce expansion effect of Concert Sound and correct volume
277          * differences for difference settings. Not applied in test modes
278          */
279         if ((pInstance->Params.OperatingMode == LVCS_ON)&& \
280                                         (pInstance->Params.CompressorMode == LVM_MODE_ON))
281         {
282             LVM_FLOAT Gain = pInstance->VolCorrect.CompMin;
283             LVM_FLOAT Current1;
284 
285             Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
286             Gain = (LVM_FLOAT)(  pInstance->VolCorrect.CompMin
287                                - (((LVM_FLOAT)pInstance->VolCorrect.CompMin  * (Current1)))
288                                + (((LVM_FLOAT)pInstance->VolCorrect.CompFull * (Current1))));
289 
290             if(NumSamples < LVCS_COMPGAINFRAME)
291             {
292 #ifdef SUPPORT_MC
293                 NonLinComp_Float(Gain,                    /* Compressor gain setting */
294                                  pStereoOut,
295                                  pStereoOut,
296                                  (LVM_INT32)(2 * NrFrames));
297 #else
298                 NonLinComp_Float(Gain,                    /* Compressor gain setting */
299                                  pOutData,
300                                  pOutData,
301                                  (LVM_INT32)(2 * NumSamples));
302 #endif
303             }
304             else
305             {
306                 LVM_FLOAT  GainStep;
307                 LVM_FLOAT  FinalGain;
308                 LVM_INT16  SampleToProcess = NumSamples;
309                 LVM_FLOAT  *pOutPtr;
310 
311                 /* Large changes in Gain can cause clicks in output
312                    Split data into small blocks and use interpolated gain values */
313 
314                 GainStep = (LVM_FLOAT)(((Gain-pInstance->CompressGain) * \
315                                                 LVCS_COMPGAINFRAME) / NumSamples);
316 
317                 if((GainStep == 0) && (pInstance->CompressGain < Gain))
318                 {
319                     GainStep = 1;
320                 }
321                 else
322                 {
323                     if((GainStep == 0) && (pInstance->CompressGain > Gain))
324                     {
325                         GainStep = -1;
326                     }
327                 }
328 
329                 FinalGain = Gain;
330                 Gain = pInstance->CompressGain;
331 #ifdef SUPPORT_MC
332                 pOutPtr = pStereoOut;
333 #else
334                 pOutPtr = pOutData;
335 #endif
336 
337                 while(SampleToProcess > 0)
338                 {
339                     Gain = (LVM_FLOAT)(Gain + GainStep);
340                     if((GainStep > 0) && (FinalGain <= Gain))
341                     {
342                         Gain = FinalGain;
343                         GainStep = 0;
344                     }
345 
346                     if((GainStep < 0) && (FinalGain > Gain))
347                     {
348                         Gain = FinalGain;
349                         GainStep = 0;
350                     }
351 
352                     if(SampleToProcess > LVCS_COMPGAINFRAME)
353                     {
354                         NonLinComp_Float(Gain,                    /* Compressor gain setting */
355                                          pOutPtr,
356                                          pOutPtr,
357                                          (LVM_INT32)(2 * LVCS_COMPGAINFRAME));
358                         pOutPtr += (2 * LVCS_COMPGAINFRAME);
359                         SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
360                     }
361                     else
362                     {
363                         NonLinComp_Float(Gain,                    /* Compressor gain setting */
364                                          pOutPtr,
365                                          pOutPtr,
366                                          (LVM_INT32)(2 * SampleToProcess));
367                         SampleToProcess = 0;
368                     }
369 
370                 }
371             }
372 
373             /* Store gain value*/
374             pInstance->CompressGain = Gain;
375         }
376 
377         if(pInstance->bInOperatingModeTransition == LVM_TRUE){
378 
379             /*
380              * Re-init bypass mix when timer has completed
381              */
382             if ((pInstance->bTimerDone == LVM_TRUE) &&
383                 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
384             {
385                 err = LVCS_BypassMixInit(hInstance,
386                                          &pInstance->Params);
387 
388                 if(err != LVCS_SUCCESS)
389                 {
390                     return err;
391                 }
392 
393             }
394             else{
395                 LVM_Timer ( &pInstance->TimerInstance,
396                             (LVM_INT16)NumSamples);
397             }
398         }
399 #ifdef SUPPORT_MC
400         Copy_Float_Stereo_Mc(pInData,
401                              pStereoOut,
402                              pOutData,
403                              NrFrames,
404                              channels);
405 #endif
406     }
407     else
408     {
409         if (pInData != pOutData)
410         {
411 #ifdef SUPPORT_MC
412             /*
413              * The algorithm is disabled so just copy the data
414              */
415             Copy_Float((LVM_FLOAT *)pInData,               /* Source */
416                        (LVM_FLOAT *)pOutData,                  /* Destination */
417                        (LVM_INT16)(channels * NrFrames));    /* All Channels*/
418 #else
419             /*
420              * The algorithm is disabled so just copy the data
421              */
422             Copy_Float((LVM_FLOAT *)pInData,               /* Source */
423                        (LVM_FLOAT *)pOutData,                  /* Destination */
424                        (LVM_INT16)(2 * NumSamples));             /* Left and right */
425 #endif
426         }
427     }
428 
429     return(LVCS_SUCCESS);
430 }
431