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_BypassMix.h" 27 #include "VectorArithmetic.h" 28 #include "LVCS_Tables.h" 29 30 /****************************************************************************************/ 31 /* */ 32 /* Function Prototypes */ 33 /* */ 34 /****************************************************************************************/ 35 LVM_INT32 LVCS_MixerCallback( LVCS_Handle_t hInstance, 36 void *pGeneralPurpose, 37 LVM_INT16 CallbackParam); 38 39 /************************************************************************************/ 40 /* */ 41 /* FUNCTION: LVCS_BypassMixInit */ 42 /* */ 43 /* DESCRIPTION: */ 44 /* Initialises the bypass mixer module */ 45 /* */ 46 /* The overall gain of the processed path is set by the gains in the individual */ 47 /* processing blocks and by the effect level gain. */ 48 /* */ 49 /* The unprocessed path must have matching gain for the processed path to ensure */ 50 /* as they are mixed together the correct effect is achieved, this is the value */ 51 /* UnprocLoss. */ 52 /* */ 53 /* The overall gain is corrected by a combination of a shift with saturation and a */ 54 /* linear scaler, loss. The loss ensures the sum in the mixer does not saturate */ 55 /* and also corrects for any excess gain in the shift. */ 56 /* */ 57 /* PARAMETERS: */ 58 /* hInstance Instance Handle */ 59 /* pParams Initialisation parameters */ 60 /* */ 61 /* RETURNS: */ 62 /* LVCS_Success Always succeeds */ 63 /* */ 64 /* NOTES: */ 65 /* */ 66 /************************************************************************************/ 67 68 LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t hInstance, 69 LVCS_Params_t *pParams) 70 { 71 72 LVM_UINT16 Offset; 73 #ifndef BUILD_FLOAT 74 LVM_UINT32 Gain; 75 LVM_INT32 Current; 76 #else 77 LVM_FLOAT Gain; 78 LVM_FLOAT Current; 79 #endif 80 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 81 LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix; 82 const Gain_t *pOutputGainTable; 83 84 85 86 /* 87 * Set the transition gain 88 */ 89 if ((pParams->OperatingMode == LVCS_ON) && 90 (pInstance->bTimerDone == LVM_TRUE) 91 && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */ 92 ) 93 { 94 #ifndef BUILD_FLOAT 95 pInstance->TransitionGain = pParams->EffectLevel; 96 #else 97 pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767); 98 #endif 99 } 100 else 101 { 102 /* Select no effect level */ 103 pInstance->TransitionGain = 0; 104 } 105 106 /* 107 * Calculate the output gain table offset 108 */ 109 Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES))); 110 pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0]; 111 112 /* 113 * Setup the mixer gain for the processed path 114 */ 115 #ifndef BUILD_FLOAT 116 Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain); 117 #else 118 Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain); 119 #endif 120 121 pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0; 122 pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL; 123 pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL; 124 pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1; 125 126 #ifndef BUILD_FLOAT 127 Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]); 128 LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current); 129 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 130 #else 131 Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]); 132 LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current); 133 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0], 134 LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2); 135 #endif 136 137 /* 138 * Setup the mixer gain for the unprocessed path 139 */ 140 #ifndef BUILD_FLOAT 141 Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain)); 142 Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15); 143 Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]); 144 LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current); 145 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 146 #else 147 Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * (1.0 - \ 148 (LVM_FLOAT)pInstance->TransitionGain)); 149 Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain; 150 Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]); 151 LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current); 152 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1], 153 LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2); 154 #endif 155 pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0; 156 pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance; 157 pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1; 158 pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback; 159 160 /* 161 * Setup the output gain shift 162 */ 163 pConfig->Output_Shift = pOutputGainTable[Offset].Shift; 164 165 166 /* 167 * Correct gain for the effect level 168 */ 169 { 170 #ifndef BUILD_FLOAT 171 LVM_INT16 GainCorrect; 172 LVM_INT32 Gain1; 173 LVM_INT32 Gain2; 174 175 Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]); 176 Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]); 177 /* 178 * Calculate the gain correction 179 */ 180 if (pInstance->Params.CompressorMode == LVM_MODE_ON) 181 { 182 GainCorrect = (LVM_INT16)( pInstance->VolCorrect.GainMin 183 - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15) 184 + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) ); 185 186 /* 187 * Apply the gain correction and shift, note the result is in Q3.13 format 188 */ 189 Gain1 = (Gain1 * GainCorrect) << 4; 190 Gain2 = (Gain2 * GainCorrect) << 4; 191 } 192 else 193 { 194 Gain1 = Gain1 << 16; 195 Gain2 = Gain2 << 16; 196 } 197 198 199 200 /* 201 * Set the gain values 202 */ 203 pConfig->Output_Shift = pConfig->Output_Shift; 204 LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16); 205 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 206 LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16); 207 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 208 #else 209 LVM_FLOAT GainCorrect; 210 LVM_FLOAT Gain1; 211 LVM_FLOAT Gain2; 212 213 Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]); 214 Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]); 215 /* 216 * Calculate the gain correction 217 */ 218 if (pInstance->Params.CompressorMode == LVM_MODE_ON) 219 { 220 GainCorrect = (LVM_FLOAT)( pInstance->VolCorrect.GainMin 221 - (((LVM_FLOAT)pInstance->VolCorrect.GainMin * \ 222 ((LVM_FLOAT)pInstance->TransitionGain))) 223 + (((LVM_FLOAT)pInstance->VolCorrect.GainFull * \ 224 ((LVM_FLOAT)pInstance->TransitionGain)))); 225 226 /* 227 * Apply the gain correction 228 */ 229 Gain1 = (Gain1 * GainCorrect); 230 Gain2 = (Gain2 * GainCorrect); 231 232 } 233 234 /* 235 * Set the gain values 236 */ 237 pConfig->Output_Shift = pConfig->Output_Shift; 238 LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1); 239 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0], 240 LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2); 241 LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2); 242 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1], 243 LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2); 244 #endif 245 } 246 247 return(LVCS_SUCCESS); 248 249 } 250 251 /************************************************************************************/ 252 /* */ 253 /* FUNCTION: LVCS_BypassMixer */ 254 /* */ 255 /* DESCRIPTION: */ 256 /* Apply Bypass Mix. */ 257 /* */ 258 /* This mixes the processed and unprocessed data streams together to correct the */ 259 /* overall system gain and allow progressive control of the Concert Sound effect. */ 260 /* */ 261 /* When the bypass mixer is enabled the output is the processed signal only and */ 262 /* without gain correction. */ 263 /* */ 264 /* PARAMETERS: */ 265 /* hInstance Instance Handle */ 266 /* pProcessed Pointer to the processed data */ 267 /* pUnprocessed Pointer to the unprocessed data */ 268 /* pOutData Pointer to the output data */ 269 /* NumSamples Number of samples to process */ 270 /* */ 271 /* RETURNS: */ 272 /* LVCS_Success Always succeeds */ 273 /* */ 274 /* NOTES: */ 275 /* */ 276 /************************************************************************************/ 277 278 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance, 279 #ifndef BUILD_FLOAT 280 const LVM_INT16 *pProcessed, 281 const LVM_INT16 *pUnprocessed, 282 LVM_INT16 *pOutData, 283 #else 284 const LVM_FLOAT *pProcessed, 285 const LVM_FLOAT *pUnprocessed, 286 LVM_FLOAT *pOutData, 287 #endif 288 LVM_UINT16 NumSamples) 289 { 290 291 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 292 LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix; 293 294 /* 295 * Check if the bypass mixer is enabled 296 */ 297 if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0) 298 { 299 /* 300 * Apply the bypass mix 301 */ 302 #ifndef BUILD_FLOAT 303 LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance, 304 pProcessed, 305 (LVM_INT16 *) pUnprocessed, 306 pOutData, 307 (LVM_INT16)(2*NumSamples)); 308 309 /* 310 * Apply output gain correction shift 311 */ 312 Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift, 313 (LVM_INT16*)pOutData, 314 (LVM_INT16*)pOutData, 315 (LVM_INT16)(2*NumSamples)); /* Left and right*/ 316 #else 317 LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance, 318 pProcessed, 319 (LVM_FLOAT *) pUnprocessed, 320 pOutData, 321 (LVM_INT16)(2 * NumSamples)); 322 /* 323 * Apply output gain correction shift 324 */ 325 Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift, 326 (LVM_FLOAT*)pOutData, 327 (LVM_FLOAT*)pOutData, 328 (LVM_INT16)(2 * NumSamples)); /* Left and right*/ 329 #endif 330 } 331 332 return(LVCS_SUCCESS); 333 } 334 335 336 /************************************************************************************/ 337 /* */ 338 /* FUNCTION: LVCS_MixerCallback */ 339 /* */ 340 /************************************************************************************/ 341 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t hInstance, 342 void *pGeneralPurpose, 343 LVM_INT16 CallbackParam) 344 { 345 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 346 347 (void)pGeneralPurpose; 348 349 /* 350 * Off transition has completed in Headphone mode 351 */ 352 if ((pInstance->OutputDevice == LVCS_HEADPHONE) && 353 (pInstance->bInOperatingModeTransition) && 354 (pInstance->MSTarget0 == 0x0000)&& /* this indicates an on->off transition */ 355 (CallbackParam == 0)) 356 { 357 /* Set operating mode to OFF */ 358 pInstance->Params.OperatingMode = LVCS_OFF; 359 360 /* Exit transition state */ 361 pInstance->bInOperatingModeTransition = LVM_FALSE; 362 363 /* Signal to the bundle */ 364 if((*pInstance->Capabilities.CallBack) != LVM_NULL){ 365 (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance, 366 LVM_NULL, 367 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF)); 368 } 369 } 370 371 372 if ((pInstance->OutputDevice == LVCS_HEADPHONE) && 373 (pInstance->MSTarget0 == 1) && 374 (pInstance->bTimerDone == LVM_TRUE)){ 375 376 /* Exit transition state */ 377 pInstance->bInOperatingModeTransition = LVM_FALSE; 378 } 379 380 return 1; 381 } 382 383 384 385