-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathaec1.c
283 lines (228 loc) · 7.5 KB
/
aec1.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// 1. 低频指导高频
void HighProc(float *gain)
{
int bins = 257;
const int FREQ_300HZ = 300;
const int FREQ_1200HZ = 1200;
const int FREQ_8000HZ = 8000;
int lowFreq = FREQ_300HZ / FREQ_8000HZ * bins;
int highFreq = FREQ_1200HZ / FREQ_8000HZ * bins;
int band = (highFreq - lowFreq) / 4 + 0.5;
int maxId = bins;
int lenght = 0;
int lastLength = 0;
for (int i = lowFreq; i <= highFreq; ++i) {
if (gain[i] < 0.05) {
lenght += 1;
lastLength += 1;
} else {
if (lastLength > band) {
maxId = i;
} else {
lastLength = 0;
}
}
}
if ((lenght > (highFreq - lowFreq) / 2) && (lastLength > band)) {
for (int i = maxId; i < bins; ++i) {
gain[i] = 0;
}
}
}
// 2. 计算ERL, SER
float xPowSmooth[257]; // 远端信号平滑能量谱 [0-257]
float dPowSmooth[257]; // 近端信号平滑能量谱 [0-257]
float echoEstPow[257]; // 回声估计平滑能量[0-257]
float errEstPow[257]; // 残差估计平滑能量[0-257]
float curERL[257];
float curSER[257];
float smoothERL[257];
float smoothSER[257];
for (int i = 0; i < 257; ++i) {
curERL[i] = (dPowSmooth[i] - noiseEst[i]) / max(xPowSmooth[i], 1);
curERL[i] = max(EPS, curERL[i]);
curSER[i] = (errEstPow[i] - noiseEst[i]) / max(echoEstPow[i], 1);
curSER[i] = max(EPS, curSER[i]);
}
// alpha需要根据单双讲,当前帧回声大小动态调整
SMOOTH(smoothERL, curERL, alpha);
SMOOTH(smoothSER, curSER, alpha);
// 可以根据在[400Hz, 2000Hz]范围内,就散curSER, curERL, smoothERL, smoothSER来作为
// 单双讲的辅助判断依据
// 3. 谐波增强消除回声
const int FFT_SIZE = 514;
float echoEstPow[257]; // 回声估计能量谱
float errEst[514]; // 滤波器+后滤波误差信号估计
float tmpErrEst[514]; // 误差估计增强信号
float snrEchoEst[257]; // 信回比
copy(errEst, tmpErrEst, FFT_SIZE); // errEst->tmpErrEst
IFFT(tmpErrEst);
for (int i = 0; i < 514; ++i) {
tmpErrEst[i] = max(tmpErrEst[i], 0);
}
FFT(tmpErrEst);
for (int i = 0; i < 257; ++i) {
float tmpR1 = tmpErrEst[2 * i];
float tmpI1 = tmpErrEst[2 * i + 1];
float tmpR2 = errEst[2 * i] - tmpR1;
float tmpI2 = errEst[2 * i] - tmpI1;
float tmp = ((tmpR1 * tmpR1 + tmpI1 * tmpI1) + (tmpR2 * tmpR2 + tmpI2 * tmpI2)) / 2;
snrEchoEst[i] = 0.2 * snrEchoEst[i] + 0.8 * (tmp / (echoEstPow[i] + EPS));
}
// 3.1 根据snr计算回声最终增益值
for (i = 0; i < 257; ++i) {
tmp1 = snrEchoEst[i];
tmp2 = tmp1 + 1;
gain[i] = tmp1 / tmp2;
gain[i] = min(gain[i], aec->gainMinLimit);
}
// 4. 倒谱消回声
// 分成0~4K低频做和4~8K
// cemp8k: 0~4K倒谱
// cemp16k: 4~8K倒谱
// errEst误差谱
// 先求倒谱
for (i = 0; i < 123; ++i) {
tmpPow[i] = errEst[2 * i] * errEst[2 * i] +
errEst[2 * i + 1] * errEst[2 * i + 1];
}
tmpPow = Log(tmpPow);
tmpPow[123] = 0;
for (i = 123; i >= 0; --i) {
tmpPow[2 * i ] = tmp[i];
tmpPow[2 * i + 1] = 0;
cemp16k[2 * i] = tmp[i];
cemp16k[2 * i + 1] = tmp[i];
}
cemp8k = IFFT(tmpPow);
// 倒谱平滑值
alpha[15] = [0, 0, 0, 0, 0, 0, 1, 0.4, 0.6, 0.8, 0.8, 0.85, 0.9, 0.95, 0.997]
for (i = 0; i < 15; ++i) {
smooth_cemp8k = SMOOTH(cemp8k, alpha[i]);
}
alpha1 = alpha[14];
for (i = 15; i < 123; ++i) {
smooth_cemp8k = SMOOTH(cemp8k, alpha1);
}
cempMod: // 原始倒谱值 [2k-4k]
cempModAmp: //平滑倒谱值 [0-2k]
for (i = 0; i < 123; ++i) {
tmp1 = cemp8k[i];
tmp2 = smooth_cemp8k[i];
cempMod = tmp1;
if (tmp1 > 0.36 && i >= 15) {
smooth_cemp8k[i] = 0;
tmp2 = tmp1 * 5;
}
cempMod[i] = tmp1;
cempModAmp[i] = tmp2;
}
cempMod = FFT(cempMod);
for (i = 0; i < 123 / 2; ++i) {
snr = exp(cempMod[2 * i]);
gain = snr / (echoEst + EPS);
}
cempModAmp = FFT(cempModAmp);
for (i = 123 / 2; i < 123; ++i) {
snr = exp(cempModAmp[2 * i]);
gain = snr / (echoEst + EPS);
}
// 5. 相干性计算
X: 远端频域数据
Y: 近端频域数据
errEst: 误差估计/残差信号
echoEst: 回声估计
X_power: 远端信号能量 X_power_smooth 能量平滑信号
Y_power: 近端信号能量
err_power: 误差信号能量
echo_power: 回声信号能量
corr_xy: 远近端互相关
corr_xerr: 远端和残差互相关
// cohxd
// a. 计算分母能量
for (i = 0; i < 257; ++i) {
X_power[i] = X[2 * i] * X[2 * i] + X[2 * i + 1] * X[2 * i + 1];
Y_power[i] = Y[2 * i] * Y[2 * i] + Y[2 * i + 1] * Y[2 * i + 1];
X_power_smooth[i] = 0.9 * X_power_smooth[i] + 0.1 * X_power[i];
}
// b. 互相关
for (i = 0; i < 257; ++i) {
corr_xy[2 * i] = X[2 * i] * Y[2 * i] + X[2 * i + 1] * Y[2 * i + 1];
corr_xy[2 * i + 1] = X[2 * i + 1] * Y[2 * i] - X[2 * i] * Y[2 * i + 1];
smooth_corr_xy[2 * i] = 0.1 * corr_xy[2 * i] + 0.9 * smooth_corr_xy[2 * i];
smooth_corr_xy[2 * i + 1] = 0.1 * corr_xy[2 * i + 1] + 0.9 * smooth_corr_xy[2 * i + 1]
}
// c. 计算相干性
for (i = 0; i < 257; ++i) {
tmp = smooth_corr_xy[2 * i] * smooth_corr_xy[2 * i] + smooth_corr_xy[2 * i + 1] * smooth_corr_xy[2 * i + 1];
cohxd[i] = tmp / (X_power_smooth[i] * Y_power_smooth[i] + EPS);
}
// d. 计算相干性ERL
for(i = 0; i < 257; ++i) {
coheec[i] = min(1, coheec[i]);
cohed[i] = min(1, cohed[i]);
cohERL[i] = coheec * (1 - cohed[i]); // 不做平滑
}
// 7. 根据cohxd, cohxe计算NLP增益
for (i = 0; i < 400Hz; ++i) {
gain = ((cohxd[i] - cohxe[i]) * 1.5 + 1.0) * cohxe[i];
gain = max(gain, cohxe[i]);
gain = min(gain, 0.95); // 0.95 不同频域设置不同值,频带越大设置越大
gain = 1 - gain;
}
// 8. NLMS步长更新
// errEst: 误差信号估计
// curErrPow:当前帧误差能量平滑值
// constErrPow: 0.98平滑系数的误差信号能量平滑值
// smoothErrPow: 0.85平滑系数的误差能量平滑值
// refPow: 参考信号能量
// FilterBlockNum: 滤波器块数
float mu = 0.1;
for (i = 0; i < 257; ++i) {
tmp1 = min(sqrt(constErrPow[i] / max(EPS, curErrPow[i])), 1);
tmp2 = refPow[i] * FilterBlockNum + smoothErrPow[i];
R = tmp1 * errEst[2 * i] / (tmp2 + EPS);
I = tmp1 * errEs[2 * i + 1] / (tmp2 + EPS);
alpha = 0.002f / max(sqrt(R * R + I * I), 0.002f);
R *= alpha;
I *= alpha;
step[2 * i] = mu * R;
step[2 * i + 1] = mu * I;
}
// 9. 基频检测
// mag: 幅度谱
for (i = 0; i < 257; ++i) {
cemp[i] = mag[2 * i] * mag[2 * i] + mag[2 * i + 1] * mag[2 * i + 1];
}
cemp = log(cemp);
for (i = 257; i >= 0; --i) {
cemp[2 * i] = cemp[i];
cemp[2 * i + 1] = 0;
}
cemp = IFFT(cemp)
L = Fs/400 - 1;
H = Fs / 70 - 1;
pitchId = -1;
for (L:H) {
if (cemp[i] >= 0.36) {
pitch = i;
break;
}
}
// 10. 能量求dB
// energy: 能量谱
// [L, H]: 求dB的能量谱范围
for (L: H) {
sumEnergy += energy[i];
}
coff = (H - L) * 0.5 * stft_size;
tmp = sumEnergy / coff;
dB = LOG(tmp) * 0.434294481903252;
dB = max(10 * dB, -20);
// 11. 根据cohxd, cohxe计算NLP增益
for (i = 0; i < 400Hz; ++i) {
gain = ((cohxd[i] - cohxe[i]) * 1.5 + 1.0) * cohxe[i];
gain = max(gain, cohxe[i]);
gain = min(gain, 0.95); // 0.95 不同频域设置不同值,频带越大设置越大
gain = 1 - gain;
}