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 /* */ 21 /* Includes */ 22 /* */ 23 /************************************************************************************/ 24 25 #include "LVCS.h" 26 #include "LVCS_Private.h" 27 #include "VectorArithmetic.h" 28 #include "CompLim.h" 29 30 /************************************************************************************/ 31 /* */ 32 /* FUNCTION: LVCS_Process_CS */ 33 /* */ 34 /* DESCRIPTION: */ 35 /* Process function for the Concert Sound module based on the following block */ 36 /* diagram: */ 37 /* _________ ________ _____ _______ ___ ______ */ 38 /* | | | | | | | | | | | | */ 39 /* ----->| Stereo |->| Reverb |->| Equ |->| Alpha |-->| + |-| Gain |----> */ 40 /* | | Enhance | |________| |_____| |_______| |___| |______| */ 41 /* | |_________| | */ 42 /* | ___________ | */ 43 /* | | | | */ 44 /* |------------------------------->| 1 - Alpha |-----| */ 45 /* |___________| */ 46 /* */ 47 /* The Stereo Enhancer, Reverb and Equaliser blocks are each configured to have */ 48 /* their gain to give a near peak to peak output (-0.1dBFS) with a worst case */ 49 /* input signal. The gains of these blocks are re-combined in the Alpha mixer and */ 50 /* the gain block folloing the sum. */ 51 /* */ 52 /* The processing uses the output buffer for data storage after each processing */ 53 /* block. When processing is inplace a copy of the input signal is made in scratch */ 54 /* memory for the 1-Alpha path. */ 55 /* */ 56 /* */ 57 /* PARAMETERS: */ 58 /* hInstance Instance handle */ 59 /* pInData Pointer to the input data */ 60 /* pOutData Pointer to the output data */ 61 /* NumSamples Number of samples in the input buffer */ 62 /* */ 63 /* RETURNS: */ 64 /* LVCS_Success Succeeded */ 65 /* */ 66 /* NOTES: */ 67 /* */ 68 /************************************************************************************/ 69 70 LVCS_ReturnStatus_en LVCS_Process_CS(LVCS_Handle_t hInstance, 71 const LVM_INT16 *pInData, 72 LVM_INT16 *pOutData, 73 LVM_UINT16 NumSamples) 74 { 75 const LVM_INT16 *pInput; 76 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 77 LVM_INT16 *pScratch = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress; 78 LVCS_ReturnStatus_en err; 79 80 /* 81 * Check if the processing is inplace 82 */ 83 if (pInData == pOutData) 84 { 85 /* Processing inplace */ 86 pInput = pScratch + (2*NumSamples); 87 Copy_16((LVM_INT16 *)pInData, /* Source */ 88 (LVM_INT16 *)pInput, /* Destination */ 89 (LVM_INT16)(2*NumSamples)); /* Left and right */ 90 } 91 else 92 { 93 /* Processing outplace */ 94 pInput = pInData; 95 } 96 97 /* 98 * Call the stereo enhancer 99 */ 100 err=LVCS_StereoEnhancer(hInstance, /* Instance handle */ 101 pInData, /* Pointer to the input data */ 102 pOutData, /* Pointer to the output data */ 103 NumSamples); /* Number of samples to process */ 104 105 /* 106 * Call the reverb generator 107 */ 108 err=LVCS_ReverbGenerator(hInstance, /* Instance handle */ 109 pOutData, /* Pointer to the input data */ 110 pOutData, /* Pointer to the output data */ 111 NumSamples); /* Number of samples to process */ 112 113 /* 114 * Call the equaliser 115 */ 116 err=LVCS_Equaliser(hInstance, /* Instance handle */ 117 pOutData, /* Pointer to the input data */ 118 NumSamples); /* Number of samples to process */ 119 120 /* 121 * Call the bypass mixer 122 */ 123 err=LVCS_BypassMixer(hInstance, /* Instance handle */ 124 pOutData, /* Pointer to the processed data */ 125 pInput, /* Pointer to the input (unprocessed) data */ 126 pOutData, /* Pointer to the output data */ 127 NumSamples); /* Number of samples to process */ 128 129 if(err !=LVCS_SUCCESS) 130 { 131 return err; 132 } 133 134 return(LVCS_SUCCESS); 135 } 136 137 /************************************************************************************/ 138 /* */ 139 /* FUNCTION: LVCS_Process */ 140 /* */ 141 /* DESCRIPTION: */ 142 /* Process function for the Concert Sound module. The implementation supports two */ 143 /* variants of the algorithm, one for headphones and one for mobile speakers. */ 144 /* */ 145 /* Data can be processed in two formats, stereo or mono-in-stereo. Data in mono */ 146 /* format is not supported, the calling routine must convert the mono stream to */ 147 /* mono-in-stereo. */ 148 /* */ 149 /* */ 150 /* PARAMETERS: */ 151 /* hInstance Instance handle */ 152 /* pInData Pointer to the input data */ 153 /* pOutData Pointer to the output data */ 154 /* NumSamples Number of samples in the input buffer */ 155 /* */ 156 /* RETURNS: */ 157 /* LVCS_Success Succeeded */ 158 /* LVCS_TooManySamples NumSamples was larger than the maximum block size */ 159 /* */ 160 /* NOTES: */ 161 /* */ 162 /************************************************************************************/ 163 164 LVCS_ReturnStatus_en LVCS_Process(LVCS_Handle_t hInstance, 165 const LVM_INT16 *pInData, 166 LVM_INT16 *pOutData, 167 LVM_UINT16 NumSamples) 168 { 169 170 LVCS_Instance_t *pInstance =(LVCS_Instance_t *)hInstance; 171 LVCS_ReturnStatus_en err; 172 173 /* 174 * Check the number of samples is not too large 175 */ 176 if (NumSamples > pInstance->Capabilities.MaxBlockSize) 177 { 178 return(LVCS_TOOMANYSAMPLES); 179 } 180 181 /* 182 * Check if the algorithm is enabled 183 */ 184 if (pInstance->Params.OperatingMode != LVCS_OFF) 185 { 186 /* 187 * Call CS process function 188 */ 189 err=LVCS_Process_CS(hInstance, 190 pInData, 191 pOutData, 192 NumSamples); 193 194 /* 195 * Compress to reduce expansion effect of Concert Sound and correct volume 196 * differences for difference settings. Not applied in test modes 197 */ 198 if ((pInstance->Params.OperatingMode == LVCS_ON)&&(pInstance->Params.CompressorMode == LVM_MODE_ON)) 199 { 200 LVM_INT16 Gain = pInstance->VolCorrect.CompMin; 201 LVM_INT32 Current1; 202 203 Current1 = LVC_Mixer_GetCurrent(&pInstance->BypassMix.Mixer_Instance.MixerStream[0]); 204 Gain = (LVM_INT16)( pInstance->VolCorrect.CompMin 205 - (((LVM_INT32)pInstance->VolCorrect.CompMin * (Current1)) >> 15) 206 + (((LVM_INT32)pInstance->VolCorrect.CompFull * (Current1)) >> 15) ); 207 208 if(NumSamples < LVCS_COMPGAINFRAME) 209 { 210 NonLinComp_D16(Gain, /* Compressor gain setting */ 211 pOutData, 212 pOutData, 213 (LVM_INT32)(2*NumSamples)); 214 } 215 else 216 { 217 LVM_INT16 GainStep; 218 LVM_INT16 FinalGain; 219 LVM_INT16 SampleToProcess = NumSamples; 220 LVM_INT16 *pOutPtr; 221 222 /* Large changes in Gain can cause clicks in output 223 Split data into small blocks and use interpolated gain values */ 224 225 GainStep = (LVM_INT16)(((Gain-pInstance->CompressGain) * LVCS_COMPGAINFRAME)/NumSamples); 226 227 if((GainStep ==0)&&(pInstance->CompressGain < Gain)) 228 { 229 GainStep=1; 230 } 231 else 232 { 233 if((GainStep ==0)&&(pInstance->CompressGain > Gain)) 234 { 235 GainStep=-1; 236 } 237 } 238 239 FinalGain = Gain; 240 Gain = pInstance->CompressGain; 241 pOutPtr = pOutData; 242 243 while(SampleToProcess > 0) 244 { 245 Gain = (LVM_INT16)(Gain + GainStep); 246 if((GainStep > 0)&& (FinalGain <= Gain)) 247 { 248 Gain = FinalGain; 249 GainStep =0; 250 } 251 252 if((GainStep < 0)&& (FinalGain > Gain)) 253 { 254 Gain = FinalGain; 255 GainStep =0; 256 } 257 258 if(SampleToProcess > LVCS_COMPGAINFRAME) 259 { 260 NonLinComp_D16(Gain, /* Compressor gain setting */ 261 pOutPtr, 262 pOutPtr, 263 (LVM_INT32)(2*LVCS_COMPGAINFRAME)); 264 pOutPtr +=(2*LVCS_COMPGAINFRAME); 265 SampleToProcess = (LVM_INT16)(SampleToProcess-LVCS_COMPGAINFRAME); 266 } 267 else 268 { 269 NonLinComp_D16(Gain, /* Compressor gain setting */ 270 pOutPtr, 271 pOutPtr, 272 (LVM_INT32)(2*SampleToProcess)); 273 274 SampleToProcess = 0; 275 } 276 277 } 278 } 279 280 /* Store gain value*/ 281 pInstance->CompressGain = Gain; 282 } 283 284 285 if(pInstance->bInOperatingModeTransition == LVM_TRUE){ 286 287 /* 288 * Re-init bypass mix when timer has completed 289 */ 290 if ((pInstance->bTimerDone == LVM_TRUE) && 291 (pInstance->BypassMix.Mixer_Instance.MixerStream[1].CallbackSet == 0)) 292 { 293 err=LVCS_BypassMixInit(hInstance, 294 &pInstance->Params); 295 296 if(err != LVCS_SUCCESS) 297 { 298 return err; 299 } 300 301 } 302 else{ 303 LVM_Timer ( &pInstance->TimerInstance, 304 (LVM_INT16)NumSamples); 305 } 306 } 307 } 308 else 309 { 310 if (pInData != pOutData) 311 { 312 /* 313 * The algorithm is disabled so just copy the data 314 */ 315 Copy_16((LVM_INT16 *)pInData, /* Source */ 316 (LVM_INT16 *)pOutData, /* Destination */ 317 (LVM_INT16)(2*NumSamples)); /* Left and right */ 318 } 319 } 320 321 322 return(LVCS_SUCCESS); 323 } 324 325 326 327 328 329 330 331 332 333 334