Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: webrtc/modules/audio_processing/aec/aec_core.cc

Issue 1963493003: Moved the AEC echo suppression gain computation code to a separate method (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 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
(...skipping 967 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 memcpy(e_extended + PART_LEN, e, sizeof(float) * PART_LEN); 978 memcpy(e_extended + PART_LEN, e, sizeof(float) * PART_LEN);
979 Fft(e_extended, e_fft); 979 Fft(e_extended, e_fft);
980 980
981 // Scale error signal inversely with far power. 981 // Scale error signal inversely with far power.
982 WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft); 982 WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft);
983 WebRtcAec_FilterAdaptation(num_partitions, *x_fft_buf_block_pos, x_fft_buf, 983 WebRtcAec_FilterAdaptation(num_partitions, *x_fft_buf_block_pos, x_fft_buf,
984 e_fft, h_fft_buf); 984 e_fft, h_fft_buf);
985 memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN); 985 memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN);
986 } 986 }
987 987
988 static void EchoSuppression(AecCore* aec, 988 static void FormSuppressionGain(AecCore* aec,
989 float farend[PART_LEN2], 989 float cohde[PART_LEN1],
990 float* echo_subtractor_output, 990 float cohxd[PART_LEN1],
991 float* output, 991 float hNl[PART_LEN1]) {
992 float* const* outputH) {
993 float efw[2][PART_LEN1];
994 float xfw[2][PART_LEN1];
995 float dfw[2][PART_LEN1];
996 float comfortNoiseHband[2][PART_LEN1];
997 float fft[PART_LEN2];
998 float nlpGainHband;
999 int i;
1000 size_t j;
1001
1002 // Coherence and non-linear filter
1003 float cohde[PART_LEN1], cohxd[PART_LEN1];
1004 float hNlDeAvg, hNlXdAvg; 992 float hNlDeAvg, hNlXdAvg;
1005 float hNl[PART_LEN1];
1006 float hNlPref[kPrefBandSize]; 993 float hNlPref[kPrefBandSize];
1007 float hNlFb = 0, hNlFbLow = 0; 994 float hNlFb = 0, hNlFbLow = 0;
995 const int prefBandSize = kPrefBandSize / aec->mult;
1008 const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f; 996 const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f;
1009 const int prefBandSize = kPrefBandSize / aec->mult;
1010 const int minPrefBand = 4 / aec->mult; 997 const int minPrefBand = 4 / aec->mult;
1011 // Power estimate smoothing coefficients. 998 // Power estimate smoothing coefficients.
1012 const float* min_overdrive = aec->extended_filter_enabled 999 const float* min_overdrive = aec->extended_filter_enabled
1013 ? kExtendedMinOverDrive 1000 ? kExtendedMinOverDrive
1014 : kNormalMinOverDrive; 1001 : kNormalMinOverDrive;
1015 1002
1016 // Filter energy
1017 const int delayEstInterval = 10 * aec->mult;
1018
1019 float* xfw_ptr = NULL;
1020
1021 // Update eBuf with echo subtractor output.
1022 memcpy(aec->eBuf + PART_LEN, echo_subtractor_output,
1023 sizeof(float) * PART_LEN);
1024
1025 // Analysis filter banks for the echo suppressor.
1026 // Windowed near-end ffts.
1027 WindowData(fft, aec->dBuf);
1028 aec_rdft_forward_128(fft);
1029 StoreAsComplex(fft, dfw);
1030
1031 // Windowed echo suppressor output ffts.
1032 WindowData(fft, aec->eBuf);
1033 aec_rdft_forward_128(fft);
1034 StoreAsComplex(fft, efw);
1035
1036 // NLP
1037
1038 // Convert far-end partition to the frequency domain with windowing.
1039 WindowData(fft, farend);
1040 Fft(fft, xfw);
1041 xfw_ptr = &xfw[0][0];
1042
1043 // Buffer far.
1044 memcpy(aec->xfwBuf, xfw_ptr, sizeof(float) * 2 * PART_LEN1);
1045
1046 aec->delayEstCtr++;
1047 if (aec->delayEstCtr == delayEstInterval) {
1048 aec->delayEstCtr = 0;
1049 aec->delayIdx = WebRtcAec_PartitionDelay(aec->num_partitions, aec->wfBuf);
1050 }
1051
1052 // Use delayed far.
1053 memcpy(xfw, aec->xfwBuf + aec->delayIdx * PART_LEN1,
1054 sizeof(xfw[0][0]) * 2 * PART_LEN1);
1055
1056 WebRtcAec_UpdateCoherenceSpectra(aec->mult, aec->extended_filter_enabled == 1,
1057 efw, dfw, xfw, &aec->coherence_state,
1058 &aec->divergeState,
1059 &aec->extreme_filter_divergence);
1060
1061 WebRtcAec_ComputeCoherence(&aec->coherence_state, cohde, cohxd);
1062
1063 // Select the microphone signal as output if the filter is deemed to have
1064 // diverged.
1065 if (aec->divergeState) {
1066 memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
1067 }
1068
1069 hNlXdAvg = 0; 1003 hNlXdAvg = 0;
1070 for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) { 1004 for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
1071 hNlXdAvg += cohxd[i]; 1005 hNlXdAvg += cohxd[i];
1072 } 1006 }
1073 hNlXdAvg /= prefBandSize; 1007 hNlXdAvg /= prefBandSize;
1074 hNlXdAvg = 1 - hNlXdAvg; 1008 hNlXdAvg = 1 - hNlXdAvg;
1075 1009
1076 hNlDeAvg = 0; 1010 hNlDeAvg = 0;
1077 for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) { 1011 for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
1078 hNlDeAvg += cohde[i]; 1012 hNlDeAvg += cohde[i];
1079 } 1013 }
1080 hNlDeAvg /= prefBandSize; 1014 hNlDeAvg /= prefBandSize;
1081 1015
1082 if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) { 1016 if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) {
1083 aec->hNlXdAvgMin = hNlXdAvg; 1017 aec->hNlXdAvgMin = hNlXdAvg;
1084 } 1018 }
1085 1019
1086 if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) { 1020 if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) {
1087 aec->stNearState = 1; 1021 aec->stNearState = 1;
1088 } else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) { 1022 } else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) {
1089 aec->stNearState = 0; 1023 aec->stNearState = 0;
1090 } 1024 }
1091 1025
1092 if (aec->hNlXdAvgMin == 1) { 1026 if (aec->hNlXdAvgMin == 1) {
1093 aec->echoState = 0; 1027 aec->echoState = 0;
1094 aec->overDrive = min_overdrive[aec->nlp_mode]; 1028 aec->overDrive = min_overdrive[aec->nlp_mode];
1095 1029
1096 if (aec->stNearState == 1) { 1030 if (aec->stNearState == 1) {
1097 memcpy(hNl, cohde, sizeof(hNl)); 1031 memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
ivoc 2016/05/12 10:42:43 Is this better than sizeof(hNl), or does that not
peah-webrtc 2016/05/12 11:07:50 No, I would have preferred the previous way to do
ivoc 2016/05/12 11:19:39 I see, that makes sense, thanks.
kwiberg-webrtc 2016/05/12 11:29:58 It'll work if you pass a reference to the array as
peah-webrtc 2016/05/13 04:05:47 Thanks! The ::copy approach is definitely much nic
kwiberg-webrtc 2016/05/13 06:23:09 Do note that while it's specialized for trivial ty
1098 hNlFb = hNlDeAvg; 1032 hNlFb = hNlDeAvg;
1099 hNlFbLow = hNlDeAvg; 1033 hNlFbLow = hNlDeAvg;
1100 } else { 1034 } else {
1101 for (i = 0; i < PART_LEN1; i++) { 1035 for (int i = 0; i < PART_LEN1; ++i) {
1102 hNl[i] = 1 - cohxd[i]; 1036 hNl[i] = 1 - cohxd[i];
1103 } 1037 }
1104 hNlFb = hNlXdAvg; 1038 hNlFb = hNlXdAvg;
1105 hNlFbLow = hNlXdAvg; 1039 hNlFbLow = hNlXdAvg;
1106 } 1040 }
1107 } else { 1041 } else {
1108 if (aec->stNearState == 1) { 1042 if (aec->stNearState == 1) {
1109 aec->echoState = 0; 1043 aec->echoState = 0;
1110 memcpy(hNl, cohde, sizeof(hNl)); 1044 memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
1111 hNlFb = hNlDeAvg; 1045 hNlFb = hNlDeAvg;
1112 hNlFbLow = hNlDeAvg; 1046 hNlFbLow = hNlDeAvg;
1113 } else { 1047 } else {
1114 aec->echoState = 1; 1048 aec->echoState = 1;
1115 for (i = 0; i < PART_LEN1; i++) { 1049 for (int i = 0; i < PART_LEN1; ++i) {
1116 hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]); 1050 hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]);
1117 } 1051 }
1118 1052
1119 // Select an order statistic from the preferred bands. 1053 // Select an order statistic from the preferred bands.
1120 // TODO(peah): Using quicksort now, but a selection algorithm may be 1054 // TODO(peah): Using quicksort now, but a selection algorithm may be
1121 // preferred. 1055 // preferred.
1122 memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize); 1056 memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize);
1123 qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat); 1057 qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat);
1124 hNlFb = hNlPref[static_cast<int>(floor(prefBandQuant * 1058 hNlFb = hNlPref[static_cast<int>(floor(prefBandQuant *
1125 (prefBandSize - 1)))]; 1059 (prefBandSize - 1)))];
(...skipping 27 matching lines...) Expand all
1153 1087
1154 // Smooth the overdrive. 1088 // Smooth the overdrive.
1155 if (aec->overDrive < aec->overdrive_scaling) { 1089 if (aec->overDrive < aec->overdrive_scaling) {
1156 aec->overdrive_scaling = 1090 aec->overdrive_scaling =
1157 0.99f * aec->overdrive_scaling + 0.01f * aec->overDrive; 1091 0.99f * aec->overdrive_scaling + 0.01f * aec->overDrive;
1158 } else { 1092 } else {
1159 aec->overdrive_scaling = 1093 aec->overdrive_scaling =
1160 0.9f * aec->overdrive_scaling + 0.1f * aec->overDrive; 1094 0.9f * aec->overdrive_scaling + 0.1f * aec->overDrive;
1161 } 1095 }
1162 1096
1097 // Apply the overdrive.
1163 WebRtcAec_Overdrive(aec->overdrive_scaling, hNlFb, hNl); 1098 WebRtcAec_Overdrive(aec->overdrive_scaling, hNlFb, hNl);
1099 }
1100
1101 static void EchoSuppression(AecCore* aec,
1102 float farend[PART_LEN2],
1103 float* echo_subtractor_output,
1104 float* output,
1105 float* const* outputH) {
1106 float efw[2][PART_LEN1];
1107 float xfw[2][PART_LEN1];
1108 float dfw[2][PART_LEN1];
1109 float comfortNoiseHband[2][PART_LEN1];
1110 float fft[PART_LEN2];
1111 float nlpGainHband;
1112 int i;
1113 size_t j;
1114
1115 // Coherence and non-linear filter
1116 float cohde[PART_LEN1], cohxd[PART_LEN1];
1117 float hNl[PART_LEN1];
1118
1119 // Filter energy
1120 const int delayEstInterval = 10 * aec->mult;
1121
1122 float* xfw_ptr = NULL;
1123
1124 // Update eBuf with echo subtractor output.
1125 memcpy(aec->eBuf + PART_LEN, echo_subtractor_output,
1126 sizeof(float) * PART_LEN);
1127
1128 // Analysis filter banks for the echo suppressor.
1129 // Windowed near-end ffts.
1130 WindowData(fft, aec->dBuf);
1131 aec_rdft_forward_128(fft);
1132 StoreAsComplex(fft, dfw);
1133
1134 // Windowed echo suppressor output ffts.
1135 WindowData(fft, aec->eBuf);
1136 aec_rdft_forward_128(fft);
1137 StoreAsComplex(fft, efw);
1138
1139 // NLP
1140
1141 // Convert far-end partition to the frequency domain with windowing.
1142 WindowData(fft, farend);
1143 Fft(fft, xfw);
1144 xfw_ptr = &xfw[0][0];
1145
1146 // Buffer far.
1147 memcpy(aec->xfwBuf, xfw_ptr, sizeof(float) * 2 * PART_LEN1);
1148
1149 aec->delayEstCtr++;
1150 if (aec->delayEstCtr == delayEstInterval) {
1151 aec->delayEstCtr = 0;
1152 aec->delayIdx = WebRtcAec_PartitionDelay(aec->num_partitions, aec->wfBuf);
1153 }
1154
1155 // Use delayed far.
1156 memcpy(xfw, aec->xfwBuf + aec->delayIdx * PART_LEN1,
1157 sizeof(xfw[0][0]) * 2 * PART_LEN1);
1158
1159 WebRtcAec_UpdateCoherenceSpectra(aec->mult, aec->extended_filter_enabled == 1,
1160 efw, dfw, xfw, &aec->coherence_state,
1161 &aec->divergeState,
1162 &aec->extreme_filter_divergence);
1163
1164 WebRtcAec_ComputeCoherence(&aec->coherence_state, cohde, cohxd);
1165
1166 // Select the microphone signal as output if the filter is deemed to have
1167 // diverged.
1168 if (aec->divergeState) {
1169 memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
1170 }
1171
1172 FormSuppressionGain(aec, cohde, cohxd, hNl);
1173
1164 WebRtcAec_Suppress(hNl, efw); 1174 WebRtcAec_Suppress(hNl, efw);
1165 1175
1166 // Add comfort noise. 1176 // Add comfort noise.
1167 ComfortNoise(aec, efw, comfortNoiseHband, aec->noisePow, hNl); 1177 ComfortNoise(aec, efw, comfortNoiseHband, aec->noisePow, hNl);
1168 1178
1169 // Inverse error fft. 1179 // Inverse error fft.
1170 ScaledInverseFft(efw, fft, 2.0f, 1); 1180 ScaledInverseFft(efw, fft, 2.0f, 1);
1171 1181
1172 // Overlap and add to obtain output. 1182 // Overlap and add to obtain output.
1173 for (i = 0; i < PART_LEN; i++) { 1183 for (i = 0; i < PART_LEN; i++) {
(...skipping 782 matching lines...) Expand 10 before | Expand all | Expand 10 after
1956 1966
1957 int WebRtcAec_system_delay(AecCore* self) { 1967 int WebRtcAec_system_delay(AecCore* self) {
1958 return self->system_delay; 1968 return self->system_delay;
1959 } 1969 }
1960 1970
1961 void WebRtcAec_SetSystemDelay(AecCore* self, int delay) { 1971 void WebRtcAec_SetSystemDelay(AecCore* self, int delay) {
1962 assert(delay >= 0); 1972 assert(delay >= 0);
1963 self->system_delay = delay; 1973 self->system_delay = delay;
1964 } 1974 }
1965 } // namespace webrtc 1975 } // namespace webrtc
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698