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
LVCS_Process_CS(LVCS_Handle_t hInstance,const LVM_INT16 * pInData,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)70 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t hInstance,
71 const LVM_INT16 *pInData,
72 LVM_INT16 *pOutData,
73 LVM_UINT16 NumSamples)
74 {
75 const LVM_INT16 *pInput;
76 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
77 LVM_INT16 *pScratch = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
78 LVCS_ReturnStatus_en err;
79
80 /*
81 * Check if the processing is inplace
82 */
83 if (pInData == pOutData)
84 {
85 /* Processing inplace */
86 pInput = pScratch + (2*NumSamples);
87 Copy_16((LVM_INT16 *)pInData, /* Source */
88 (LVM_INT16 *)pInput, /* Destination */
89 (LVM_INT16)(2*NumSamples)); /* Left and right */
90 }
91 else
92 {
93 /* Processing outplace */
94 pInput = pInData;
95 }
96
97 /*
98 * Call the stereo enhancer
99 */
100 err=LVCS_StereoEnhancer(hInstance, /* Instance handle */
101 pInData, /* Pointer to the input data */
102 pOutData, /* Pointer to the output data */
103 NumSamples); /* Number of samples to process */
104
105 /*
106 * Call the reverb generator
107 */
108 err=LVCS_ReverbGenerator(hInstance, /* Instance handle */
109 pOutData, /* Pointer to the input data */
110 pOutData, /* Pointer to the output data */
111 NumSamples); /* Number of samples to process */
112
113 /*
114 * Call the equaliser
115 */
116 err=LVCS_Equaliser(hInstance, /* Instance handle */
117 pOutData, /* Pointer to the input data */
118 NumSamples); /* Number of samples to process */
119
120 /*
121 * Call the bypass mixer
122 */
123 err=LVCS_BypassMixer(hInstance, /* Instance handle */
124 pOutData, /* Pointer to the processed data */
125 pInput, /* Pointer to the input (unprocessed) data */
126 pOutData, /* Pointer to the output data */
127 NumSamples); /* Number of samples to process */
128
129 if(err !=LVCS_SUCCESS)
130 {
131 return err;
132 }
133
134 return(LVCS_SUCCESS);
135 }
136
137 /************************************************************************************/
138 /* */
139 /* FUNCTION: LVCS_Process */
140 /* */
141 /* DESCRIPTION: */
142 /* Process function for the Concert Sound module. The implementation supports two */
143 /* variants of the algorithm, one for headphones and one for mobile speakers. */
144 /* */
145 /* Data can be processed in two formats, stereo or mono-in-stereo. Data in mono */
146 /* format is not supported, the calling routine must convert the mono stream to */
147 /* mono-in-stereo. */
148 /* */
149 /* */
150 /* PARAMETERS: */
151 /* hInstance Instance handle */
152 /* pInData Pointer to the input data */
153 /* pOutData Pointer to the output data */
154 /* NumSamples Number of samples in the input buffer */
155 /* */
156 /* RETURNS: */
157 /* LVCS_Success Succeeded */
158 /* LVCS_TooManySamples NumSamples was larger than the maximum block size */
159 /* */
160 /* NOTES: */
161 /* */
162 /************************************************************************************/
163
LVCS_Process(LVCS_Handle_t hInstance,const LVM_INT16 * pInData,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)164 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance,
165 const LVM_INT16 *pInData,
166 LVM_INT16 *pOutData,
167 LVM_UINT16 NumSamples)
168 {
169
170 LVCS_Instance_t *pInstance =(LVCS_Instance_t *)hInstance;
171 LVCS_ReturnStatus_en err;
172
173 /*
174 * Check the number of samples is not too large
175 */
176 if (NumSamples > pInstance->Capabilities.MaxBlockSize)
177 {
178 return(LVCS_TOOMANYSAMPLES);
179 }
180
181 /*
182 * Check if the algorithm is enabled
183 */
184 if (pInstance->Params.OperatingMode != LVCS_OFF)
185 {
186 /*
187 * Call CS process function
188 */
189 err=LVCS_Process_CS(hInstance,
190 pInData,
191 pOutData,
192 NumSamples);
193
194 /*
195 * Compress to reduce expansion effect of Concert Sound and correct volume
196 * differences for difference settings. Not applied in test modes
197 */
198 if ((pInstance->Params.OperatingMode == LVCS_ON)&&(pInstance->Params.CompressorMode == LVM_MODE_ON))
199 {
200 LVM_INT16 Gain = pInstance->VolCorrect.CompMin;
201 LVM_INT32 Current1;
202
203 Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]);
204 Gain = (LVM_INT16)( pInstance->VolCorrect.CompMin
205 - (((LVM_INT32)pInstance->VolCorrect.CompMin * (Current1)) >> 15)
206 + (((LVM_INT32)pInstance->VolCorrect.CompFull * (Current1)) >> 15) );
207
208 if(NumSamples < LVCS_COMPGAINFRAME)
209 {
210 NonLinComp_D16(Gain, /* Compressor gain setting */
211 pOutData,
212 pOutData,
213 (LVM_INT32)(2*NumSamples));
214 }
215 else
216 {
217 LVM_INT16 GainStep;
218 LVM_INT16 FinalGain;
219 LVM_INT16 SampleToProcess = NumSamples;
220 LVM_INT16 *pOutPtr;
221
222 /* Large changes in Gain can cause clicks in output
223 Split data into small blocks and use interpolated gain values */
224
225 GainStep = (LVM_INT16)(((Gain-pInstance->CompressGain) * LVCS_COMPGAINFRAME)/NumSamples);
226
227 if((GainStep ==0)&&(pInstance->CompressGain < Gain))
228 {
229 GainStep=1;
230 }
231 else
232 {
233 if((GainStep ==0)&&(pInstance->CompressGain > Gain))
234 {
235 GainStep=-1;
236 }
237 }
238
239 FinalGain = Gain;
240 Gain = pInstance->CompressGain;
241 pOutPtr = pOutData;
242
243 while(SampleToProcess > 0)
244 {
245 Gain = (LVM_INT16)(Gain + GainStep);
246 if((GainStep > 0)&& (FinalGain <= Gain))
247 {
248 Gain = FinalGain;
249 GainStep =0;
250 }
251
252 if((GainStep < 0)&& (FinalGain > Gain))
253 {
254 Gain = FinalGain;
255 GainStep =0;
256 }
257
258 if(SampleToProcess > LVCS_COMPGAINFRAME)
259 {
260 NonLinComp_D16(Gain, /* Compressor gain setting */
261 pOutPtr,
262 pOutPtr,
263 (LVM_INT32)(2*LVCS_COMPGAINFRAME));
264 pOutPtr +=(2*LVCS_COMPGAINFRAME);
265 SampleToProcess = (LVM_INT16)(SampleToProcess-LVCS_COMPGAINFRAME);
266 }
267 else
268 {
269 NonLinComp_D16(Gain, /* Compressor gain setting */
270 pOutPtr,
271 pOutPtr,
272 (LVM_INT32)(2*SampleToProcess));
273
274 SampleToProcess = 0;
275 }
276
277 }
278 }
279
280 /* Store gain value*/
281 pInstance->CompressGain = Gain;
282 }
283
284
285 if(pInstance->bInOperatingModeTransition == LVM_TRUE){
286
287 /*
288 * Re-init bypass mix when timer has completed
289 */
290 if ((pInstance->bTimerDone == LVM_TRUE) &&
291 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0))
292 {
293 err=LVCS_BypassMixInit(hInstance,
294 &pInstance->Params);
295
296 if(err != LVCS_SUCCESS)
297 {
298 return err;
299 }
300
301 }
302 else{
303 LVM_Timer ( &pInstance->TimerInstance,
304 (LVM_INT16)NumSamples);
305 }
306 }
307 }
308 else
309 {
310 if (pInData != pOutData)
311 {
312 /*
313 * The algorithm is disabled so just copy the data
314 */
315 Copy_16((LVM_INT16 *)pInData, /* Source */
316 (LVM_INT16 *)pOutData, /* Destination */
317 (LVM_INT16)(2*NumSamples)); /* Left and right */
318 }
319 }
320
321
322 return(LVCS_SUCCESS);
323 }
324
325
326
327
328
329
330
331
332
333
334