LVCS_Process.c revision d7d013446a64c6de9f0f2dfe098a721b140e0b48
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
70LVCS_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
140LVCS_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
234LVCS_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
397LVCS_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