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