LVCS_ReverbGenerator.c revision 2c8e5cab3faa6d360e222b7a6c40a80083d021ac
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: beq07716 $ 21 $Revision: 1001 $ 22 $Date: 2010-06-28 13:23:02 +0200 (Mon, 28 Jun 2010) $ 23 24*************************************************************************************/ 25 26/************************************************************************************/ 27/* */ 28/* Includes */ 29/* */ 30/************************************************************************************/ 31 32#include "LVCS.h" 33#include "LVCS_Private.h" 34#include "LVCS_ReverbGenerator.h" 35#include "LVC_Mixer.h" 36#include "VectorArithmetic.h" 37#include "BIQUAD.h" 38#include "LVCS_Tables.h" 39 40/************************************************************************************/ 41/* */ 42/* FUNCTION: LVCS_ReverbGeneratorInit */ 43/* */ 44/* DESCRIPTION: */ 45/* Initialises the reverb module. The delay buffer size is configured for the */ 46/* sample rate and the speaker type. */ 47/* */ 48/* The routine may also be called for re-initialisation, i.e. when one of the */ 49/* control parameters has changed. In this case the delay and filters are only */ 50/* re-initialised if one of the following two conditions is met: */ 51/* - the sample rate has changed */ 52/* - the speaker type changes to/from the mobile speaker */ 53/* */ 54/* */ 55/* PARAMETERS: */ 56/* hInstance Instance Handle */ 57/* pParams Pointer to the inialisation parameters */ 58/* */ 59/* RETURNS: */ 60/* LVCS_Success Always succeeds */ 61/* */ 62/* NOTES: */ 63/* 1. In the delay settings 'Samples' is the number of samples to the end of the */ 64/* buffer. */ 65/* 2. The numerator coefficients of the filter are negated to cause an inversion. */ 66/* */ 67/************************************************************************************/ 68 69LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance, 70 LVCS_Params_t *pParams) 71{ 72 73 LVM_UINT16 Delay; 74 LVM_UINT16 Offset; 75 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 76 LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation; 77 LVCS_Data_t *pData = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress; 78 LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress; 79 BQ_C16_Coefs_t Coeffs; 80 const BiquadA012B12CoefsSP_t *pReverbCoefTable; 81 82 /* 83 * Initialise the delay and filters if: 84 * - the sample rate has changed 85 * - the speaker type has changed to or from the mobile speaker 86 */ 87 if(pInstance->Params.SampleRate != pParams->SampleRate ) /* Sample rate change test */ 88 89 { 90 /* 91 * Setup the delay 92 */ 93 Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate]; 94 95 96 pConfig->DelaySize = (LVM_INT16)(2 * Delay); 97 pConfig->DelayOffset = 0; 98 LoadConst_16(0, /* Value */ 99 (LVM_INT16 *)&pConfig->StereoSamples[0], /* Destination */ 100 (LVM_UINT16)(sizeof(pConfig->StereoSamples)/sizeof(LVM_INT16))); /* Number of words */ 101 102 /* 103 * Setup the filters 104 */ 105 Offset = (LVM_UINT16)pParams->SampleRate; 106 pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0]; 107 108 /* Convert incoming coefficients to the required format/ordering */ 109 Coeffs.A0 = (LVM_INT16)pReverbCoefTable[Offset].A0; 110 Coeffs.A1 = (LVM_INT16)pReverbCoefTable[Offset].A1; 111 Coeffs.A2 = (LVM_INT16)pReverbCoefTable[Offset].A2; 112 Coeffs.B1 = (LVM_INT16)-pReverbCoefTable[Offset].B1; 113 Coeffs.B2 = (LVM_INT16)-pReverbCoefTable[Offset].B2; 114 115 LoadConst_16(0, /* Value */ 116 (LVM_INT16 *)&pData->ReverbBiquadTaps, /* Destination */ 117 (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps)/sizeof(LVM_INT16))); /* Number of words */ 118 119 BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance, 120 &pData->ReverbBiquadTaps, 121 &Coeffs); 122 123 /* Callbacks */ 124 switch(pReverbCoefTable[Offset].Scale) 125 { 126 case 14: 127 pConfig->pBiquadCallBack = BQ_2I_D16F16C14_TRC_WRA_01; 128 break; 129 case 15: 130 pConfig->pBiquadCallBack = BQ_2I_D16F16C15_TRC_WRA_01; 131 break; 132 } 133 134 135 /* 136 * Setup the mixer 137 */ 138 pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC); 139 pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC); 140 } 141 142 if(pInstance->Params.ReverbLevel != pParams->ReverbLevel) 143 { 144 LVM_INT32 ReverbPercentage=83886; // 1 Percent Reverb i.e 1/100 in Q 23 format 145 ReverbPercentage*=pParams->ReverbLevel; // Actual Reverb Level in Q 23 format 146 pConfig->ReverbLevel=(LVM_INT16)(ReverbPercentage>>8); // Reverb Level in Q 15 format 147 } 148 149 return(LVCS_SUCCESS); 150} 151 152/************************************************************************************/ 153/* */ 154/* FUNCTION: LVCS_Reverb */ 155/* */ 156/* DESCRIPTION: */ 157/* Create reverb using the block of input samples based on the following block */ 158/* diagram: */ 159/* ________ ________ */ 160/* | | | | */ 161/* _____ _______ | |----------->| | ______ ___ */ 162/* | | | | | Stereo | | L & R | | | | | */ 163/* -->| LPF |-->| Delay |-->| to | ____ | to |-->| Gain |-->| + |--> */ 164/* | |_____| |_______| | L & R | | | | Stereo | |______| |___| */ 165/* | | |-->| -1 |-->| | | */ 166/* | |________| |____| |________| | */ 167/* | | */ 168/* |-----------------------------------------------------------------------| */ 169/* */ 170/* The input buffer is broken in to sub-blocks of the size of the delay or less. */ 171/* This allows the delay buffer to be treated as a circular buffer but processed */ 172/* as a linear buffer. */ 173/* */ 174/* */ 175/* PARAMETERS: */ 176/* hInstance Instance Handle */ 177/* pInData Pointer to the input buffer */ 178/* pOutData Pointer to the output buffer */ 179/* NumSamples Number of samples to process */ 180/* */ 181/* RETURNS: */ 182/* LVCS_Success Always succeeds */ 183/* */ 184/* NOTES: */ 185/* 1. Process in blocks of samples the size of the delay where possible, if not */ 186/* the number of samples left over */ 187/* 2. The Gain is combined with the LPF and incorporated in to the coefficients */ 188/* */ 189/************************************************************************************/ 190 191LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance, 192 const LVM_INT16 *pInData, 193 LVM_INT16 *pOutData, 194 LVM_UINT16 NumSamples) 195{ 196 197 LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance; 198 LVCS_ReverbGenerator_t *pConfig = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation; 199 LVCS_Coefficient_t *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress; 200 LVM_INT16 *pScratch = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress; 201 202 203 /* 204 * Copy the data to the output in outplace processing 205 */ 206 if (pInData != pOutData) 207 { 208 /* 209 * Reverb not required so just copy the data 210 */ 211 Copy_16((LVM_INT16 *)pInData, /* Source */ 212 (LVM_INT16 *)pOutData, /* Destination */ 213 (LVM_INT16)(2*NumSamples)); /* Left and right */ 214 } 215 216 217 /* 218 * Check if the reverb is required 219 */ 220 if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || /* Disable when CS4MS in stereo mode */ 221 (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) || 222 (pInstance->Params.SourceFormat != LVCS_STEREO)) && 223 ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0)) /* For validation testing */ 224 { 225 /********************************************************************************/ 226 /* */ 227 /* Copy the input data to scratch memory and filter it */ 228 /* */ 229 /********************************************************************************/ 230 231 /* 232 * Copy the input data to the scratch memory 233 */ 234 Copy_16((LVM_INT16 *)pInData, /* Source */ 235 (LVM_INT16 *)pScratch, /* Destination */ 236 (LVM_INT16)(2*NumSamples)); /* Left and right */ 237 238 239 /* 240 * Filter the data 241 */ 242 (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->ReverbBiquadInstance, 243 (LVM_INT16 *)pScratch, 244 (LVM_INT16 *)pScratch, 245 (LVM_INT16)NumSamples); 246 247 Mult3s_16x16( (LVM_INT16 *)pScratch, 248 pConfig->ReverbLevel, 249 (LVM_INT16 *)pScratch, 250 (LVM_INT16)(2*NumSamples)); 251 252 253 /* 254 * Apply the delay mix 255 */ 256 DelayMix_16x16((LVM_INT16 *)pScratch, 257 &pConfig->StereoSamples[0], 258 pConfig->DelaySize, 259 pOutData, 260 &pConfig->DelayOffset, 261 (LVM_INT16)NumSamples); 262 263 264 } 265 266 return(LVCS_SUCCESS); 267} 268 269 270 271 272 273