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