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 #ifdef BUILD_FLOAT
LVCS_Process_CS(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)70 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t              hInstance,
71                                      const LVM_FLOAT            *pInData,
72                                      LVM_FLOAT                  *pOutData,
73                                      LVM_UINT16                 NumSamples)
74 {
75     const LVM_FLOAT     *pInput;
76     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
77     LVM_FLOAT           *pScratch;
78     LVCS_ReturnStatus_en err;
79 #ifdef SUPPORT_MC
80     LVM_FLOAT           *pStIn;
81     LVM_INT32           channels = pInstance->Params.NrChannels;
82 #define NrFrames NumSamples  // alias for clarity
83 
84     /*In case of mono processing, stereo input is created from mono
85      *and stored in pInData before applying any of the effects.
86      *However we do not update the value pInstance->Params.NrChannels
87      *at this point.
88      *So to treat the pInData as stereo we are setting channels to 2
89      */
90     if (channels == 1)
91     {
92         channels = 2;
93     }
94 #endif
95 
96     pScratch  = (LVM_FLOAT *) \
97                   pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
98 
99     /*
100      * Check if the processing is inplace
101      */
102 #ifdef SUPPORT_MC
103     /*
104      * The pInput buffer holds the first 2 (Left, Right) channels information.
105      * Hence the memory required by this buffer is 2 * NumFrames.
106      * The Concert Surround module carries out processing only on L, R.
107      */
108     pInput = pScratch + (2 * NrFrames);
109     pStIn  = pScratch + (LVCS_SCRATCHBUFFERS * NrFrames);
110     /* The first two channel data is extracted from the input data and
111      * copied into pInput buffer
112      */
113     Copy_Float_Mc_Stereo((LVM_FLOAT *)pInData,
114                          (LVM_FLOAT *)pInput,
115                          NrFrames,
116                          channels);
117     Copy_Float((LVM_FLOAT *)pInput,
118                (LVM_FLOAT *)pStIn,
119                (LVM_INT16)(2 * NrFrames));
120 #else
121     if (pInData == pOutData)
122     {
123         /* Processing inplace */
124         pInput = pScratch + (2 * NumSamples);
125         Copy_Float((LVM_FLOAT *)pInData,           /* Source */
126                    (LVM_FLOAT *)pInput,            /* Destination */
127                    (LVM_INT16)(2 * NumSamples));     /* Left and right */
128     }
129     else
130     {
131         /* Processing outplace */
132         pInput = pInData;
133     }
134 #endif
135     /*
136      * Call the stereo enhancer
137      */
138 #ifdef SUPPORT_MC
139     err = LVCS_StereoEnhancer(hInstance,              /* Instance handle */
140                               pStIn,                  /* Pointer to the input data */
141                               pOutData,               /* Pointer to the output data */
142                               NrFrames);              /* Number of frames to process */
143 #else
144     err = LVCS_StereoEnhancer(hInstance,              /* Instance handle */
145                               pInData,                    /* Pointer to the input data */
146                               pOutData,                   /* Pointer to the output data */
147                               NumSamples);                /* Number of samples to process */
148 #endif
149 
150     /*
151      * Call the reverb generator
152      */
153     err = LVCS_ReverbGenerator(hInstance,             /* Instance handle */
154                                pOutData,                  /* Pointer to the input data */
155                                pOutData,                  /* Pointer to the output data */
156                                NumSamples);               /* Number of samples to process */
157 
158     /*
159      * Call the equaliser
160      */
161     err = LVCS_Equaliser(hInstance,                   /* Instance handle */
162                          pOutData,                        /* Pointer to the input data */
163                          NumSamples);                     /* Number of samples to process */
164 
165     /*
166      * Call the bypass mixer
167      */
168     err = LVCS_BypassMixer(hInstance,                 /* Instance handle */
169                            pOutData,                      /* Pointer to the processed data */
170                            pInput,                        /* Pointer to the input (unprocessed) data */
171                            pOutData,                      /* Pointer to the output data */
172                            NumSamples);                   /* Number of samples to process */
173 
174     if(err != LVCS_SUCCESS)
175     {
176         return err;
177     }
178 
179     return(LVCS_SUCCESS);
180 }
181 #else
LVCS_Process_CS(LVCS_Handle_t hInstance,const LVM_INT16 * pInData,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)182 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t              hInstance,
183                                      const LVM_INT16            *pInData,
184                                      LVM_INT16                  *pOutData,
185                                      LVM_UINT16                 NumSamples)
186 {
187     const LVM_INT16     *pInput;
188     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
189     LVM_INT16           *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
190     LVCS_ReturnStatus_en err;
191 
192     /*
193      * Check if the processing is inplace
194      */
195     if (pInData == pOutData)
196     {
197         /* Processing inplace */
198         pInput = pScratch + (2*NumSamples);
199         Copy_16((LVM_INT16 *)pInData,           /* Source */
200                 (LVM_INT16 *)pInput,            /* Destination */
201                 (LVM_INT16)(2*NumSamples));     /* Left and right */
202     }
203     else
204     {
205         /* Processing outplace */
206         pInput = pInData;
207     }
208 
209     /*
210      * Call the stereo enhancer
211      */
212     err=LVCS_StereoEnhancer(hInstance,              /* Instance handle */
213                         pInData,                    /* Pointer to the input data */
214                         pOutData,                   /* Pointer to the output data */
215                         NumSamples);                /* Number of samples to process */
216 
217     /*
218      * Call the reverb generator
219      */
220     err=LVCS_ReverbGenerator(hInstance,             /* Instance handle */
221                          pOutData,                  /* Pointer to the input data */
222                          pOutData,                  /* Pointer to the output data */
223                          NumSamples);               /* Number of samples to process */
224 
225     /*
226      * Call the equaliser
227      */
228     err=LVCS_Equaliser(hInstance,                   /* Instance handle */
229                    pOutData,                        /* Pointer to the input data */
230                    NumSamples);                     /* Number of samples to process */
231 
232     /*
233      * Call the bypass mixer
234      */
235     err=LVCS_BypassMixer(hInstance,                 /* Instance handle */
236                      pOutData,                      /* Pointer to the processed data */
237                      pInput,                        /* Pointer to the input (unprocessed) data */
238                      pOutData,                      /* Pointer to the output data */
239                      NumSamples);                   /* Number of samples to process */
240 
241     if(err !=LVCS_SUCCESS)
242     {
243         return err;
244     }
245 
246     return(LVCS_SUCCESS);
247 }
248 #endif
249 /************************************************************************************/
250 /*                                                                                  */
251 /* FUNCTION:                LVCS_Process                                            */
252 /*                                                                                  */
253 /* DESCRIPTION:                                                                     */
254 /*  Process function for the Concert Sound module. The implementation supports two  */
255 /*  variants of the algorithm, one for headphones and one for mobile speakers.      */
256 /*                                                                                  */
257 /*  Data can be processed in two formats, stereo or mono-in-stereo. Data in mono    */
258 /*  format is not supported, the calling routine must convert the mono stream to    */
259 /*  mono-in-stereo.                                                                 */
260 /*                                                                                  */
261 /*                                                                                  */
262 /* PARAMETERS:                                                                      */
263 /*  hInstance               Instance handle                                         */
264 /*  pInData                 Pointer to the input data                               */
265 /*  pOutData                Pointer to the output data                              */
266 /*  NumSamples              Number of samples in the input buffer                   */
267 /*                                                                                  */
268 /* RETURNS:                                                                         */
269 /*  LVCS_Success            Succeeded                                               */
270 /*  LVCS_TooManySamples     NumSamples was larger than the maximum block size       */
271 /*                                                                                  */
272 /* NOTES:                                                                           */
273 /*                                                                                  */
274 /************************************************************************************/
275 #ifdef BUILD_FLOAT
LVCS_Process(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)276 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t             hInstance,
277                                   const LVM_FLOAT           *pInData,
278                                   LVM_FLOAT                 *pOutData,
279                                   LVM_UINT16                NumSamples)
280 {
281 
282     LVCS_Instance_t *pInstance = (LVCS_Instance_t  *)hInstance;
283     LVCS_ReturnStatus_en err;
284 #ifdef SUPPORT_MC
285     /*Extract number of Channels info*/
286     LVM_INT32 channels = pInstance->Params.NrChannels;
287 #define NrFrames NumSamples  // alias for clarity
288     if (channels == 1)
289     {
290         channels = 2;
291     }
292 #endif
293     /*
294      * Check the number of samples is not too large
295      */
296     if (NumSamples > pInstance->Capabilities.MaxBlockSize)
297     {
298         return(LVCS_TOOMANYSAMPLES);
299     }
300 
301     /*
302      * Check if the algorithm is enabled
303      */
304     if (pInstance->Params.OperatingMode != LVCS_OFF)
305     {
306         /*
307          * Call CS process function
308          */
309             err = LVCS_Process_CS(hInstance,
310                                   pInData,
311                                   pOutData,
312                                   NumSamples);
313 
314 
315         /*
316          * Compress to reduce expansion effect of Concert Sound and correct volume
317          * differences for difference settings. Not applied in test modes
318          */
319         if ((pInstance->Params.OperatingMode == LVCS_ON)&& \
320                                         (pInstance->Params.CompressorMode == LVM_MODE_ON))
321         {
322             LVM_FLOAT Gain = pInstance->VolCorrect.CompMin;
323             LVM_FLOAT Current1;
324 
325             Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
326             Gain = (LVM_FLOAT)(  pInstance->VolCorrect.CompMin
327                                - (((LVM_FLOAT)pInstance->VolCorrect.CompMin  * (Current1)))
328                                + (((LVM_FLOAT)pInstance->VolCorrect.CompFull * (Current1))));
329 
330             if(NumSamples < LVCS_COMPGAINFRAME)
331             {
332                 NonLinComp_Float(Gain,                    /* Compressor gain setting */
333                                  pOutData,
334                                  pOutData,
335                                  (LVM_INT32)(2 * NumSamples));
336             }
337             else
338             {
339                 LVM_FLOAT  GainStep;
340                 LVM_FLOAT  FinalGain;
341                 LVM_INT16  SampleToProcess = NumSamples;
342                 LVM_FLOAT  *pOutPtr;
343 
344                 /* Large changes in Gain can cause clicks in output
345                    Split data into small blocks and use interpolated gain values */
346 
347                 GainStep = (LVM_FLOAT)(((Gain-pInstance->CompressGain) * \
348                                                 LVCS_COMPGAINFRAME) / NumSamples);
349 
350                 if((GainStep == 0) && (pInstance->CompressGain < Gain))
351                 {
352                     GainStep = 1;
353                 }
354                 else
355                 {
356                     if((GainStep == 0) && (pInstance->CompressGain > Gain))
357                     {
358                         GainStep = -1;
359                     }
360                 }
361 
362                 FinalGain = Gain;
363                 Gain = pInstance->CompressGain;
364                 pOutPtr = pOutData;
365 
366                 while(SampleToProcess > 0)
367                 {
368                     Gain = (LVM_FLOAT)(Gain + GainStep);
369                     if((GainStep > 0) && (FinalGain <= Gain))
370                     {
371                         Gain = FinalGain;
372                         GainStep = 0;
373                     }
374 
375                     if((GainStep < 0) && (FinalGain > Gain))
376                     {
377                         Gain = FinalGain;
378                         GainStep = 0;
379                     }
380 
381                     if(SampleToProcess > LVCS_COMPGAINFRAME)
382                     {
383                         NonLinComp_Float(Gain,                    /* Compressor gain setting */
384                                          pOutPtr,
385                                          pOutPtr,
386                                          (LVM_INT32)(2 * LVCS_COMPGAINFRAME));
387                         pOutPtr += (2 * LVCS_COMPGAINFRAME);
388                         SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
389                     }
390                     else
391                     {
392                         NonLinComp_Float(Gain,                    /* Compressor gain setting */
393                                          pOutPtr,
394                                          pOutPtr,
395                                          (LVM_INT32)(2 * SampleToProcess));
396                         SampleToProcess = 0;
397                     }
398 
399                 }
400             }
401 
402             /* Store gain value*/
403             pInstance->CompressGain = Gain;
404         }
405 
406 
407         if(pInstance->bInOperatingModeTransition == LVM_TRUE){
408 
409             /*
410              * Re-init bypass mix when timer has completed
411              */
412             if ((pInstance->bTimerDone == LVM_TRUE) &&
413                 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
414             {
415                 err = LVCS_BypassMixInit(hInstance,
416                                          &pInstance->Params);
417 
418                 if(err != LVCS_SUCCESS)
419                 {
420                     return err;
421                 }
422 
423             }
424             else{
425                 LVM_Timer ( &pInstance->TimerInstance,
426                             (LVM_INT16)NumSamples);
427             }
428         }
429 #ifdef SUPPORT_MC
430         Copy_Float_Stereo_Mc(pInData,
431                              pOutData,
432                              NrFrames,
433                              channels);
434 #endif
435     }
436     else
437     {
438         if (pInData != pOutData)
439         {
440 #ifdef SUPPORT_MC
441             /*
442              * The algorithm is disabled so just copy the data
443              */
444             Copy_Float((LVM_FLOAT *)pInData,               /* Source */
445                        (LVM_FLOAT *)pOutData,                  /* Destination */
446                        (LVM_INT16)(channels * NrFrames));    /* All Channels*/
447 #else
448             /*
449              * The algorithm is disabled so just copy the data
450              */
451             Copy_Float((LVM_FLOAT *)pInData,               /* Source */
452                        (LVM_FLOAT *)pOutData,                  /* Destination */
453                        (LVM_INT16)(2 * NumSamples));             /* Left and right */
454 #endif
455         }
456     }
457 
458 
459     return(LVCS_SUCCESS);
460 }
461 #else
LVCS_Process(LVCS_Handle_t hInstance,const LVM_INT16 * pInData,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)462 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t             hInstance,
463                                   const LVM_INT16           *pInData,
464                                   LVM_INT16                 *pOutData,
465                                   LVM_UINT16                NumSamples)
466 {
467 
468     LVCS_Instance_t *pInstance =(LVCS_Instance_t  *)hInstance;
469     LVCS_ReturnStatus_en err;
470 
471     /*
472      * Check the number of samples is not too large
473      */
474     if (NumSamples > pInstance->Capabilities.MaxBlockSize)
475     {
476         return(LVCS_TOOMANYSAMPLES);
477     }
478 
479     /*
480      * Check if the algorithm is enabled
481      */
482     if (pInstance->Params.OperatingMode != LVCS_OFF)
483     {
484         /*
485          * Call CS process function
486          */
487             err=LVCS_Process_CS(hInstance,
488                             pInData,
489                             pOutData,
490                             NumSamples);
491 
492         /*
493          * Compress to reduce expansion effect of Concert Sound and correct volume
494          * differences for difference settings. Not applied in test modes
495          */
496         if ((pInstance->Params.OperatingMode == LVCS_ON)&&(pInstance->Params.CompressorMode == LVM_MODE_ON))
497         {
498             LVM_INT16 Gain = pInstance->VolCorrect.CompMin;
499             LVM_INT32 Current1;
500 
501             Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
502             Gain = (LVM_INT16)(  pInstance->VolCorrect.CompMin
503                                - (((LVM_INT32)pInstance->VolCorrect.CompMin  * (Current1)) >> 15)
504                                + (((LVM_INT32)pInstance->VolCorrect.CompFull * (Current1)) >> 15) );
505 
506             if(NumSamples < LVCS_COMPGAINFRAME)
507             {
508                 NonLinComp_D16(Gain,                    /* Compressor gain setting */
509                     pOutData,
510                     pOutData,
511                     (LVM_INT32)(2*NumSamples));
512             }
513             else
514             {
515                 LVM_INT16  GainStep;
516                 LVM_INT16  FinalGain;
517                 LVM_INT16  SampleToProcess = NumSamples;
518                 LVM_INT16  *pOutPtr;
519 
520                 /* Large changes in Gain can cause clicks in output
521                    Split data into small blocks and use interpolated gain values */
522 
523                 GainStep = (LVM_INT16)(((Gain-pInstance->CompressGain) * LVCS_COMPGAINFRAME)/NumSamples);
524 
525                 if((GainStep ==0)&&(pInstance->CompressGain < Gain))
526                 {
527                     GainStep=1;
528                 }
529                 else
530                 {
531                     if((GainStep ==0)&&(pInstance->CompressGain > Gain))
532                     {
533                         GainStep=-1;
534                     }
535                 }
536 
537                 FinalGain = Gain;
538                 Gain = pInstance->CompressGain;
539                 pOutPtr = pOutData;
540 
541                 while(SampleToProcess > 0)
542                 {
543                     Gain = (LVM_INT16)(Gain + GainStep);
544                     if((GainStep > 0)&& (FinalGain <= Gain))
545                     {
546                         Gain = FinalGain;
547                         GainStep =0;
548                     }
549 
550                     if((GainStep < 0)&& (FinalGain > Gain))
551                     {
552                         Gain = FinalGain;
553                         GainStep =0;
554                     }
555 
556                     if(SampleToProcess > LVCS_COMPGAINFRAME)
557                     {
558                         NonLinComp_D16(Gain,                    /* Compressor gain setting */
559                             pOutPtr,
560                             pOutPtr,
561                             (LVM_INT32)(2*LVCS_COMPGAINFRAME));
562                         pOutPtr +=(2*LVCS_COMPGAINFRAME);
563                         SampleToProcess = (LVM_INT16)(SampleToProcess-LVCS_COMPGAINFRAME);
564                     }
565                     else
566                     {
567                         NonLinComp_D16(Gain,                    /* Compressor gain setting */
568                             pOutPtr,
569                             pOutPtr,
570                             (LVM_INT32)(2*SampleToProcess));
571 
572                         SampleToProcess = 0;
573                     }
574 
575                 }
576             }
577 
578             /* Store gain value*/
579             pInstance->CompressGain = Gain;
580         }
581 
582 
583         if(pInstance->bInOperatingModeTransition == LVM_TRUE){
584 
585             /*
586              * Re-init bypass mix when timer has completed
587              */
588             if ((pInstance->bTimerDone == LVM_TRUE) &&
589                 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
590             {
591                 err=LVCS_BypassMixInit(hInstance,
592                                    &pInstance->Params);
593 
594                 if(err != LVCS_SUCCESS)
595                 {
596                     return err;
597                 }
598 
599             }
600             else{
601                 LVM_Timer ( &pInstance->TimerInstance,
602                             (LVM_INT16)NumSamples);
603             }
604         }
605     }
606     else
607     {
608         if (pInData != pOutData)
609         {
610             /*
611              * The algorithm is disabled so just copy the data
612              */
613             Copy_16((LVM_INT16 *)pInData,               /* Source */
614                 (LVM_INT16 *)pOutData,                  /* Destination */
615                 (LVM_INT16)(2*NumSamples));             /* Left and right */
616         }
617     }
618 
619 
620     return(LVCS_SUCCESS);
621 }
622 #endif
623