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