• 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 /*  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, const LVM_FLOAT* pInData,
69                                      LVM_FLOAT* pOutData, LVM_UINT16 NumSamples) {
70     const LVM_FLOAT* pInput;
71     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
72     LVM_FLOAT* pScratch;
73     LVCS_ReturnStatus_en err;
74     LVM_FLOAT* pStIn;
75     LVM_INT32 channels = pInstance->Params.NrChannels;
76 #define NrFrames NumSamples  // alias for clarity
77 
78     pScratch = (LVM_FLOAT*)pInstance->pScratch;
79 
80     /*
81      * Check if the processing is inplace
82      */
83     /*
84      * The pInput buffer holds the first 2 (Left, Right) channels information.
85      * Hence the memory required by this buffer is 2 * NumFrames.
86      * The Concert Surround module carries out processing only on L, R.
87      */
88     pInput = pScratch + (2 * NrFrames);
89     pStIn = pScratch + ((LVCS_SCRATCHBUFFERS - 2) * NrFrames);
90     if (channels == FCC_1) {
91         Copy_Float((LVM_FLOAT*)pInData, (LVM_FLOAT*)pInput, (LVM_INT16)NrFrames);
92         Copy_Float((LVM_FLOAT*)pInput, (LVM_FLOAT*)pStIn, (LVM_INT16)NrFrames);
93     } else {
94         /* The first two channel data is extracted from the input data and
95          * copied into pInput buffer
96          */
97         Copy_Float_Mc_Stereo((LVM_FLOAT*)pInData, (LVM_FLOAT*)pInput, NrFrames, channels);
98         Copy_Float((LVM_FLOAT*)pInput, (LVM_FLOAT*)pStIn, (LVM_INT16)(FCC_2 * NrFrames));
99     }
100     /*
101      * Call the stereo enhancer
102      */
103     err = LVCS_StereoEnhancer(hInstance, /* Instance handle */
104                               pStIn,     /* Pointer to the input data */
105                               pOutData,  /* Pointer to the output data */
106                               NrFrames); /* Number of frames 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         return err;
134     }
135 
136     return (LVCS_SUCCESS);
137 }
138 /************************************************************************************/
139 /*                                                                                  */
140 /* FUNCTION:                LVCS_Process                                            */
141 /*                                                                                  */
142 /* DESCRIPTION:                                                                     */
143 /*  Process function for the Concert Sound module. The implementation supports two  */
144 /*  variants of the algorithm, one for headphones and one for mobile speakers.      */
145 /*                                                                                  */
146 /*  Data can be processed in two formats, stereo or mono-in-stereo. Data in mono    */
147 /*  format is not supported, the calling routine must convert the mono stream to    */
148 /*  mono-in-stereo.                                                                 */
149 /*                                                                                  */
150 /*                                                                                  */
151 /* PARAMETERS:                                                                      */
152 /*  hInstance               Instance handle                                         */
153 /*  pInData                 Pointer to the input data                               */
154 /*  pOutData                Pointer to the output data                              */
155 /*  NumSamples              Number of samples in the input buffer                   */
156 /*                                                                                  */
157 /* RETURNS:                                                                         */
158 /*  LVCS_Success            Succeeded                                               */
159 /*  LVCS_TooManySamples     NumSamples was larger than the maximum block size       */
160 /*                                                                                  */
161 /* NOTES:                                                                           */
162 /*                                                                                  */
163 /************************************************************************************/
LVCS_Process(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)164 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance, const LVM_FLOAT* pInData,
165                                   LVM_FLOAT* pOutData, LVM_UINT16 NumSamples) {
166     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
167     LVCS_ReturnStatus_en err;
168     /*Extract number of Channels info*/
169     LVM_INT32 channels = pInstance->Params.NrChannels;
170     LVM_UINT16 destNumSamples = (channels == FCC_1) ? NumSamples : FCC_2 * NumSamples;
171     LVM_INT32 compGainInterval =
172             (channels == FCC_1) ? LVCS_COMPGAINFRAME : FCC_2 * LVCS_COMPGAINFRAME;
173 #define NrFrames NumSamples  // alias for clarity
174     /*
175      * Check the number of samples is not too large
176      */
177     if (NumSamples > pInstance->Capabilities.MaxBlockSize) {
178         return (LVCS_TOOMANYSAMPLES);
179     }
180 
181     /*
182      * Check if the algorithm is enabled
183      */
184     if (pInstance->Params.OperatingMode != LVCS_OFF) {
185         LVM_FLOAT* pStereoOut;
186         /*
187          * LVCS_Process_CS uses output buffer to store intermediate outputs of StereoEnhancer,
188          * Equalizer, ReverbGenerator and BypassMixer.
189          * So, to avoid i/o data overlapping, when i/o buffers are common, use scratch buffer
190          * to store intermediate outputs.
191          */
192         if (pOutData == pInData) {
193             /*
194              * Scratch memory is used in 4 chunks of (2 * NrFrames) size.
195              * First chunk of memory is used by LVCS_StereoEnhancer and LVCS_ReverbGenerator,
196              * second and fourth are used as input buffers by pInput and pStIn in LVCS_Process_CS.
197              * Hence, pStereoOut is pointed to use unused third portion of scratch memory.
198              */
199             pStereoOut = (LVM_FLOAT*)pInstance->pScratch + ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
200         } else {
201             pStereoOut = pOutData;
202         }
203 
204         /*
205          * Call CS process function
206          */
207         err = LVCS_Process_CS(hInstance, pInData, pStereoOut, NrFrames);
208 
209         /*
210          * Compress to reduce expansion effect of Concert Sound and correct volume
211          * differences for difference settings. Not applied in test modes
212          */
213         if ((pInstance->Params.OperatingMode == LVCS_ON) &&
214             (pInstance->Params.CompressorMode == LVM_MODE_ON)) {
215             LVM_FLOAT Gain = pInstance->VolCorrect.CompMin;
216             LVM_FLOAT Current1;
217 
218             Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
219             Gain = (LVM_FLOAT)(pInstance->VolCorrect.CompMin -
220                                (((LVM_FLOAT)pInstance->VolCorrect.CompMin * (Current1))) +
221                                (((LVM_FLOAT)pInstance->VolCorrect.CompFull * (Current1))));
222 
223             if (NumSamples < LVCS_COMPGAINFRAME) {
224                 NonLinComp_Float(Gain, /* Compressor gain setting */
225                                  pStereoOut, pStereoOut, (LVM_INT32)destNumSamples);
226             } else {
227                 LVM_FLOAT GainStep;
228                 LVM_FLOAT FinalGain;
229                 LVM_INT16 SampleToProcess = NumSamples;
230                 LVM_FLOAT* pOutPtr;
231 
232                 /* Large changes in Gain can cause clicks in output
233                    Split data into small blocks and use interpolated gain values */
234 
235                 GainStep = (LVM_FLOAT)(((Gain - pInstance->CompressGain) * LVCS_COMPGAINFRAME) /
236                                        NumSamples);
237 
238                 if ((GainStep == 0) && (pInstance->CompressGain < Gain)) {
239                     GainStep = 1;
240                 } else {
241                     if ((GainStep == 0) && (pInstance->CompressGain > Gain)) {
242                         GainStep = -1;
243                     }
244                 }
245 
246                 FinalGain = Gain;
247                 Gain = pInstance->CompressGain;
248                 pOutPtr = pStereoOut;
249 
250                 while (SampleToProcess > 0) {
251                     Gain = (LVM_FLOAT)(Gain + GainStep);
252                     if ((GainStep > 0) && (FinalGain <= Gain)) {
253                         Gain = FinalGain;
254                         GainStep = 0;
255                     }
256 
257                     if ((GainStep < 0) && (FinalGain > Gain)) {
258                         Gain = FinalGain;
259                         GainStep = 0;
260                     }
261 
262                     if (SampleToProcess > LVCS_COMPGAINFRAME) {
263                         NonLinComp_Float(Gain, /* Compressor gain setting */
264                                          pOutPtr, pOutPtr, compGainInterval);
265                         pOutPtr += compGainInterval;
266                         SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
267                     } else {
268                         NonLinComp_Float(Gain, /* Compressor gain setting */
269                                          pOutPtr, pOutPtr,
270                                          (channels == FCC_1)
271                                                  ? (LVM_INT32)(SampleToProcess)
272                                                  : (LVM_INT32)(FCC_2 * SampleToProcess));
273                         SampleToProcess = 0;
274                     }
275                 }
276             }
277 
278             /* Store gain value*/
279             pInstance->CompressGain = Gain;
280         }
281 
282         if (pInstance->bInOperatingModeTransition == LVM_TRUE) {
283             /*
284              * Re-init bypass mix when timer has completed
285              */
286             if ((pInstance->bTimerDone == LVM_TRUE) &&
287                 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0)) {
288                 err = LVCS_BypassMixInit(hInstance, &pInstance->Params);
289 
290                 if (err != LVCS_SUCCESS) {
291                     return err;
292                 }
293 
294             } else {
295                 LVM_Timer(&pInstance->TimerInstance, (LVM_INT16)NumSamples);
296             }
297         }
298         Copy_Float_Stereo_Mc(pInData, (const LVM_FLOAT*)pStereoOut, pOutData, NrFrames, channels);
299     } else {
300         if (pInData != pOutData) {
301             /*
302              * The algorithm is disabled so just copy the data
303              */
304             Copy_Float((LVM_FLOAT*)pInData,               /* Source */
305                        (LVM_FLOAT*)pOutData,              /* Destination */
306                        (LVM_INT16)(channels * NrFrames)); /* All Channels*/
307         }
308     }
309 
310     return (LVCS_SUCCESS);
311 }
312