OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 /* digital_agc.c | 11 /* digital_agc.c |
12 * | 12 * |
13 */ | 13 */ |
14 | 14 |
15 #include "webrtc/modules/audio_processing/agc/legacy/digital_agc.h" | 15 #include "webrtc/modules/audio_processing/agc/legacy/digital_agc.h" |
16 | 16 |
17 #include <assert.h> | 17 #include <assert.h> |
18 #include <string.h> | 18 #include <string.h> |
19 #ifdef WEBRTC_AGC_DEBUG_DUMP | 19 #ifdef WEBRTC_AGC_DEBUG_DUMP |
20 #include <stdio.h> | 20 #include <stdio.h> |
21 #endif | 21 #endif |
22 | 22 |
23 #include "webrtc/modules/audio_processing/agc/legacy/gain_control.h" | 23 #include "webrtc/modules/audio_processing/agc/legacy/gain_control.h" |
24 | 24 |
25 // To generate the gaintable, copy&paste the following lines to a Matlab window: | 25 // To generate the gaintable, copy&paste the following lines to a Matlab window: |
26 // MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1; | 26 // MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1; |
27 // zeros = 0:31; lvl = 2.^(1-zeros); | 27 // zeros = 0:31; lvl = 2.^(1-zeros); |
28 // A = -10*log10(lvl) * (CompRatio - 1) / CompRatio; | 28 // A = -10*log10(lvl) * (CompRatio - 1) / CompRatio; |
29 // B = MaxGain - MinGain; | 29 // B = MaxGain - MinGain; |
30 // gains = round(2^16*10.^(0.05 * (MinGain + B * ( log(exp(-Knee*A)+exp(-Knee*B)
) - log(1+exp(-Knee*B)) ) / log(1/(1+exp(Knee*B)))))); | 30 // gains = round(2^16*10.^(0.05 * (MinGain + B * ( |
| 31 // log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) / |
| 32 // log(1/(1+exp(Knee*B)))))); |
31 // fprintf(1, '\t%i, %i, %i, %i,\n', gains); | 33 // fprintf(1, '\t%i, %i, %i, %i,\n', gains); |
32 // % Matlab code for plotting the gain and input/output level characteristic (co
py/paste the following 3 lines): | 34 // % Matlab code for plotting the gain and input/output level characteristic |
| 35 // (copy/paste the following 3 lines): |
33 // in = 10*log10(lvl); out = 20*log10(gains/65536); | 36 // in = 10*log10(lvl); out = 20*log10(gains/65536); |
34 // subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input (
dB)'); ylabel('Gain (dB)'); | 37 // subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input |
35 // subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on; xlabel('Inpu
t (dB)'); ylabel('Output (dB)'); | 38 // (dB)'); ylabel('Gain (dB)'); |
| 39 // subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on; |
| 40 // xlabel('Input (dB)'); ylabel('Output (dB)'); |
36 // zoom on; | 41 // zoom on; |
37 | 42 |
38 // Generator table for y=log2(1+e^x) in Q8. | 43 // Generator table for y=log2(1+e^x) in Q8. |
39 enum { kGenFuncTableSize = 128 }; | 44 enum { kGenFuncTableSize = 128 }; |
40 static const uint16_t kGenFuncTable[kGenFuncTableSize] = { | 45 static const uint16_t kGenFuncTable[kGenFuncTableSize] = { |
41 256, 485, 786, 1126, 1484, 1849, 2217, 2586, | 46 256, 485, 786, 1126, 1484, 1849, 2217, 2586, 2955, 3324, 3693, |
42 2955, 3324, 3693, 4063, 4432, 4801, 5171, 5540, | 47 4063, 4432, 4801, 5171, 5540, 5909, 6279, 6648, 7017, 7387, 7756, |
43 5909, 6279, 6648, 7017, 7387, 7756, 8125, 8495, | 48 8125, 8495, 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449, 11819, |
44 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449, | 49 12188, 12557, 12927, 13296, 13665, 14035, 14404, 14773, 15143, 15512, 15881, |
45 11819, 12188, 12557, 12927, 13296, 13665, 14035, 14404, | 50 16251, 16620, 16989, 17359, 17728, 18097, 18466, 18836, 19205, 19574, 19944, |
46 14773, 15143, 15512, 15881, 16251, 16620, 16989, 17359, | 51 20313, 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268, 23637, 24006, |
47 17728, 18097, 18466, 18836, 19205, 19574, 19944, 20313, | 52 24376, 24745, 25114, 25484, 25853, 26222, 26592, 26961, 27330, 27700, 28069, |
48 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268, | 53 28438, 28808, 29177, 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132, |
49 23637, 24006, 24376, 24745, 25114, 25484, 25853, 26222, | 54 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086, 35456, 35825, 36194, |
50 26592, 26961, 27330, 27700, 28069, 28438, 28808, 29177, | 55 36564, 36933, 37302, 37672, 38041, 38410, 38780, 39149, 39518, 39888, 40257, |
51 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132, | 56 40626, 40996, 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950, 44320, |
52 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086, | 57 44689, 45058, 45428, 45797, 46166, 46536, 46905}; |
53 35456, 35825, 36194, 36564, 36933, 37302, 37672, 38041, | 58 |
54 38410, 38780, 39149, 39518, 39888, 40257, 40626, 40996, | 59 static const int16_t kAvgDecayTime = 250; // frames; < 3000 |
55 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950, | 60 |
56 44320, 44689, 45058, 45428, 45797, 46166, 46536, 46905 | 61 int32_t WebRtcAgc_CalculateGainTable(int32_t* gainTable, // Q16 |
57 }; | 62 int16_t digCompGaindB, // Q0 |
58 | 63 int16_t targetLevelDbfs, // Q0 |
59 static const int16_t kAvgDecayTime = 250; // frames; < 3000 | |
60 | |
61 int32_t WebRtcAgc_CalculateGainTable(int32_t *gainTable, // Q16 | |
62 int16_t digCompGaindB, // Q0 | |
63 int16_t targetLevelDbfs,// Q0 | |
64 uint8_t limiterEnable, | 64 uint8_t limiterEnable, |
65 int16_t analogTarget) // Q0 | 65 int16_t analogTarget) // Q0 |
66 { | 66 { |
67 // This function generates the compressor gain table used in the fixed digit
al part. | 67 // This function generates the compressor gain table used in the fixed digital |
68 uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox; | 68 // part. |
69 int32_t inLevel, limiterLvl; | 69 uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox; |
70 int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32; | 70 int32_t inLevel, limiterLvl; |
71 const uint16_t kLog10 = 54426; // log2(10) in Q14 | 71 int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32; |
72 const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14 | 72 const uint16_t kLog10 = 54426; // log2(10) in Q14 |
73 const uint16_t kLogE_1 = 23637; // log2(e) in Q14 | 73 const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14 |
74 uint16_t constMaxGain; | 74 const uint16_t kLogE_1 = 23637; // log2(e) in Q14 |
75 uint16_t tmpU16, intPart, fracPart; | 75 uint16_t constMaxGain; |
76 const int16_t kCompRatio = 3; | 76 uint16_t tmpU16, intPart, fracPart; |
77 const int16_t kSoftLimiterLeft = 1; | 77 const int16_t kCompRatio = 3; |
78 int16_t limiterOffset = 0; // Limiter offset | 78 const int16_t kSoftLimiterLeft = 1; |
79 int16_t limiterIdx, limiterLvlX; | 79 int16_t limiterOffset = 0; // Limiter offset |
80 int16_t constLinApprox, zeroGainLvl, maxGain, diffGain; | 80 int16_t limiterIdx, limiterLvlX; |
81 int16_t i, tmp16, tmp16no1; | 81 int16_t constLinApprox, zeroGainLvl, maxGain, diffGain; |
82 int zeros, zerosScale; | 82 int16_t i, tmp16, tmp16no1; |
83 | 83 int zeros, zerosScale; |
84 // Constants | 84 |
85 // kLogE_1 = 23637; // log2(e) in Q14 | 85 // Constants |
86 // kLog10 = 54426; // log2(10) in Q14 | 86 // kLogE_1 = 23637; // log2(e) in Q14 |
87 // kLog10_2 = 49321; // 10*log10(2) in Q14 | 87 // kLog10 = 54426; // log2(10) in Q14 |
88 | 88 // kLog10_2 = 49321; // 10*log10(2) in Q14 |
89 // Calculate maximum digital gain and zero gain level | 89 |
90 tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1); | 90 // Calculate maximum digital gain and zero gain level |
91 tmp16no1 = analogTarget - targetLevelDbfs; | 91 tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1); |
92 tmp16no1 += WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRat
io); | 92 tmp16no1 = analogTarget - targetLevelDbfs; |
93 maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs)); | 93 tmp16no1 += |
94 tmp32no1 = maxGain * kCompRatio; | 94 WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio); |
95 zeroGainLvl = digCompGaindB; | 95 maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs)); |
96 zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1), | 96 tmp32no1 = maxGain * kCompRatio; |
97 kCompRatio - 1); | 97 zeroGainLvl = digCompGaindB; |
98 if ((digCompGaindB <= analogTarget) && (limiterEnable)) | 98 zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1), |
| 99 kCompRatio - 1); |
| 100 if ((digCompGaindB <= analogTarget) && (limiterEnable)) { |
| 101 zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft); |
| 102 limiterOffset = 0; |
| 103 } |
| 104 |
| 105 // Calculate the difference between maximum gain and gain at 0dB0v: |
| 106 // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio |
| 107 // = (compRatio-1)*digCompGaindB/compRatio |
| 108 tmp32no1 = digCompGaindB * (kCompRatio - 1); |
| 109 diffGain = |
| 110 WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio); |
| 111 if (diffGain < 0 || diffGain >= kGenFuncTableSize) { |
| 112 assert(0); |
| 113 return -1; |
| 114 } |
| 115 |
| 116 // Calculate the limiter level and index: |
| 117 // limiterLvlX = analogTarget - limiterOffset |
| 118 // limiterLvl = targetLevelDbfs + limiterOffset/compRatio |
| 119 limiterLvlX = analogTarget - limiterOffset; |
| 120 limiterIdx = 2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX * (1 << 13), |
| 121 kLog10_2 / 2); |
| 122 tmp16no1 = |
| 123 WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio); |
| 124 limiterLvl = targetLevelDbfs + tmp16no1; |
| 125 |
| 126 // Calculate (through table lookup): |
| 127 // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8) |
| 128 constMaxGain = kGenFuncTable[diffGain]; // in Q8 |
| 129 |
| 130 // Calculate a parameter used to approximate the fractional part of 2^x with a |
| 131 // piecewise linear function in Q14: |
| 132 // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14); |
| 133 constLinApprox = 22817; // in Q14 |
| 134 |
| 135 // Calculate a denominator used in the exponential part to convert from dB to |
| 136 // linear scale: |
| 137 // den = 20*constMaxGain (in Q8) |
| 138 den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8 |
| 139 |
| 140 for (i = 0; i < 32; i++) { |
| 141 // Calculate scaled input level (compressor): |
| 142 // inLevel = |
| 143 // fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio) |
| 144 tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0 |
| 145 tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14 |
| 146 inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14 |
| 147 |
| 148 // Calculate diffGain-inLevel, to map using the genFuncTable |
| 149 inLevel = (int32_t)diffGain * (1 << 14) - inLevel; // Q14 |
| 150 |
| 151 // Make calculations on abs(inLevel) and compensate for the sign afterwards. |
| 152 absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14 |
| 153 |
| 154 // LUT with interpolation |
| 155 intPart = (uint16_t)(absInLevel >> 14); |
| 156 fracPart = |
| 157 (uint16_t)(absInLevel & 0x00003FFF); // extract the fractional part |
| 158 tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8 |
| 159 tmpU32no1 = tmpU16 * fracPart; // Q22 |
| 160 tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22 |
| 161 logApprox = tmpU32no1 >> 8; // Q14 |
| 162 // Compensate for negative exponent using the relation: |
| 163 // log2(1 + 2^-x) = log2(1 + 2^x) - x |
| 164 if (inLevel < 0) { |
| 165 zeros = WebRtcSpl_NormU32(absInLevel); |
| 166 zerosScale = 0; |
| 167 if (zeros < 15) { |
| 168 // Not enough space for multiplication |
| 169 tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1) |
| 170 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13) |
| 171 if (zeros < 9) { |
| 172 zerosScale = 9 - zeros; |
| 173 tmpU32no1 >>= zerosScale; // Q(zeros+13) |
| 174 } else { |
| 175 tmpU32no2 >>= zeros - 9; // Q22 |
| 176 } |
| 177 } else { |
| 178 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28 |
| 179 tmpU32no2 >>= 6; // Q22 |
| 180 } |
| 181 logApprox = 0; |
| 182 if (tmpU32no2 < tmpU32no1) { |
| 183 logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); // Q14 |
| 184 } |
| 185 } |
| 186 numFIX = (maxGain * constMaxGain) * (1 << 6); // Q14 |
| 187 numFIX -= (int32_t)logApprox * diffGain; // Q14 |
| 188 |
| 189 // Calculate ratio |
| 190 // Shift |numFIX| as much as possible. |
| 191 // Ensure we avoid wrap-around in |den| as well. |
| 192 if (numFIX > (den >> 8)) // |den| is Q8. |
99 { | 193 { |
100 zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft); | 194 zeros = WebRtcSpl_NormW32(numFIX); |
101 limiterOffset = 0; | 195 } else { |
102 } | 196 zeros = WebRtcSpl_NormW32(den) + 8; |
103 | 197 } |
104 // Calculate the difference between maximum gain and gain at 0dB0v: | 198 numFIX *= 1 << zeros; // Q(14+zeros) |
105 // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio | 199 |
106 // = (compRatio-1)*digCompGaindB/compRatio | 200 // Shift den so we end up in Qy1 |
107 tmp32no1 = digCompGaindB * (kCompRatio - 1); | 201 tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 8); // Q(zeros) |
108 diffGain = WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRati
o); | 202 if (numFIX < 0) { |
109 if (diffGain < 0 || diffGain >= kGenFuncTableSize) | 203 numFIX -= tmp32no1 / 2; |
110 { | 204 } else { |
111 assert(0); | 205 numFIX += tmp32no1 / 2; |
112 return -1; | 206 } |
113 } | 207 y32 = numFIX / tmp32no1; // in Q14 |
114 | 208 if (limiterEnable && (i < limiterIdx)) { |
115 // Calculate the limiter level and index: | 209 tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14 |
116 // limiterLvlX = analogTarget - limiterOffset | 210 tmp32 -= limiterLvl * (1 << 14); // Q14 |
117 // limiterLvl = targetLevelDbfs + limiterOffset/compRatio | 211 y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20); |
118 limiterLvlX = analogTarget - limiterOffset; | 212 } |
119 limiterIdx = | 213 if (y32 > 39000) { |
120 2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX * (1 << 13), | 214 tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27 |
121 kLog10_2 / 2); | 215 tmp32 >>= 13; // In Q14. |
122 tmp16no1 = WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCom
pRatio); | 216 } else { |
123 limiterLvl = targetLevelDbfs + tmp16no1; | 217 tmp32 = y32 * kLog10 + 8192; // in Q28 |
124 | 218 tmp32 >>= 14; // In Q14. |
125 // Calculate (through table lookup): | 219 } |
126 // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8) | 220 tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16) |
127 constMaxGain = kGenFuncTable[diffGain]; // in Q8 | 221 |
128 | 222 // Calculate power |
129 // Calculate a parameter used to approximate the fractional part of 2^x with
a | 223 if (tmp32 > 0) { |
130 // piecewise linear function in Q14: | 224 intPart = (int16_t)(tmp32 >> 14); |
131 // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14); | 225 fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14 |
132 constLinApprox = 22817; // in Q14 | 226 if ((fracPart >> 13) != 0) { |
133 | 227 tmp16 = (2 << 14) - constLinApprox; |
134 // Calculate a denominator used in the exponential part to convert from dB t
o linear scale: | 228 tmp32no2 = (1 << 14) - fracPart; |
135 // den = 20*constMaxGain (in Q8) | 229 tmp32no2 *= tmp16; |
136 den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8 | 230 tmp32no2 >>= 13; |
137 | 231 tmp32no2 = (1 << 14) - tmp32no2; |
138 for (i = 0; i < 32; i++) | 232 } else { |
139 { | 233 tmp16 = constLinApprox - (1 << 14); |
140 // Calculate scaled input level (compressor): | 234 tmp32no2 = (fracPart * tmp16) >> 13; |
141 // inLevel = fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/c
ompRatio) | 235 } |
142 tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0 | 236 fracPart = (uint16_t)tmp32no2; |
143 tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14 | 237 gainTable[i] = |
144 inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14 | 238 (1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14); |
145 | 239 } else { |
146 // Calculate diffGain-inLevel, to map using the genFuncTable | 240 gainTable[i] = 0; |
147 inLevel = (int32_t)diffGain * (1 << 14) - inLevel; // Q14 | 241 } |
148 | 242 } |
149 // Make calculations on abs(inLevel) and compensate for the sign afterwa
rds. | 243 |
150 absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14 | 244 return 0; |
151 | |
152 // LUT with interpolation | |
153 intPart = (uint16_t)(absInLevel >> 14); | |
154 fracPart = (uint16_t)(absInLevel & 0x00003FFF); // extract the fractiona
l part | |
155 tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8 | |
156 tmpU32no1 = tmpU16 * fracPart; // Q22 | |
157 tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22 | |
158 logApprox = tmpU32no1 >> 8; // Q14 | |
159 // Compensate for negative exponent using the relation: | |
160 // log2(1 + 2^-x) = log2(1 + 2^x) - x | |
161 if (inLevel < 0) | |
162 { | |
163 zeros = WebRtcSpl_NormU32(absInLevel); | |
164 zerosScale = 0; | |
165 if (zeros < 15) | |
166 { | |
167 // Not enough space for multiplication | |
168 tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1) | |
169 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zero
s+13) | |
170 if (zeros < 9) | |
171 { | |
172 zerosScale = 9 - zeros; | |
173 tmpU32no1 >>= zerosScale; // Q(zeros+13) | |
174 } else | |
175 { | |
176 tmpU32no2 >>= zeros - 9; // Q22 | |
177 } | |
178 } else | |
179 { | |
180 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28 | |
181 tmpU32no2 >>= 6; // Q22 | |
182 } | |
183 logApprox = 0; | |
184 if (tmpU32no2 < tmpU32no1) | |
185 { | |
186 logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); //Q14 | |
187 } | |
188 } | |
189 numFIX = (maxGain * constMaxGain) * (1 << 6); // Q14 | |
190 numFIX -= (int32_t)logApprox * diffGain; // Q14 | |
191 | |
192 // Calculate ratio | |
193 // Shift |numFIX| as much as possible. | |
194 // Ensure we avoid wrap-around in |den| as well. | |
195 if (numFIX > (den >> 8)) // |den| is Q8. | |
196 { | |
197 zeros = WebRtcSpl_NormW32(numFIX); | |
198 } else | |
199 { | |
200 zeros = WebRtcSpl_NormW32(den) + 8; | |
201 } | |
202 numFIX *= 1 << zeros; // Q(14+zeros) | |
203 | |
204 // Shift den so we end up in Qy1 | |
205 tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 8); // Q(zeros) | |
206 if (numFIX < 0) | |
207 { | |
208 numFIX -= tmp32no1 / 2; | |
209 } else | |
210 { | |
211 numFIX += tmp32no1 / 2; | |
212 } | |
213 y32 = numFIX / tmp32no1; // in Q14 | |
214 if (limiterEnable && (i < limiterIdx)) | |
215 { | |
216 tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14 | |
217 tmp32 -= limiterLvl * (1 << 14); // Q14 | |
218 y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20); | |
219 } | |
220 if (y32 > 39000) | |
221 { | |
222 tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27 | |
223 tmp32 >>= 13; // In Q14. | |
224 } else | |
225 { | |
226 tmp32 = y32 * kLog10 + 8192; // in Q28 | |
227 tmp32 >>= 14; // In Q14. | |
228 } | |
229 tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16) | |
230 | |
231 // Calculate power | |
232 if (tmp32 > 0) | |
233 { | |
234 intPart = (int16_t)(tmp32 >> 14); | |
235 fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14 | |
236 if ((fracPart >> 13) != 0) | |
237 { | |
238 tmp16 = (2 << 14) - constLinApprox; | |
239 tmp32no2 = (1 << 14) - fracPart; | |
240 tmp32no2 *= tmp16; | |
241 tmp32no2 >>= 13; | |
242 tmp32no2 = (1 << 14) - tmp32no2; | |
243 } else | |
244 { | |
245 tmp16 = constLinApprox - (1 << 14); | |
246 tmp32no2 = (fracPart * tmp16) >> 13; | |
247 } | |
248 fracPart = (uint16_t)tmp32no2; | |
249 gainTable[i] = | |
250 (1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14); | |
251 } else | |
252 { | |
253 gainTable[i] = 0; | |
254 } | |
255 } | |
256 | |
257 return 0; | |
258 } | 245 } |
259 | 246 |
260 int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) { | 247 int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) { |
261 if (agcMode == kAgcModeFixedDigital) | 248 if (agcMode == kAgcModeFixedDigital) { |
262 { | 249 // start at minimum to find correct gain faster |
263 // start at minimum to find correct gain faster | 250 stt->capacitorSlow = 0; |
264 stt->capacitorSlow = 0; | 251 } else { |
265 } else | 252 // start out with 0 dB gain |
266 { | 253 stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0f); |
267 // start out with 0 dB gain | 254 } |
268 stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0
f); | 255 stt->capacitorFast = 0; |
269 } | 256 stt->gain = 65536; |
270 stt->capacitorFast = 0; | 257 stt->gatePrevious = 0; |
271 stt->gain = 65536; | 258 stt->agcMode = agcMode; |
272 stt->gatePrevious = 0; | |
273 stt->agcMode = agcMode; | |
274 #ifdef WEBRTC_AGC_DEBUG_DUMP | 259 #ifdef WEBRTC_AGC_DEBUG_DUMP |
275 stt->frameCounter = 0; | 260 stt->frameCounter = 0; |
276 #endif | 261 #endif |
277 | 262 |
278 // initialize VADs | 263 // initialize VADs |
279 WebRtcAgc_InitVad(&stt->vadNearend); | 264 WebRtcAgc_InitVad(&stt->vadNearend); |
280 WebRtcAgc_InitVad(&stt->vadFarend); | 265 WebRtcAgc_InitVad(&stt->vadFarend); |
281 | 266 |
282 return 0; | 267 return 0; |
283 } | 268 } |
284 | 269 |
285 int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt, | 270 int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt, |
286 const int16_t* in_far, | 271 const int16_t* in_far, |
287 size_t nrSamples) { | 272 size_t nrSamples) { |
288 assert(stt != NULL); | 273 assert(stt != NULL); |
289 // VAD for far end | 274 // VAD for far end |
290 WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples); | 275 WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples); |
291 | 276 |
292 return 0; | 277 return 0; |
293 } | 278 } |
294 | 279 |
295 int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt, | 280 int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt, |
296 const int16_t* const* in_near, | 281 const int16_t* const* in_near, |
297 size_t num_bands, | 282 size_t num_bands, |
298 int16_t* const* out, | 283 int16_t* const* out, |
299 uint32_t FS, | 284 uint32_t FS, |
300 int16_t lowlevelSignal) { | 285 int16_t lowlevelSignal) { |
301 // array for gains (one value per ms, incl start & end) | 286 // array for gains (one value per ms, incl start & end) |
302 int32_t gains[11]; | 287 int32_t gains[11]; |
303 | 288 |
304 int32_t out_tmp, tmp32; | 289 int32_t out_tmp, tmp32; |
305 int32_t env[10]; | 290 int32_t env[10]; |
306 int32_t max_nrg; | 291 int32_t max_nrg; |
307 int32_t cur_level; | 292 int32_t cur_level; |
308 int32_t gain32, delta; | 293 int32_t gain32, delta; |
309 int16_t logratio; | 294 int16_t logratio; |
310 int16_t lower_thr, upper_thr; | 295 int16_t lower_thr, upper_thr; |
311 int16_t zeros = 0, zeros_fast, frac = 0; | 296 int16_t zeros = 0, zeros_fast, frac = 0; |
312 int16_t decay; | 297 int16_t decay; |
313 int16_t gate, gain_adj; | 298 int16_t gate, gain_adj; |
314 int16_t k; | 299 int16_t k; |
315 size_t n, i, L; | 300 size_t n, i, L; |
316 int16_t L2; // samples/subframe | 301 int16_t L2; // samples/subframe |
317 | 302 |
318 // determine number of samples per ms | 303 // determine number of samples per ms |
319 if (FS == 8000) | 304 if (FS == 8000) { |
320 { | 305 L = 8; |
321 L = 8; | 306 L2 = 3; |
322 L2 = 3; | 307 } else if (FS == 16000 || FS == 32000 || FS == 48000) { |
323 } else if (FS == 16000 || FS == 32000 || FS == 48000) | 308 L = 16; |
324 { | 309 L2 = 4; |
325 L = 16; | 310 } else { |
326 L2 = 4; | 311 return -1; |
327 } else | 312 } |
328 { | 313 |
329 return -1; | 314 for (i = 0; i < num_bands; ++i) { |
330 } | 315 if (in_near[i] != out[i]) { |
331 | 316 // Only needed if they don't already point to the same place. |
332 for (i = 0; i < num_bands; ++i) | 317 memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0])); |
333 { | 318 } |
334 if (in_near[i] != out[i]) | 319 } |
335 { | 320 // VAD for near end |
336 // Only needed if they don't already point to the same place. | 321 logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out[0], L * 10); |
337 memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0])); | 322 |
338 } | 323 // Account for far end VAD |
339 } | 324 if (stt->vadFarend.counter > 10) { |
340 // VAD for near end | 325 tmp32 = 3 * logratio; |
341 logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out[0], L * 10); | 326 logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2); |
342 | 327 } |
343 // Account for far end VAD | 328 |
344 if (stt->vadFarend.counter > 10) | 329 // Determine decay factor depending on VAD |
345 { | 330 // upper_thr = 1.0f; |
346 tmp32 = 3 * logratio; | 331 // lower_thr = 0.25f; |
347 logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2); | 332 upper_thr = 1024; // Q10 |
348 } | 333 lower_thr = 0; // Q10 |
349 | 334 if (logratio > upper_thr) { |
350 // Determine decay factor depending on VAD | 335 // decay = -2^17 / DecayTime; -> -65 |
351 // upper_thr = 1.0f; | 336 decay = -65; |
352 // lower_thr = 0.25f; | 337 } else if (logratio < lower_thr) { |
353 upper_thr = 1024; // Q10 | 338 decay = 0; |
354 lower_thr = 0; // Q10 | 339 } else { |
355 if (logratio > upper_thr) | 340 // decay = (int16_t)(((lower_thr - logratio) |
356 { | 341 // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10); |
357 // decay = -2^17 / DecayTime; -> -65 | 342 // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65 |
358 decay = -65; | 343 tmp32 = (lower_thr - logratio) * 65; |
359 } else if (logratio < lower_thr) | 344 decay = (int16_t)(tmp32 >> 10); |
360 { | 345 } |
361 decay = 0; | 346 |
362 } else | 347 // adjust decay factor for long silence (detected as low standard deviation) |
363 { | 348 // This is only done in the adaptive modes |
364 // decay = (int16_t)(((lower_thr - logratio) | 349 if (stt->agcMode != kAgcModeFixedDigital) { |
365 // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10); | 350 if (stt->vadNearend.stdLongTerm < 4000) { |
366 // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65 | 351 decay = 0; |
367 tmp32 = (lower_thr - logratio) * 65; | 352 } else if (stt->vadNearend.stdLongTerm < 8096) { |
368 decay = (int16_t)(tmp32 >> 10); | 353 // decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay) >> |
369 } | 354 // 12); |
370 | 355 tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay; |
371 // adjust decay factor for long silence (detected as low standard deviation) | 356 decay = (int16_t)(tmp32 >> 12); |
372 // This is only done in the adaptive modes | 357 } |
373 if (stt->agcMode != kAgcModeFixedDigital) | 358 |
374 { | 359 if (lowlevelSignal != 0) { |
375 if (stt->vadNearend.stdLongTerm < 4000) | 360 decay = 0; |
376 { | 361 } |
377 decay = 0; | 362 } |
378 } else if (stt->vadNearend.stdLongTerm < 8096) | |
379 { | |
380 // decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay)
>> 12); | |
381 tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay; | |
382 decay = (int16_t)(tmp32 >> 12); | |
383 } | |
384 | |
385 if (lowlevelSignal != 0) | |
386 { | |
387 decay = 0; | |
388 } | |
389 } | |
390 #ifdef WEBRTC_AGC_DEBUG_DUMP | 363 #ifdef WEBRTC_AGC_DEBUG_DUMP |
391 stt->frameCounter++; | 364 stt->frameCounter++; |
392 fprintf(stt->logFile, | 365 fprintf(stt->logFile, "%5.2f\t%d\t%d\t%d\t", (float)(stt->frameCounter) / 100, |
393 "%5.2f\t%d\t%d\t%d\t", | 366 logratio, decay, stt->vadNearend.stdLongTerm); |
394 (float)(stt->frameCounter) / 100, | |
395 logratio, | |
396 decay, | |
397 stt->vadNearend.stdLongTerm); | |
398 #endif | 367 #endif |
399 // Find max amplitude per sub frame | 368 // Find max amplitude per sub frame |
400 // iterate over sub frames | 369 // iterate over sub frames |
401 for (k = 0; k < 10; k++) | 370 for (k = 0; k < 10; k++) { |
402 { | 371 // iterate over samples |
403 // iterate over samples | 372 max_nrg = 0; |
404 max_nrg = 0; | 373 for (n = 0; n < L; n++) { |
405 for (n = 0; n < L; n++) | 374 int32_t nrg = out[0][k * L + n] * out[0][k * L + n]; |
406 { | 375 if (nrg > max_nrg) { |
407 int32_t nrg = out[0][k * L + n] * out[0][k * L + n]; | 376 max_nrg = nrg; |
408 if (nrg > max_nrg) | 377 } |
409 { | 378 } |
410 max_nrg = nrg; | 379 env[k] = max_nrg; |
411 } | 380 } |
412 } | 381 |
413 env[k] = max_nrg; | 382 // Calculate gain per sub frame |
414 } | 383 gains[0] = stt->gain; |
415 | 384 for (k = 0; k < 10; k++) { |
416 // Calculate gain per sub frame | 385 // Fast envelope follower |
417 gains[0] = stt->gain; | 386 // decay time = -131000 / -1000 = 131 (ms) |
418 for (k = 0; k < 10; k++) | 387 stt->capacitorFast = |
419 { | 388 AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast); |
420 // Fast envelope follower | 389 if (env[k] > stt->capacitorFast) { |
421 // decay time = -131000 / -1000 = 131 (ms) | 390 stt->capacitorFast = env[k]; |
422 stt->capacitorFast = AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->cap
acitorFast); | 391 } |
423 if (env[k] > stt->capacitorFast) | 392 // Slow envelope follower |
424 { | 393 if (env[k] > stt->capacitorSlow) { |
425 stt->capacitorFast = env[k]; | 394 // increase capacitorSlow |
426 } | 395 stt->capacitorSlow = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow), |
427 // Slow envelope follower | 396 stt->capacitorSlow); |
428 if (env[k] > stt->capacitorSlow) | 397 } else { |
429 { | 398 // decrease capacitorSlow |
430 // increase capacitorSlow | 399 stt->capacitorSlow = |
431 stt->capacitorSlow | 400 AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow); |
432 = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow), stt->c
apacitorSlow); | 401 } |
433 } else | 402 |
434 { | 403 // use maximum of both capacitors as current level |
435 // decrease capacitorSlow | 404 if (stt->capacitorFast > stt->capacitorSlow) { |
436 stt->capacitorSlow | 405 cur_level = stt->capacitorFast; |
437 = AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorS
low); | 406 } else { |
438 } | 407 cur_level = stt->capacitorSlow; |
439 | 408 } |
440 // use maximum of both capacitors as current level | 409 // Translate signal level into gain, using a piecewise linear approximation |
441 if (stt->capacitorFast > stt->capacitorSlow) | 410 // find number of leading zeros |
442 { | 411 zeros = WebRtcSpl_NormU32((uint32_t)cur_level); |
443 cur_level = stt->capacitorFast; | 412 if (cur_level == 0) { |
444 } else | 413 zeros = 31; |
445 { | 414 } |
446 cur_level = stt->capacitorSlow; | 415 tmp32 = (cur_level << zeros) & 0x7FFFFFFF; |
447 } | 416 frac = (int16_t)(tmp32 >> 19); // Q12. |
448 // Translate signal level into gain, using a piecewise linear approximat
ion | 417 tmp32 = (stt->gainTable[zeros - 1] - stt->gainTable[zeros]) * frac; |
449 // find number of leading zeros | 418 gains[k + 1] = stt->gainTable[zeros] + (tmp32 >> 12); |
450 zeros = WebRtcSpl_NormU32((uint32_t)cur_level); | |
451 if (cur_level == 0) | |
452 { | |
453 zeros = 31; | |
454 } | |
455 tmp32 = (cur_level << zeros) & 0x7FFFFFFF; | |
456 frac = (int16_t)(tmp32 >> 19); // Q12. | |
457 tmp32 = (stt->gainTable[zeros-1] - stt->gainTable[zeros]) * frac; | |
458 gains[k + 1] = stt->gainTable[zeros] + (tmp32 >> 12); | |
459 #ifdef WEBRTC_AGC_DEBUG_DUMP | 419 #ifdef WEBRTC_AGC_DEBUG_DUMP |
460 if (k == 0) { | 420 if (k == 0) { |
461 fprintf(stt->logFile, | 421 fprintf(stt->logFile, "%d\t%d\t%d\t%d\t%d\n", env[0], cur_level, |
462 "%d\t%d\t%d\t%d\t%d\n", | 422 stt->capacitorFast, stt->capacitorSlow, zeros); |
463 env[0], | 423 } |
464 cur_level, | |
465 stt->capacitorFast, | |
466 stt->capacitorSlow, | |
467 zeros); | |
468 } | |
469 #endif | 424 #endif |
470 } | 425 } |
471 | 426 |
472 // Gate processing (lower gain during absence of speech) | 427 // Gate processing (lower gain during absence of speech) |
473 zeros = (zeros << 9) - (frac >> 3); | 428 zeros = (zeros << 9) - (frac >> 3); |
474 // find number of leading zeros | 429 // find number of leading zeros |
475 zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast); | 430 zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast); |
476 if (stt->capacitorFast == 0) | 431 if (stt->capacitorFast == 0) { |
477 { | 432 zeros_fast = 31; |
478 zeros_fast = 31; | 433 } |
479 } | 434 tmp32 = (stt->capacitorFast << zeros_fast) & 0x7FFFFFFF; |
480 tmp32 = (stt->capacitorFast << zeros_fast) & 0x7FFFFFFF; | 435 zeros_fast <<= 9; |
481 zeros_fast <<= 9; | 436 zeros_fast -= (int16_t)(tmp32 >> 22); |
482 zeros_fast -= (int16_t)(tmp32 >> 22); | 437 |
483 | 438 gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm; |
484 gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm; | 439 |
485 | 440 if (gate < 0) { |
486 if (gate < 0) | 441 stt->gatePrevious = 0; |
487 { | 442 } else { |
488 stt->gatePrevious = 0; | 443 tmp32 = stt->gatePrevious * 7; |
489 } else | 444 gate = (int16_t)((gate + tmp32) >> 3); |
490 { | 445 stt->gatePrevious = gate; |
491 tmp32 = stt->gatePrevious * 7; | 446 } |
492 gate = (int16_t)((gate + tmp32) >> 3); | 447 // gate < 0 -> no gate |
493 stt->gatePrevious = gate; | 448 // gate > 2500 -> max gate |
494 } | 449 if (gate > 0) { |
495 // gate < 0 -> no gate | 450 if (gate < 2500) { |
496 // gate > 2500 -> max gate | 451 gain_adj = (2500 - gate) >> 5; |
497 if (gate > 0) | 452 } else { |
498 { | 453 gain_adj = 0; |
499 if (gate < 2500) | 454 } |
500 { | 455 for (k = 0; k < 10; k++) { |
501 gain_adj = (2500 - gate) >> 5; | 456 if ((gains[k + 1] - stt->gainTable[0]) > 8388608) { |
502 } else | 457 // To prevent wraparound |
503 { | 458 tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8; |
504 gain_adj = 0; | 459 tmp32 *= 178 + gain_adj; |
505 } | 460 } else { |
506 for (k = 0; k < 10; k++) | 461 tmp32 = (gains[k + 1] - stt->gainTable[0]) * (178 + gain_adj); |
507 { | 462 tmp32 >>= 8; |
508 if ((gains[k + 1] - stt->gainTable[0]) > 8388608) | 463 } |
509 { | 464 gains[k + 1] = stt->gainTable[0] + tmp32; |
510 // To prevent wraparound | 465 } |
511 tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8; | 466 } |
512 tmp32 *= 178 + gain_adj; | 467 |
513 } else | 468 // Limit gain to avoid overload distortion |
514 { | 469 for (k = 0; k < 10; k++) { |
515 tmp32 = (gains[k+1] - stt->gainTable[0]) * (178 + gain_adj); | 470 // To prevent wrap around |
516 tmp32 >>= 8; | 471 zeros = 10; |
517 } | 472 if (gains[k + 1] > 47453132) { |
518 gains[k + 1] = stt->gainTable[0] + tmp32; | 473 zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]); |
519 } | 474 } |
520 } | 475 gain32 = (gains[k + 1] >> zeros) + 1; |
521 | 476 gain32 *= gain32; |
522 // Limit gain to avoid overload distortion | 477 // check for overflow |
523 for (k = 0; k < 10; k++) | 478 while (AGC_MUL32((env[k] >> 12) + 1, gain32) > |
524 { | 479 WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10))) { |
525 // To prevent wrap around | 480 // multiply by 253/256 ==> -0.1 dB |
526 zeros = 10; | 481 if (gains[k + 1] > 8388607) { |
527 if (gains[k + 1] > 47453132) | 482 // Prevent wrap around |
528 { | 483 gains[k + 1] = (gains[k + 1] / 256) * 253; |
529 zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]); | 484 } else { |
530 } | 485 gains[k + 1] = (gains[k + 1] * 253) / 256; |
531 gain32 = (gains[k + 1] >> zeros) + 1; | 486 } |
532 gain32 *= gain32; | 487 gain32 = (gains[k + 1] >> zeros) + 1; |
533 // check for overflow | 488 gain32 *= gain32; |
534 while (AGC_MUL32((env[k] >> 12) + 1, gain32) | 489 } |
535 > WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10))) | 490 } |
536 { | 491 // gain reductions should be done 1 ms earlier than gain increases |
537 // multiply by 253/256 ==> -0.1 dB | 492 for (k = 1; k < 10; k++) { |
538 if (gains[k + 1] > 8388607) | 493 if (gains[k] > gains[k + 1]) { |
539 { | 494 gains[k] = gains[k + 1]; |
540 // Prevent wrap around | 495 } |
541 gains[k + 1] = (gains[k+1] / 256) * 253; | 496 } |
542 } else | 497 // save start gain for next frame |
543 { | 498 stt->gain = gains[10]; |
544 gains[k + 1] = (gains[k+1] * 253) / 256; | 499 |
545 } | 500 // Apply gain |
546 gain32 = (gains[k + 1] >> zeros) + 1; | 501 // handle first sub frame separately |
547 gain32 *= gain32; | 502 delta = (gains[1] - gains[0]) * (1 << (4 - L2)); |
548 } | 503 gain32 = gains[0] * (1 << 4); |
549 } | 504 // iterate over samples |
550 // gain reductions should be done 1 ms earlier than gain increases | 505 for (n = 0; n < L; n++) { |
551 for (k = 1; k < 10; k++) | 506 for (i = 0; i < num_bands; ++i) { |
552 { | 507 tmp32 = out[i][n] * ((gain32 + 127) >> 7); |
553 if (gains[k] > gains[k + 1]) | 508 out_tmp = tmp32 >> 16; |
554 { | 509 if (out_tmp > 4095) { |
555 gains[k] = gains[k + 1]; | 510 out[i][n] = (int16_t)32767; |
556 } | 511 } else if (out_tmp < -4096) { |
557 } | 512 out[i][n] = (int16_t)-32768; |
558 // save start gain for next frame | 513 } else { |
559 stt->gain = gains[10]; | 514 tmp32 = out[i][n] * (gain32 >> 4); |
560 | 515 out[i][n] = (int16_t)(tmp32 >> 16); |
561 // Apply gain | 516 } |
562 // handle first sub frame separately | 517 } |
563 delta = (gains[1] - gains[0]) * (1 << (4 - L2)); | 518 // |
564 gain32 = gains[0] * (1 << 4); | 519 |
| 520 gain32 += delta; |
| 521 } |
| 522 // iterate over subframes |
| 523 for (k = 1; k < 10; k++) { |
| 524 delta = (gains[k + 1] - gains[k]) * (1 << (4 - L2)); |
| 525 gain32 = gains[k] * (1 << 4); |
565 // iterate over samples | 526 // iterate over samples |
566 for (n = 0; n < L; n++) | 527 for (n = 0; n < L; n++) { |
567 { | 528 for (i = 0; i < num_bands; ++i) { |
568 for (i = 0; i < num_bands; ++i) | 529 tmp32 = out[i][k * L + n] * (gain32 >> 4); |
569 { | 530 out[i][k * L + n] = (int16_t)(tmp32 >> 16); |
570 tmp32 = out[i][n] * ((gain32 + 127) >> 7); | 531 } |
571 out_tmp = tmp32 >> 16; | 532 gain32 += delta; |
572 if (out_tmp > 4095) | 533 } |
573 { | 534 } |
574 out[i][n] = (int16_t)32767; | 535 |
575 } else if (out_tmp < -4096) | 536 return 0; |
576 { | |
577 out[i][n] = (int16_t)-32768; | |
578 } else | |
579 { | |
580 tmp32 = out[i][n] * (gain32 >> 4); | |
581 out[i][n] = (int16_t)(tmp32 >> 16); | |
582 } | |
583 } | |
584 // | |
585 | |
586 gain32 += delta; | |
587 } | |
588 // iterate over subframes | |
589 for (k = 1; k < 10; k++) | |
590 { | |
591 delta = (gains[k+1] - gains[k]) * (1 << (4 - L2)); | |
592 gain32 = gains[k] * (1 << 4); | |
593 // iterate over samples | |
594 for (n = 0; n < L; n++) | |
595 { | |
596 for (i = 0; i < num_bands; ++i) | |
597 { | |
598 tmp32 = out[i][k * L + n] * (gain32 >> 4); | |
599 out[i][k * L + n] = (int16_t)(tmp32 >> 16); | |
600 } | |
601 gain32 += delta; | |
602 } | |
603 } | |
604 | |
605 return 0; | |
606 } | 537 } |
607 | 538 |
608 void WebRtcAgc_InitVad(AgcVad* state) { | 539 void WebRtcAgc_InitVad(AgcVad* state) { |
609 int16_t k; | 540 int16_t k; |
610 | 541 |
611 state->HPstate = 0; // state of high pass filter | 542 state->HPstate = 0; // state of high pass filter |
612 state->logRatio = 0; // log( P(active) / P(inactive) ) | 543 state->logRatio = 0; // log( P(active) / P(inactive) ) |
613 // average input level (Q10) | 544 // average input level (Q10) |
614 state->meanLongTerm = 15 << 10; | 545 state->meanLongTerm = 15 << 10; |
615 | 546 |
616 // variance of input level (Q8) | 547 // variance of input level (Q8) |
617 state->varianceLongTerm = 500 << 8; | 548 state->varianceLongTerm = 500 << 8; |
618 | 549 |
619 state->stdLongTerm = 0; // standard deviation of input level in dB | 550 state->stdLongTerm = 0; // standard deviation of input level in dB |
620 // short-term average input level (Q10) | 551 // short-term average input level (Q10) |
621 state->meanShortTerm = 15 << 10; | 552 state->meanShortTerm = 15 << 10; |
622 | 553 |
623 // short-term variance of input level (Q8) | 554 // short-term variance of input level (Q8) |
624 state->varianceShortTerm = 500 << 8; | 555 state->varianceShortTerm = 500 << 8; |
625 | 556 |
626 state->stdShortTerm = 0; // short-term standard deviation of input level in
dB | 557 state->stdShortTerm = |
627 state->counter = 3; // counts updates | 558 0; // short-term standard deviation of input level in dB |
628 for (k = 0; k < 8; k++) | 559 state->counter = 3; // counts updates |
629 { | 560 for (k = 0; k < 8; k++) { |
630 // downsampling filter | 561 // downsampling filter |
631 state->downState[k] = 0; | 562 state->downState[k] = 0; |
632 } | 563 } |
633 } | 564 } |
634 | 565 |
635 int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state | 566 int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state |
636 const int16_t* in, // (i) Speech signal | 567 const int16_t* in, // (i) Speech signal |
637 size_t nrSamples) // (i) number of samples | 568 size_t nrSamples) // (i) number of samples |
638 { | 569 { |
639 int32_t out, nrg, tmp32, tmp32b; | 570 int32_t out, nrg, tmp32, tmp32b; |
640 uint16_t tmpU16; | 571 uint16_t tmpU16; |
641 int16_t k, subfr, tmp16; | 572 int16_t k, subfr, tmp16; |
642 int16_t buf1[8]; | 573 int16_t buf1[8]; |
643 int16_t buf2[4]; | 574 int16_t buf2[4]; |
644 int16_t HPstate; | 575 int16_t HPstate; |
645 int16_t zeros, dB; | 576 int16_t zeros, dB; |
646 | 577 |
647 // process in 10 sub frames of 1 ms (to save on memory) | 578 // process in 10 sub frames of 1 ms (to save on memory) |
648 nrg = 0; | 579 nrg = 0; |
649 HPstate = state->HPstate; | 580 HPstate = state->HPstate; |
650 for (subfr = 0; subfr < 10; subfr++) | 581 for (subfr = 0; subfr < 10; subfr++) { |
651 { | 582 // downsample to 4 kHz |
652 // downsample to 4 kHz | 583 if (nrSamples == 160) { |
653 if (nrSamples == 160) | 584 for (k = 0; k < 8; k++) { |
654 { | 585 tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1]; |
655 for (k = 0; k < 8; k++) | 586 tmp32 >>= 1; |
656 { | 587 buf1[k] = (int16_t)tmp32; |
657 tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1]; | 588 } |
658 tmp32 >>= 1; | 589 in += 16; |
659 buf1[k] = (int16_t)tmp32; | 590 |
660 } | 591 WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState); |
661 in += 16; | 592 } else { |
662 | 593 WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState); |
663 WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState); | 594 in += 8; |
664 } else | 595 } |
665 { | 596 |
666 WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState); | 597 // high pass filter and compute energy |
667 in += 8; | 598 for (k = 0; k < 4; k++) { |
668 } | 599 out = buf2[k] + HPstate; |
669 | 600 tmp32 = 600 * out; |
670 // high pass filter and compute energy | 601 HPstate = (int16_t)((tmp32 >> 10) - buf2[k]); |
671 for (k = 0; k < 4; k++) | 602 nrg += (out * out) >> 6; |
672 { | 603 } |
673 out = buf2[k] + HPstate; | 604 } |
674 tmp32 = 600 * out; | 605 state->HPstate = HPstate; |
675 HPstate = (int16_t)((tmp32 >> 10) - buf2[k]); | 606 |
676 nrg += (out * out) >> 6; | 607 // find number of leading zeros |
677 } | 608 if (!(0xFFFF0000 & nrg)) { |
678 } | 609 zeros = 16; |
679 state->HPstate = HPstate; | 610 } else { |
680 | 611 zeros = 0; |
681 // find number of leading zeros | 612 } |
682 if (!(0xFFFF0000 & nrg)) | 613 if (!(0xFF000000 & (nrg << zeros))) { |
683 { | 614 zeros += 8; |
684 zeros = 16; | 615 } |
685 } else | 616 if (!(0xF0000000 & (nrg << zeros))) { |
686 { | 617 zeros += 4; |
687 zeros = 0; | 618 } |
688 } | 619 if (!(0xC0000000 & (nrg << zeros))) { |
689 if (!(0xFF000000 & (nrg << zeros))) | 620 zeros += 2; |
690 { | 621 } |
691 zeros += 8; | 622 if (!(0x80000000 & (nrg << zeros))) { |
692 } | 623 zeros += 1; |
693 if (!(0xF0000000 & (nrg << zeros))) | 624 } |
694 { | 625 |
695 zeros += 4; | 626 // energy level (range {-32..30}) (Q10) |
696 } | 627 dB = (15 - zeros) << 11; |
697 if (!(0xC0000000 & (nrg << zeros))) | 628 |
698 { | 629 // Update statistics |
699 zeros += 2; | 630 |
700 } | 631 if (state->counter < kAvgDecayTime) { |
701 if (!(0x80000000 & (nrg << zeros))) | 632 // decay time = AvgDecTime * 10 ms |
702 { | 633 state->counter++; |
703 zeros += 1; | 634 } |
704 } | 635 |
705 | 636 // update short-term estimate of mean energy level (Q10) |
706 // energy level (range {-32..30}) (Q10) | 637 tmp32 = state->meanShortTerm * 15 + dB; |
707 dB = (15 - zeros) << 11; | 638 state->meanShortTerm = (int16_t)(tmp32 >> 4); |
708 | 639 |
709 // Update statistics | 640 // update short-term estimate of variance in energy level (Q8) |
710 | 641 tmp32 = (dB * dB) >> 12; |
711 if (state->counter < kAvgDecayTime) | 642 tmp32 += state->varianceShortTerm * 15; |
712 { | 643 state->varianceShortTerm = tmp32 / 16; |
713 // decay time = AvgDecTime * 10 ms | 644 |
714 state->counter++; | 645 // update short-term estimate of standard deviation in energy level (Q10) |
715 } | 646 tmp32 = state->meanShortTerm * state->meanShortTerm; |
716 | 647 tmp32 = (state->varianceShortTerm << 12) - tmp32; |
717 // update short-term estimate of mean energy level (Q10) | 648 state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32); |
718 tmp32 = state->meanShortTerm * 15 + dB; | 649 |
719 state->meanShortTerm = (int16_t)(tmp32 >> 4); | 650 // update long-term estimate of mean energy level (Q10) |
720 | 651 tmp32 = state->meanLongTerm * state->counter + dB; |
721 // update short-term estimate of variance in energy level (Q8) | 652 state->meanLongTerm = |
722 tmp32 = (dB * dB) >> 12; | 653 WebRtcSpl_DivW32W16ResW16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1)); |
723 tmp32 += state->varianceShortTerm * 15; | 654 |
724 state->varianceShortTerm = tmp32 / 16; | 655 // update long-term estimate of variance in energy level (Q8) |
725 | 656 tmp32 = (dB * dB) >> 12; |
726 // update short-term estimate of standard deviation in energy level (Q10) | 657 tmp32 += state->varianceLongTerm * state->counter; |
727 tmp32 = state->meanShortTerm * state->meanShortTerm; | 658 state->varianceLongTerm = |
728 tmp32 = (state->varianceShortTerm << 12) - tmp32; | 659 WebRtcSpl_DivW32W16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1)); |
729 state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32); | 660 |
730 | 661 // update long-term estimate of standard deviation in energy level (Q10) |
731 // update long-term estimate of mean energy level (Q10) | 662 tmp32 = state->meanLongTerm * state->meanLongTerm; |
732 tmp32 = state->meanLongTerm * state->counter + dB; | 663 tmp32 = (state->varianceLongTerm << 12) - tmp32; |
733 state->meanLongTerm = WebRtcSpl_DivW32W16ResW16( | 664 state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32); |
734 tmp32, WebRtcSpl_AddSatW16(state->counter, 1)); | 665 |
735 | 666 // update voice activity measure (Q10) |
736 // update long-term estimate of variance in energy level (Q8) | 667 tmp16 = 3 << 12; |
737 tmp32 = (dB * dB) >> 12; | 668 // TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in |
738 tmp32 += state->varianceLongTerm * state->counter; | 669 // ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16() |
739 state->varianceLongTerm = WebRtcSpl_DivW32W16( | 670 // was used, which did an intermediate cast to (int16_t), hence losing |
740 tmp32, WebRtcSpl_AddSatW16(state->counter, 1)); | 671 // significant bits. This cause logRatio to max out positive, rather than |
741 | 672 // negative. This is a bug, but has very little significance. |
742 // update long-term estimate of standard deviation in energy level (Q10) | 673 tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm); |
743 tmp32 = state->meanLongTerm * state->meanLongTerm; | 674 tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm); |
744 tmp32 = (state->varianceLongTerm << 12) - tmp32; | 675 tmpU16 = (13 << 12); |
745 state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32); | 676 tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16); |
746 | 677 tmp32 += tmp32b >> 10; |
747 // update voice activity measure (Q10) | 678 |
748 tmp16 = 3 << 12; | 679 state->logRatio = (int16_t)(tmp32 >> 6); |
749 // TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in | 680 |
750 // ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16() | 681 // limit |
751 // was used, which did an intermediate cast to (int16_t), hence losing | 682 if (state->logRatio > 2048) { |
752 // significant bits. This cause logRatio to max out positive, rather than | 683 state->logRatio = 2048; |
753 // negative. This is a bug, but has very little significance. | 684 } |
754 tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm); | 685 if (state->logRatio < -2048) { |
755 tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm); | 686 state->logRatio = -2048; |
756 tmpU16 = (13 << 12); | 687 } |
757 tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16); | 688 |
758 tmp32 += tmp32b >> 10; | 689 return state->logRatio; // Q10 |
759 | |
760 state->logRatio = (int16_t)(tmp32 >> 6); | |
761 | |
762 // limit | |
763 if (state->logRatio > 2048) | |
764 { | |
765 state->logRatio = 2048; | |
766 } | |
767 if (state->logRatio < -2048) | |
768 { | |
769 state->logRatio = -2048; | |
770 } | |
771 | |
772 return state->logRatio; // Q10 | |
773 } | 690 } |
OLD | NEW |