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 "AGC.h" 25 #include "ScalarArithmetic.h" 26 27 28 /****************************************************************************************/ 29 /* */ 30 /* Defines */ 31 /* */ 32 /****************************************************************************************/ 33 34 #define VOL_TC_SHIFT 21 /* As a power of 2 */ 35 #define DECAY_SHIFT 10 /* As a power of 2 */ 36 37 38 /****************************************************************************************/ 39 /* */ 40 /* FUNCTION: AGC_MIX_VOL_2St1Mon_D32_WRA */ 41 /* */ 42 /* DESCRIPTION: */ 43 /* Apply AGC and mix signals */ 44 /* */ 45 /* */ 46 /* StSrc ------------------| */ 47 /* | */ 48 /* ______ _|_ ________ */ 49 /* | | | | | | */ 50 /* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */ 51 /* | Gain | |___| | Gain | | */ 52 /* |______| |________| | */ 53 /* /|\ __________ ________ | */ 54 /* | | | | | | */ 55 /* |-------------------------------| AGC Gain |<--| Peak |<--| */ 56 /* | Update | | Detect | */ 57 /* |__________| |________| */ 58 /* */ 59 /* */ 60 /* PARAMETERS: */ 61 /* pInstance Instance pointer */ 62 /* pStereoIn Stereo source */ 63 /* pMonoIn Mono band pass source */ 64 /* pStereoOut Stereo destination */ 65 /* */ 66 /* RETURNS: */ 67 /* Void */ 68 /* */ 69 /* NOTES: */ 70 /* */ 71 /****************************************************************************************/ 72 73 void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_D32_t *pInstance, /* Instance pointer */ 74 const LVM_INT32 *pStSrc, /* Stereo source */ 75 const LVM_INT32 *pMonoSrc, /* Mono source */ 76 LVM_INT32 *pDst, /* Stereo destination */ 77 LVM_UINT16 NumSamples) /* Number of samples */ 78 { 79 80 /* 81 * General variables 82 */ 83 LVM_UINT16 i; /* Sample index */ 84 LVM_INT32 Left; /* Left sample */ 85 LVM_INT32 Right; /* Right sample */ 86 LVM_INT32 Mono; /* Mono sample */ 87 LVM_INT32 AbsPeak; /* Absolute peak signal */ 88 LVM_INT32 HighWord; /* High word in intermediate calculations */ 89 LVM_INT32 LowWord; /* Low word in intermediate calculations */ 90 LVM_INT16 AGC_Mult; /* Short AGC gain */ 91 LVM_INT16 Vol_Mult; /* Short volume */ 92 93 94 /* 95 * Instance control variables 96 */ 97 LVM_INT32 AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */ 98 LVM_INT32 AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */ 99 LVM_INT16 AGC_GainShift = pInstance->AGC_GainShift; /* Get the AGC shift */ 100 LVM_INT16 AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */ 101 LVM_INT16 AGC_Decay = pInstance->AGC_Decay; /* Decay scaler */ 102 LVM_INT32 AGC_Target = pInstance->AGC_Target; /* Get the target level */ 103 LVM_INT32 Vol_Current = pInstance->Volume; /* Actual volume setting */ 104 LVM_INT32 Vol_Target = pInstance->Target; /* Target volume setting */ 105 LVM_INT16 Vol_Shift = pInstance->VolumeShift; /* Volume shift scaling */ 106 LVM_INT16 Vol_TC = pInstance->VolumeTC; /* Time constant */ 107 108 109 /* 110 * Process on a sample by sample basis 111 */ 112 for (i=0;i<NumSamples;i++) /* For each sample */ 113 { 114 115 /* 116 * Get the short scalers 117 */ 118 AGC_Mult = (LVM_INT16)(AGC_Gain >> 16); /* Get the short AGC gain */ 119 Vol_Mult = (LVM_INT16)(Vol_Current >> 16); /* Get the short volume gain */ 120 121 122 /* 123 * Get the input samples 124 */ 125 Left = *pStSrc++; /* Get the left sample */ 126 Right = *pStSrc++; /* Get the right sample */ 127 Mono = *pMonoSrc++; /* Get the mono sample */ 128 129 130 /* 131 * Apply the AGC gain to the mono input and mix with the stereo signal 132 */ 133 HighWord = (AGC_Mult * (Mono >> 16)); /* signed long (Mono) by unsigned short (AGC_Mult) multiply */ 134 LowWord = (AGC_Mult * (Mono & 0xffff)); 135 Mono = (HighWord + (LowWord >> 16)) << (AGC_GainShift); 136 Left += Mono; /* Mix in the mono signal */ 137 Right += Mono; 138 139 140 /* 141 * Apply the volume and write to the output stream 142 */ 143 HighWord = (Vol_Mult * (Left >> 16)); /* signed long (Left) by unsigned short (Vol_Mult) multiply */ 144 LowWord = (Vol_Mult * (Left & 0xffff)); 145 Left = (HighWord + (LowWord >> 16)) << (Vol_Shift); 146 HighWord = (Vol_Mult * (Right >> 16)); /* signed long (Right) by unsigned short (Vol_Mult) multiply */ 147 LowWord = (Vol_Mult * (Right & 0xffff)); 148 Right = (HighWord + (LowWord >> 16)) << (Vol_Shift); 149 *pDst++ = Left; /* Save the results */ 150 *pDst++ = Right; 151 152 153 /* 154 * Update the AGC gain 155 */ 156 AbsPeak = (Abs_32(Left)>Abs_32(Right)) ? Abs_32(Left) : Abs_32(Right); /* Get the absolute peak */ 157 if (AbsPeak > AGC_Target) 158 { 159 /* 160 * The signal is too large so decrease the gain 161 */ 162 HighWord = (AGC_Attack * (AGC_Gain >> 16)); /* signed long (AGC_Gain) by unsigned short (AGC_Attack) multiply */ 163 LowWord = (AGC_Attack * (AGC_Gain & 0xffff)); 164 AGC_Gain = (HighWord + (LowWord >> 16)) << 1; 165 } 166 else 167 { 168 /* 169 * The signal is too small so increase the gain 170 */ 171 if (AGC_Gain > AGC_MaxGain) 172 { 173 AGC_Gain -= (AGC_Decay << DECAY_SHIFT); 174 } 175 else 176 { 177 AGC_Gain += (AGC_Decay << DECAY_SHIFT); 178 } 179 } 180 181 /* 182 * Update the gain 183 */ 184 Vol_Current += Vol_TC * ((Vol_Target - Vol_Current) >> VOL_TC_SHIFT); 185 } 186 187 188 /* 189 * Update the parameters 190 */ 191 pInstance->Volume = Vol_Current; /* Actual volume setting */ 192 pInstance->AGC_Gain = AGC_Gain; 193 194 return; 195 } 196 197