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