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 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 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 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 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