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