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 LVM_UINT32 Gain; 74 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 75 LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix; 76 const Gain_t *pOutputGainTable; 77 LVM_INT32 Current; 78 79 80 /* 81 * Set the transition gain 82 */ 83 if ((pParams->OperatingMode == LVCS_ON) && 84 (pInstance->bTimerDone == LVM_TRUE) 85 && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */ 86 ) 87 { 88 pInstance->TransitionGain = pParams->EffectLevel; 89 } 90 else 91 { 92 /* Select no effect level */ 93 pInstance->TransitionGain = 0; 94 } 95 96 /* 97 * Calculate the output gain table offset 98 */ 99 Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES))); 100 pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0]; 101 102 /* 103 * Setup the mixer gain for the processed path 104 */ 105 Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain); 106 107 pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0; 108 pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL; 109 pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL; 110 pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1; 111 Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]); 112 LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current); 113 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 114 /* 115 * Setup the mixer gain for the unprocessed path 116 */ 117 Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain)); 118 Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15); 119 Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]); 120 LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current); 121 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 122 pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0; 123 pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance; 124 pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1; 125 pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback; 126 127 /* 128 * Setup the output gain shift 129 */ 130 pConfig->Output_Shift = pOutputGainTable[Offset].Shift; 131 132 133 /* 134 * Correct gain for the effect level 135 */ 136 { 137 138 LVM_INT16 GainCorrect; 139 LVM_INT32 Gain1; 140 LVM_INT32 Gain2; 141 142 Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]); 143 Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]); 144 /* 145 * Calculate the gain correction 146 */ 147 if (pInstance->Params.CompressorMode == LVM_MODE_ON) 148 { 149 GainCorrect = (LVM_INT16)( pInstance->VolCorrect.GainMin 150 - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15) 151 + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) ); 152 153 /* 154 * Apply the gain correction and shift, note the result is in Q3.13 format 155 */ 156 Gain1 = (Gain1 * GainCorrect) << 4; 157 Gain2 = (Gain2 * GainCorrect) << 4; 158 } 159 else 160 { 161 Gain1 = Gain1 << 16; 162 Gain2 = Gain2 << 16; 163 } 164 165 166 167 /* 168 * Set the gain values 169 */ 170 pConfig->Output_Shift = pConfig->Output_Shift; 171 LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16); 172 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 173 LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16); 174 LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2); 175 } 176 177 return(LVCS_SUCCESS); 178 179 } 180 181 /************************************************************************************/ 182 /* */ 183 /* FUNCTION: LVCS_BypassMixer */ 184 /* */ 185 /* DESCRIPTION: */ 186 /* Apply Bypass Mix. */ 187 /* */ 188 /* This mixes the processed and unprocessed data streams together to correct the */ 189 /* overall system gain and allow progressive control of the Concert Sound effect. */ 190 /* */ 191 /* When the bypass mixer is enabled the output is the processed signal only and */ 192 /* without gain correction. */ 193 /* */ 194 /* PARAMETERS: */ 195 /* hInstance Instance Handle */ 196 /* pProcessed Pointer to the processed data */ 197 /* pUnprocessed Pointer to the unprocessed data */ 198 /* pOutData Pointer to the output data */ 199 /* NumSamples Number of samples to process */ 200 /* */ 201 /* RETURNS: */ 202 /* LVCS_Success Always succeeds */ 203 /* */ 204 /* NOTES: */ 205 /* */ 206 /************************************************************************************/ 207 208 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance, 209 const LVM_INT16 *pProcessed, 210 const LVM_INT16 *pUnprocessed, 211 LVM_INT16 *pOutData, 212 LVM_UINT16 NumSamples) 213 { 214 215 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 216 LVCS_BypassMix_t *pConfig = (LVCS_BypassMix_t *)&pInstance->BypassMix; 217 218 /* 219 * Check if the bypass mixer is enabled 220 */ 221 if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0) 222 { 223 /* 224 * Apply the bypass mix 225 */ 226 LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance, 227 pProcessed, 228 (LVM_INT16 *) pUnprocessed, 229 pOutData, 230 (LVM_INT16)(2*NumSamples)); 231 232 /* 233 * Apply output gain correction shift 234 */ 235 Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift, 236 (LVM_INT16*)pOutData, 237 (LVM_INT16*)pOutData, 238 (LVM_INT16)(2*NumSamples)); /* Left and right*/ 239 } 240 241 return(LVCS_SUCCESS); 242 } 243 244 245 /************************************************************************************/ 246 /* */ 247 /* FUNCTION: LVCS_MixerCallback */ 248 /* */ 249 /************************************************************************************/ 250 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t hInstance, 251 void *pGeneralPurpose, 252 LVM_INT16 CallbackParam) 253 { 254 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 255 256 (void)pGeneralPurpose; 257 258 /* 259 * Off transition has completed in Headphone mode 260 */ 261 if ((pInstance->OutputDevice == LVCS_HEADPHONE) && 262 (pInstance->bInOperatingModeTransition) && 263 (pInstance->MSTarget0 == 0x0000)&& /* this indicates an on->off transition */ 264 (CallbackParam == 0)) 265 { 266 /* Set operating mode to OFF */ 267 pInstance->Params.OperatingMode = LVCS_OFF; 268 269 /* Exit transition state */ 270 pInstance->bInOperatingModeTransition = LVM_FALSE; 271 272 /* Signal to the bundle */ 273 if((*pInstance->Capabilities.CallBack) != LVM_NULL){ 274 (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance, 275 LVM_NULL, 276 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF)); 277 } 278 } 279 280 281 if ((pInstance->OutputDevice == LVCS_HEADPHONE) && 282 (pInstance->MSTarget0 == 1) && 283 (pInstance->bTimerDone == LVM_TRUE)){ 284 285 /* Exit transition state */ 286 pInstance->bInOperatingModeTransition = LVM_FALSE; 287 } 288 289 return 1; 290 } 291 292 293 294