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 61LVCS_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 152LVCS_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 274LVCS_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 358LVCS_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