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 /* Includes */ 21 /* */ 22 /************************************************************************************/ 23 24 #include "LVCS.h" 25 #include "LVCS_Private.h" 26 #include "LVCS_ReverbGenerator.h" 27 #include "LVC_Mixer.h" 28 #include "VectorArithmetic.h" 29 #include "BIQUAD.h" 30 #include "LVCS_Tables.h" 31 32 /************************************************************************************/ 33 /* */ 34 /* FUNCTION: LVCS_ReverbGeneratorInit */ 35 /* */ 36 /* DESCRIPTION: */ 37 /* Initialises the reverb module. The delay buffer size is configured for the */ 38 /* sample rate and the speaker type. */ 39 /* */ 40 /* The routine may also be called for re-initialisation, i.e. when one of the */ 41 /* control parameters has changed. In this case the delay and filters are only */ 42 /* re-initialised if one of the following two conditions is met: */ 43 /* - the sample rate has changed */ 44 /* - the speaker type changes to/from the mobile speaker */ 45 /* */ 46 /* */ 47 /* PARAMETERS: */ 48 /* hInstance Instance Handle */ 49 /* pParams Pointer to the inialisation parameters */ 50 /* */ 51 /* RETURNS: */ 52 /* LVCS_Success Always succeeds */ 53 /* */ 54 /* NOTES: */ 55 /* 1. In the delay settings 'Samples' is the number of samples to the end of the */ 56 /* buffer. */ 57 /* 2. The numerator coefficients of the filter are negated to cause an inversion. */ 58 /* */ 59 /************************************************************************************/ 60 #ifdef BUILD_FLOAT 61 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance, 62 LVCS_Params_t *pParams) 63 { 64 65 LVM_UINT16 Delay; 66 LVM_UINT16 Offset; 67 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 68 LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation; 69 LVCS_Data_t *pData; 70 LVCS_Coefficient_t *pCoefficients; 71 BQ_FLOAT_Coefs_t Coeffs; 72 const BiquadA012B12CoefsSP_t *pReverbCoefTable; 73 74 75 pData = (LVCS_Data_t *) \ 76 pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress; 77 78 pCoefficients = (LVCS_Coefficient_t *) \ 79 pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress; 80 81 /* 82 * Initialise the delay and filters if: 83 * - the sample rate has changed 84 * - the speaker type has changed to or from the mobile speaker 85 */ 86 if(pInstance->Params.SampleRate != pParams->SampleRate ) /* Sample rate change test */ 87 88 { 89 /* 90 * Setup the delay 91 */ 92 Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate]; 93 94 95 pConfig->DelaySize = (LVM_INT16)(2 * Delay); 96 pConfig->DelayOffset = 0; 97 LoadConst_Float(0, /* Value */ 98 (LVM_FLOAT *)&pConfig->StereoSamples[0], /* Destination */ 99 /* Number of words */ 100 (LVM_UINT16)(sizeof(pConfig->StereoSamples) / sizeof(LVM_FLOAT))); 101 /* 102 * Setup the filters 103 */ 104 Offset = (LVM_UINT16)pParams->SampleRate; 105 pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0]; 106 107 /* Convert incoming coefficients to the required format/ordering */ 108 Coeffs.A0 = (LVM_FLOAT)pReverbCoefTable[Offset].A0; 109 Coeffs.A1 = (LVM_FLOAT)pReverbCoefTable[Offset].A1; 110 Coeffs.A2 = (LVM_FLOAT)pReverbCoefTable[Offset].A2; 111 Coeffs.B1 = (LVM_FLOAT)-pReverbCoefTable[Offset].B1; 112 Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2; 113 114 LoadConst_Float(0, /* Value */ 115 (void *)&pData->ReverbBiquadTaps, /* Destination Cast to void: 116 no dereferencing in function*/ 117 /* Number of words */ 118 (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT))); 119 120 BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance, 121 &pData->ReverbBiquadTaps, 122 &Coeffs); 123 124 /* Callbacks */ 125 switch(pReverbCoefTable[Offset].Scale) 126 { 127 case 14: 128 pConfig->pBiquadCallBack = BQ_2I_D16F16C14_TRC_WRA_01; 129 break; 130 case 15: 131 pConfig->pBiquadCallBack = BQ_2I_D16F16C15_TRC_WRA_01; 132 break; 133 } 134 135 136 /* 137 * Setup the mixer 138 */ 139 pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC); 140 pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC); 141 } 142 143 if(pInstance->Params.ReverbLevel != pParams->ReverbLevel) 144 { 145 LVM_INT32 ReverbPercentage = 83886; // 1 Percent Reverb i.e 1/100 in Q 23 format 146 ReverbPercentage *= pParams->ReverbLevel; // Actual Reverb Level in Q 23 format 147 pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage>>8)) / 32767.0f; 148 } 149 return(LVCS_SUCCESS); 150 } 151 #else 152 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance, 153 LVCS_Params_t *pParams) 154 { 155 156 LVM_UINT16 Delay; 157 LVM_UINT16 Offset; 158 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 159 LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation; 160 LVCS_Data_t *pData = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress; 161 LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress; 162 BQ_C16_Coefs_t Coeffs; 163 const BiquadA012B12CoefsSP_t *pReverbCoefTable; 164 165 /* 166 * Initialise the delay and filters if: 167 * - the sample rate has changed 168 * - the speaker type has changed to or from the mobile speaker 169 */ 170 if(pInstance->Params.SampleRate != pParams->SampleRate ) /* Sample rate change test */ 171 172 { 173 /* 174 * Setup the delay 175 */ 176 Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate]; 177 178 179 pConfig->DelaySize = (LVM_INT16)(2 * Delay); 180 pConfig->DelayOffset = 0; 181 LoadConst_16(0, /* Value */ 182 (LVM_INT16 *)&pConfig->StereoSamples[0], /* Destination */ 183 (LVM_UINT16)(sizeof(pConfig->StereoSamples)/sizeof(LVM_INT16))); /* Number of words */ 184 185 /* 186 * Setup the filters 187 */ 188 Offset = (LVM_UINT16)pParams->SampleRate; 189 pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0]; 190 191 /* Convert incoming coefficients to the required format/ordering */ 192 Coeffs.A0 = (LVM_INT16)pReverbCoefTable[Offset].A0; 193 Coeffs.A1 = (LVM_INT16)pReverbCoefTable[Offset].A1; 194 Coeffs.A2 = (LVM_INT16)pReverbCoefTable[Offset].A2; 195 Coeffs.B1 = (LVM_INT16)-pReverbCoefTable[Offset].B1; 196 Coeffs.B2 = (LVM_INT16)-pReverbCoefTable[Offset].B2; 197 198 LoadConst_16(0, /* Value */ 199 (void *)&pData->ReverbBiquadTaps, /* Destination Cast to void: no dereferencing in function*/ 200 (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps)/sizeof(LVM_INT16))); /* Number of words */ 201 202 BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance, 203 &pData->ReverbBiquadTaps, 204 &Coeffs); 205 206 /* Callbacks */ 207 switch(pReverbCoefTable[Offset].Scale) 208 { 209 case 14: 210 pConfig->pBiquadCallBack = BQ_2I_D16F16C14_TRC_WRA_01; 211 break; 212 case 15: 213 pConfig->pBiquadCallBack = BQ_2I_D16F16C15_TRC_WRA_01; 214 break; 215 } 216 217 218 /* 219 * Setup the mixer 220 */ 221 pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC); 222 pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC); 223 } 224 225 if(pInstance->Params.ReverbLevel != pParams->ReverbLevel) 226 { 227 LVM_INT32 ReverbPercentage=83886; // 1 Percent Reverb i.e 1/100 in Q 23 format 228 ReverbPercentage*=pParams->ReverbLevel; // Actual Reverb Level in Q 23 format 229 pConfig->ReverbLevel=(LVM_INT16)(ReverbPercentage>>8); // Reverb Level in Q 15 format 230 } 231 232 return(LVCS_SUCCESS); 233 } 234 #endif 235 /************************************************************************************/ 236 /* */ 237 /* FUNCTION: LVCS_Reverb */ 238 /* */ 239 /* DESCRIPTION: */ 240 /* Create reverb using the block of input samples based on the following block */ 241 /* diagram: */ 242 /* ________ ________ */ 243 /* | | | | */ 244 /* _____ _______ | |----------->| | ______ ___ */ 245 /* | | | | | Stereo | | L & R | | | | | */ 246 /* -->| LPF |-->| Delay |-->| to | ____ | to |-->| Gain |-->| + |--> */ 247 /* | |_____| |_______| | L & R | | | | Stereo | |______| |___| */ 248 /* | | |-->| -1 |-->| | | */ 249 /* | |________| |____| |________| | */ 250 /* | | */ 251 /* |-----------------------------------------------------------------------| */ 252 /* */ 253 /* The input buffer is broken in to sub-blocks of the size of the delay or less. */ 254 /* This allows the delay buffer to be treated as a circular buffer but processed */ 255 /* as a linear buffer. */ 256 /* */ 257 /* */ 258 /* PARAMETERS: */ 259 /* hInstance Instance Handle */ 260 /* pInData Pointer to the input buffer */ 261 /* pOutData Pointer to the output buffer */ 262 /* NumSamples Number of samples to process */ 263 /* */ 264 /* RETURNS: */ 265 /* LVCS_Success Always succeeds */ 266 /* */ 267 /* NOTES: */ 268 /* 1. Process in blocks of samples the size of the delay where possible, if not */ 269 /* the number of samples left over */ 270 /* 2. The Gain is combined with the LPF and incorporated in to the coefficients */ 271 /* */ 272 /************************************************************************************/ 273 #ifdef BUILD_FLOAT 274 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance, 275 const LVM_FLOAT *pInData, 276 LVM_FLOAT *pOutData, 277 LVM_UINT16 NumSamples) 278 { 279 280 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 281 LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation; 282 LVCS_Coefficient_t *pCoefficients; 283 LVM_FLOAT *pScratch; 284 285 pCoefficients = (LVCS_Coefficient_t *)\ 286 pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress; 287 288 pScratch = (LVM_FLOAT *)\ 289 pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress; 290 291 /* 292 * Copy the data to the output in outplace processing 293 */ 294 if (pInData != pOutData) 295 { 296 /* 297 * Reverb not required so just copy the data 298 */ 299 Copy_Float((LVM_FLOAT *)pInData, /* Source */ 300 (LVM_FLOAT *)pOutData, /* Destination */ 301 (LVM_INT16)(2 * NumSamples)); /* Left and right */ 302 } 303 304 305 /* 306 * Check if the reverb is required 307 */ 308 /* Disable when CS4MS in stereo mode */ 309 if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || \ 310 (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) || 311 (pInstance->Params.SourceFormat != LVCS_STEREO)) && 312 /* For validation testing */ 313 ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0)) 314 { 315 /********************************************************************************/ 316 /* */ 317 /* Copy the input data to scratch memory and filter it */ 318 /* */ 319 /********************************************************************************/ 320 321 /* 322 * Copy the input data to the scratch memory 323 */ 324 Copy_Float((LVM_FLOAT *)pInData, /* Source */ 325 (LVM_FLOAT *)pScratch, /* Destination */ 326 (LVM_INT16)(2 * NumSamples)); /* Left and right */ 327 328 /* 329 * Filter the data 330 */ 331 (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*)&pCoefficients->ReverbBiquadInstance, 332 (LVM_FLOAT *)pScratch, 333 (LVM_FLOAT *)pScratch, 334 (LVM_INT16)NumSamples); 335 336 Mult3s_Float( (LVM_FLOAT *)pScratch, 337 pConfig->ReverbLevel, 338 (LVM_FLOAT *)pScratch, 339 (LVM_INT16)(2 * NumSamples)); 340 341 342 /* 343 * Apply the delay mix 344 */ 345 DelayMix_Float((LVM_FLOAT *)pScratch, 346 &pConfig->StereoSamples[0], 347 pConfig->DelaySize, 348 pOutData, 349 &pConfig->DelayOffset, 350 (LVM_INT16)NumSamples); 351 352 353 } 354 355 return(LVCS_SUCCESS); 356 } 357 #else 358 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance, 359 const LVM_INT16 *pInData, 360 LVM_INT16 *pOutData, 361 LVM_UINT16 NumSamples) 362 { 363 364 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 365 LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation; 366 LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress; 367 LVM_INT16 *pScratch = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress; 368 369 370 /* 371 * Copy the data to the output in outplace processing 372 */ 373 if (pInData != pOutData) 374 { 375 /* 376 * Reverb not required so just copy the data 377 */ 378 Copy_16((LVM_INT16 *)pInData, /* Source */ 379 (LVM_INT16 *)pOutData, /* Destination */ 380 (LVM_INT16)(2*NumSamples)); /* Left and right */ 381 } 382 383 384 /* 385 * Check if the reverb is required 386 */ 387 if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || /* Disable when CS4MS in stereo mode */ 388 (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) || 389 (pInstance->Params.SourceFormat != LVCS_STEREO)) && 390 ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0)) /* For validation testing */ 391 { 392 /********************************************************************************/ 393 /* */ 394 /* Copy the input data to scratch memory and filter it */ 395 /* */ 396 /********************************************************************************/ 397 398 /* 399 * Copy the input data to the scratch memory 400 */ 401 Copy_16((LVM_INT16 *)pInData, /* Source */ 402 (LVM_INT16 *)pScratch, /* Destination */ 403 (LVM_INT16)(2*NumSamples)); /* Left and right */ 404 405 406 /* 407 * Filter the data 408 */ 409 (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->ReverbBiquadInstance, 410 (LVM_INT16 *)pScratch, 411 (LVM_INT16 *)pScratch, 412 (LVM_INT16)NumSamples); 413 414 Mult3s_16x16( (LVM_INT16 *)pScratch, 415 pConfig->ReverbLevel, 416 (LVM_INT16 *)pScratch, 417 (LVM_INT16)(2*NumSamples)); 418 419 420 /* 421 * Apply the delay mix 422 */ 423 DelayMix_16x16((LVM_INT16 *)pScratch, 424 &pConfig->StereoSamples[0], 425 pConfig->DelaySize, 426 pOutData, 427 &pConfig->DelayOffset, 428 (LVM_INT16)NumSamples); 429 430 431 } 432 433 return(LVCS_SUCCESS); 434 } 435 #endif 436