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 70LVCS_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 164LVCS_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