41#include "MDFEchoCancellationConfig.h"
42#include "AudioTools/AudioLibs/AudioFFT.h"
45#define ECHO_GET_FRAME_SIZE 3
46#define ECHO_SET_SAMPLING_RATE 24
47#define ECHO_GET_SAMPLING_RATE 25
48#define ECHO_GET_IMPULSE_RESPONSE_SIZE 27
49#define ECHO_GET_IMPULSE_RESPONSE 29
53#define PSEUDOFLOAT(x) (x)
54#define FLOAT_MULT(a, b) ((a) * (b))
55#define FLOAT_AMULT(a, b) ((a) * (b))
56#define FLOAT_MUL32(a, b) ((a) * (b))
57#define FLOAT_DIV32(a, b) ((a) / (b))
58#define FLOAT_EXTRACT16(a) (a)
59#define FLOAT_EXTRACT32(a) (a)
60#define FLOAT_ADD(a, b) ((a) + (b))
61#define FLOAT_SUB(a, b) ((a) - (b))
62#define FLOAT_DIV32_FLOAT(a, b) ((a) / (b))
63#define FLOAT_MUL32U(a, b) ((a) * (b))
64#define FLOAT_SHL(a, b) (a)
65#define FLOAT_LT(a, b) ((a) < (b))
66#define FLOAT_GT(a, b) ((a) > (b))
67#define FLOAT_DIVU(a, b) ((a) / (b))
68#define FLOAT_SQRT(a) (sqrtf(a))
71#define ABS(x) (((x) < 0) ? (-(x)) : (x))
72#define ABS16(x) (((x) < 0) ? (-(x)) : (x))
73#define ABS32(x) (((x) < 0) ? (-(x)) : (x))
74#define MIN16(a, b) ((a) < (b) ? (a) : (b))
75#define MAX16(a, b) ((a) > (b) ? (a) : (b))
76#define MIN32(a, b) ((a) < (b) ? (a) : (b))
77#define MAX32(a, b) ((a) > (b) ? (a) : (b))
79#define QCONST16(x, bits) (x)
80#define QCONST32(x, bits) (x)
81#define NEG16(x) (-(x))
82#define NEG32(x) (-(x))
83#define EXTRACT16(x) (x)
84#define EXTEND32(x) (x)
85#define SHR16(a, shift) (a)
86#define SHL16(a, shift) (a)
87#define SHR32(a, shift) (a)
88#define SHL32(a, shift) (a)
89#define PSHR16(a, shift) (a)
90#define PSHR32(a, shift) (a)
91#define VSHR32(a, shift) (a)
92#define SATURATE16(x, a) (x)
93#define SATURATE32(x, a) (x)
94#define ADD16(a, b) ((a) + (b))
95#define SUB16(a, b) ((a) - (b))
96#define ADD32(a, b) ((a) + (b))
97#define SUB32(a, b) ((a) - (b))
98#define MULT16_16(a, b) ((echo_word32_t)(a) * (echo_word32_t)(b))
99#define MAC16_16(c, a, b) ((c) + (echo_word32_t)(a) * (echo_word32_t)(b))
100#define MULT16_32_Q15(a, b) ((a) * (b))
101#define MULT16_16_P15(a, b) ((a) * (b))
102#define MULT16_32_P15(a, b) ((a) * (b))
103#define MULT16_16_Q15(a, b) ((a) * (b))
104#define DIV32_16(a, b) (((echo_word32_t)(a)) / (echo_word16_t)(b))
105#define DIV32(a, b) (((echo_word32_t)(a)) / (echo_word32_t)(b))
109 : ((x) > 32766.5f ? 32767 : (echo_int16_t)floorf(.5f + (x))))
110#define MULT16_16_Q14(a, b) ((a) * (b))
111#define MULT16_16_Q13(a, b) ((a) * (b))
112#define MULT16_16_P13(a, b) ((a) * (b))
113#define MULT16_16_P14(a, b) ((a) * (b))
114#define MULT16_32_Q14(a, b) ((a) * (b))
115#define MAC16_32_Q15(c, a, b) ((c) + (a) * (b))
118#define WEIGHT_SHIFT 0
122#define PSEUDOFLOAT(x) (echo_float_from_double(x))
123#define FLOAT_MULT(a, b) (echo_float_mult(a, b))
124#define FLOAT_MUL32U(a, b) (echo_float_mul32_u(a, b))
125#define FLOAT_ADD(a, b) (echo_float_add(a, b))
126#define FLOAT_SUB(a, b) (echo_float_sub(a, b))
127#define FLOAT_LT(a, b) (echo_float_lt(a, b))
128#define FLOAT_GT(a, b) (echo_float_gt(a, b))
129#define FLOAT_DIVU(a, b) (echo_float_divu(a, b))
130#define FLOAT_SQRT(a) (echo_float_sqrt(a))
131#define FLOAT_EXTRACT16(a) (echo_float_extract16(a))
132#define FLOAT_SHL(a, b) (echo_float_shl(a, b))
135#define ABS(x) (((x) < 0) ? (-(x)) : (x))
136#define ABS16(x) (((x) < 0) ? (-(x)) : (x))
137#define ABS32(x) (((x) < 0) ? (-(x)) : (x))
138#define MIN16(a, b) ((a) < (b) ? (a) : (b))
139#define MAX16(a, b) ((a) > (b) ? (a) : (b))
140#define MIN32(a, b) ((a) < (b) ? (a) : (b))
141#define MAX32(a, b) ((a) > (b) ? (a) : (b))
146 : ((x) > 32766.5f ? 32767 : (echo_int16_t)floorf(.5f + (x))))
149#define WEIGHT_SHIFT 0
157typedef int16_t echo_int16_t;
158typedef uint16_t echo_uint16_t;
159typedef int32_t echo_int32_t;
160typedef uint32_t echo_uint32_t;
162typedef echo_int16_t echo_word16_t;
163typedef echo_int32_t echo_word32_t;
164typedef echo_word32_t echo_mem_t;
169inline echo_float_t echo_float_mult(echo_float_t a, echo_float_t b);
170inline echo_float_t echo_float_mul32_u(
float a,
float b);
178 constexpr echo_float_t(int16_t mantissa = 0, int16_t exponent = 0)
179 : m(mantissa), e(exponent) {}
183 return echo_float_mult(*
this, other);
186 inline echo_word32_t operator*(int16_t scalar)
const {
188 int32_t result = ((int32_t)m * scalar);
190 return result << (e - 14);
192 return result >> (14 - e);
196 inline echo_word32_t operator*(int32_t scalar)
const {
198 int64_t result = ((int64_t)m * scalar);
200 return result << (e - 14);
202 return result >> (14 - e);
206 friend inline echo_word32_t operator*(int32_t scalar,
const echo_float_t& f) {
220 while (x >= 32768) { x *= 0.5; e++; }
221 while (x < 16384) { x *= 2.0; e--; }
227inline echo_float_t echo_float_mult(echo_float_t a, echo_float_t b) {
229 r.m = (int16_t)((((int32_t)a.m) * b.m) >> 15);
230 r.e = a.e + b.e + 15;
232 while (r.m < 16384) { r.m <<= 1; r.e--; }
237inline echo_float_t echo_float_mul32_u(
float a,
float b) {
238 return echo_float_from_double(a * b);
241inline echo_float_t echo_float_add(echo_float_t a, echo_float_t b) {
243 int shift = a.e - b.e;
244 if (shift > 15)
return a;
245 echo_float_t r = {(int16_t)(a.m + (b.m >> shift)), a.e};
248 int shift = b.e - a.e;
249 if (shift > 15)
return b;
250 echo_float_t r = {(int16_t)((a.m >> shift) + b.m), b.e};
255inline echo_float_t echo_float_sub(echo_float_t a, echo_float_t b) {
257 int shift = a.e - b.e;
258 if (shift > 15)
return a;
259 echo_float_t r = {(int16_t)(a.m - (b.m >> shift)), a.e};
262 int shift = b.e - a.e;
264 echo_float_t r = {(int16_t)(-b.m), b.e};
267 echo_float_t r = {(int16_t)((a.m >> shift) - b.m), b.e};
272inline bool echo_float_lt(echo_float_t a, echo_float_t b) {
273 if (a.e != b.e)
return a.e < b.e;
277inline bool echo_float_gt(echo_float_t a, echo_float_t b) {
278 if (a.e != b.e)
return a.e > b.e;
282inline echo_float_t echo_float_divu(echo_float_t a, echo_float_t b) {
289 r.m = (int16_t)((((int32_t)a.m) << 15) / b.m);
290 r.e = a.e - b.e - 15;
292 while (r.m < 16384) { r.m <<= 1; r.e--; }
297inline echo_float_t echo_float_sqrt(echo_float_t x) {
298 double val = x.m * pow(2.0, x.e - 14);
299 return echo_float_from_double(sqrt(val));
302inline int16_t echo_float_extract16(echo_float_t x) {
304 return x.m << (x.e > 15 ? 15 : x.e);
306 return x.m >> (-x.e > 15 ? 15 : -x.e);
310inline echo_float_t echo_float_shl(echo_float_t x,
int bits) {
311 echo_float_t r = {x.m, (int16_t)(x.e + bits)};
338static const float MIN_LEAK = 0.005f;
365typedef float echo_float_t;
390 echo_word16_t spec_average;
392 echo_word16_t beta_max;
393 echo_word32_t sum_adapt;
394 echo_word16_t leak_estimate;
399 echo_word16_t* input;
401 echo_word16_t* last_y;
407 echo_word16_t* foreground;
415 echo_word32_t* power;
425 echo_word16_t* window;
428 echo_word16_t *memX, *memD, *memE;
429 echo_word16_t preemph;
430 echo_word16_t notch_radius;
431 echo_mem_t* notch_mem;
433 echo_int16_t* play_buf;
435 int play_buf_started;
450template <
typename Allocator = std::allocator<u
int8_t>>
452 using FloatAllocator =
typename std::allocator_traits<Allocator>::template rebind_alloc<float>;
507template <
typename Allocator = std::allocator<u
int8_t>>
535 if (
state->fft_table) echo_fft_destroy<Allocator>(
state->fft_table);
575 void cancel(
const echo_int16_t* rec,
const echo_int16_t* play,
585 void capture(
const echo_int16_t* rec, echo_int16_t* out) {
587 state->play_buf_started = 1;
591 std::memmove(
state->play_buf,
593 state->play_buf_pos *
sizeof(echo_int16_t));
595 echoWarning(
"No playback frame available");
596 if (
state->play_buf_pos != 0) {
597 echoWarning(
"Internal playback buffer corruption");
598 state->play_buf_pos = 0;
609 if (!
state->play_buf_started) {
610 echoWarning(
"Discarded first playback frame");
615 state->play_buf[
state->play_buf_pos + i] = play[i];
618 echoWarning(
"Auto-filling buffer");
620 state->play_buf[
state->play_buf_pos + i] = play[i];
624 echoWarning(
"Had to discard playback frame");
631 int N =
state->window_size;
636 state->cancel_count = 0;
637 state->screwed_up = 0;
639 for (
int i = 0; i < N * M; i++)
state->W[i] = 0;
641 for (
int i = 0; i < N * M; i++)
state->foreground[i] = 0;
643 for (
int i = 0; i < N * (M + 1); i++)
state->X[i] = 0;
646 state->power_1[i] = FLOAT_ONE;
651 for (
int i = 0; i < N * C; i++)
state->E[i] = 0;
652 for (
int i = 0; i < N * K; i++)
state->x[i] = 0;
653 for (
int i = 0; i < 2 * C; i++)
state->notch_mem[i] = 0;
654 for (
int i = 0; i < C; i++)
state->memD[i] =
state->memE[i] = 0;
655 for (
int i = 0; i < K; i++)
state->memX[i] = 0;
657 state->saturated = 0;
659 state->sum_adapt = 0;
667 state->play_buf_started = 0;
677 case ECHO_GET_FRAME_SIZE:
680 case ECHO_SET_SAMPLING_RATE:
686 state->notch_radius = .9f;
688 state->notch_radius = .982f;
690 state->notch_radius = .992f;
692 case ECHO_GET_SAMPLING_RATE:
695 case ECHO_GET_IMPULSE_RESPONSE_SIZE:
698 case ECHO_GET_IMPULSE_RESPONSE: {
700 echo_int32_t* filt = (echo_int32_t*)ptr;
701 for (
int j = 0; j < M; j++) {
703 for (
int i = 0; i < n; i++) filt[j * n + i] = 32767 *
state->wtmp[i];
730 control(ECHO_GET_IMPULSE_RESPONSE, response);
738 echoWarning(
"Cannot change filter length after initialization");
752 echoWarning(
"Cannot change mic channels after initialization");
766 echoWarning(
"Cannot change speaker channels after initialization");
780 echoWarning(
"Cannot change FFT driver after initialization");
820 template <
typename T>
822 typename std::allocator_traits<Allocator>::template rebind_alloc<T> alloc(
allocator);
823 T* ptr = alloc.allocate(count);
825 for (
size_t i = 0; i < count; ++i) {
826 std::allocator_traits<typename std::allocator_traits<Allocator>::template rebind_alloc<T>>::construct(alloc, ptr + i);
838 template <
typename T>
841 typename std::allocator_traits<Allocator>::template rebind_alloc<T> alloc(
allocator);
844 alloc.deallocate(ptr, count);
848 inline void echoWarning(
const char* str) {
849 LOGW(
"EchoCanceller Warning: %s", str);
852 inline void echoFatal(
const char* str) {
853 LOGE(
"EchoCanceller Error: %s", str);
856 inline float spxSqrt(
float x) {
return sqrtf(x); }
858 inline echo_int16_t spxIlog2(echo_uint32_t x) {
860 if (x >= (echo_int32_t)65536) {
887 inline float spxExp(
float x) {
return expf(x); }
894 inline float spxCos(
float x) {
return cosf(x); }
906 echo_word16_t* out,
int len, echo_mem_t* mem,
908 echo_word16_t den2 = radius * radius + .7f * (1 - radius) * (1 - radius);
909 for (
int i = 0; i < len; i++) {
910 echo_word16_t vin = in[i * stride];
911 echo_word32_t vout = mem[0] + vin;
912 mem[0] = mem[1] + 2 * (-vin + radius * vout);
913 mem[1] = vin - den2 * vout;
914 out[i] = radius * vout;
925 inline echo_word32_t
mdfInnerProd(
const echo_word16_t* x,
const echo_word16_t* y,
928 for (
int i = 0; i < len; i++) {
940 inline void powerSpectrum(
const echo_word16_t* X, echo_word32_t* ps,
int N) {
942 for (
int i = 1, j = 1; i < N - 1; i += 2, j++) {
943 ps[j] = X[i] * X[i] + X[i + 1] * X[i + 1];
945 ps[N / 2] = X[N - 1] * X[N - 1];
956 ps[0] += X[0] * X[0];
957 for (
int i = 1, j = 1; i < N - 1; i += 2, j++) {
958 ps[j] += X[i] * X[i] + X[i + 1] * X[i + 1];
960 ps[N / 2] += X[N - 1] * X[N - 1];
972 echo_word16_t* acc,
int N,
int M) {
973 for (
int i = 0; i < N; i++) acc[i] = 0;
975 for (
int j = 0; j < M; j++) {
976 acc[0] += X[0] * Y[0];
977 for (
int i = 1; i < N - 1; i += 2) {
978 acc[i] += (X[i] * Y[i] - X[i + 1] * Y[i + 1]);
979 acc[i + 1] += (X[i + 1] * Y[i] + X[i] * Y[i + 1]);
981 acc[N - 1] += X[N - 1] * Y[N - 1];
997 const echo_word16_t* X,
998 const echo_word16_t* Y, echo_word32_t* prod,
1002 prod[0] = W * ((int32_t)X[0] * Y[0]);
1003 for (
int i = 1, j = 1; i < N - 1; i += 2, j++) {
1005 prod[i] = W * ((int32_t)(X[i] * Y[i] + X[i + 1] * Y[i + 1]));
1006 prod[i + 1] = W * ((int32_t)(-X[i + 1] * Y[i] + X[i] * Y[i + 1]));
1009 prod[N - 1] = W * ((int32_t)X[N - 1] * Y[N - 1]);
1021 echo_word16_t* prop) {
1022 echo_word16_t max_sum = 1;
1023 echo_word32_t prop_sum = 1;
1025 for (
int i = 0; i < M; i++) {
1026 echo_word32_t tmp = 1;
1027 for (
int p = 0; p < P; p++) {
1028 for (
int j = 0; j < N; j++) {
1029 float val = W[p * N * M + i * N + j];
1033 prop[i] = spxSqrt(tmp);
1034 if (prop[i] > max_sum) max_sum = prop[i];
1037 for (
int i = 0; i < M; i++) {
1038 prop[i] += 0.1f * max_sum;
1039 prop_sum += prop[i];
1042 for (
int i = 0; i < M; i++) {
1043 prop[i] = 0.99f * prop[i] / prop_sum;
1057 int N = frame_size * 2;
1063 if (!st)
return nullptr;
1068 st->window_size = N;
1070 st->cancel_count = 0;
1078 st->leak_estimate = 0;
1081 st->e = echoAlloc<echo_word16_t>(C * N);
1082 st->x = echoAlloc<echo_word16_t>(K * N);
1083 st->input = echoAlloc<echo_word16_t>(C * st->
frame_size);
1084 st->y = echoAlloc<echo_word16_t>(C * N);
1085 st->last_y = echoAlloc<echo_word16_t>(C * N);
1086 st->Yf = echoAlloc<echo_word32_t>(st->
frame_size + 1);
1087 st->Rf = echoAlloc<echo_word32_t>(st->
frame_size + 1);
1088 st->Xf = echoAlloc<echo_word32_t>(st->
frame_size + 1);
1089 st->Yh = echoAlloc<echo_word32_t>(st->
frame_size + 1);
1090 st->Eh = echoAlloc<echo_word32_t>(st->
frame_size + 1);
1091 st->X = echoAlloc<echo_word16_t>(K * (M + 1) * N);
1092 st->Y = echoAlloc<echo_word16_t>(C * N);
1093 st->E = echoAlloc<echo_word16_t>(C * N);
1094 st->W = echoAlloc<echo_word32_t>(C * K * M * N);
1097 st->foreground = echoAlloc<echo_word16_t>(M * N * C * K);
1100 st->PHI = echoAlloc<echo_word32_t>(N);
1101 st->power = echoAlloc<echo_word32_t>(frame_size + 1);
1102 st->power_1 = echoAlloc<echo_float_t>(frame_size + 1);
1103 st->window = echoAlloc<echo_word16_t>(N);
1104 st->prop = echoAlloc<echo_word16_t>(M);
1105 st->wtmp = echoAlloc<echo_word16_t>(N);
1108 for (
int i = 0; i < N; i++)
1109 st->window[i] = .5f - .5f * cosf(2 * M_PI * i / N);
1112 for (
int i = 0; i <= st->
frame_size; i++) st->power_1[i] = FLOAT_ONE;
1115 for (
int i = 0; i < N * M * K * C; i++) st->W[i] = 0;
1119 echo_word32_t sum = 0;
1120 float decay = expf(-2.4f / M);
1123 for (
int i = 1; i < M; i++) {
1124 st->prop[i] = st->prop[i - 1] * decay;
1127 for (
int i = M - 1; i >= 0; i--) {
1128 st->prop[i] = .8f * st->prop[i] / sum;
1132 st->memX = echoAlloc<echo_word16_t>(K);
1133 st->memD = echoAlloc<echo_word16_t>(C);
1134 st->memE = echoAlloc<echo_word16_t>(C);
1138 st->notch_radius = .9f;
1140 st->notch_radius = .982f;
1142 st->notch_radius = .992f;
1144 st->notch_mem = echoAlloc<echo_mem_t>(2 * C);
1146 st->Pey = st->Pyy = FLOAT_ONE;
1149 st->Davg1 = st->Davg2 = 0;
1150 st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
1154 echoAlloc<echo_int16_t>(K * (PLAYBACK_DELAY + 1) * st->
frame_size);
1155 st->play_buf_pos = PLAYBACK_DELAY * st->
frame_size;
1156 st->play_buf_started = 0;
1158 st->fft_table =
nullptr;
1180 const echo_int16_t* far_end,
1181 echo_int16_t* out) {
1182 int N = st->window_size;
1188 float ss = .35f / M;
1189 float ss_1 = 1 - ss;
1192 for (
int chan = 0; chan < C; chan++) {
1195 st->notch_mem + 2 * chan, C);
1198 echo_word32_t tmp32 =
1199 st->input[chan * st->
frame_size + i] - st->preemph * st->memD[chan];
1200 st->memD[chan] = st->input[chan * st->
frame_size + i];
1201 st->input[chan * st->
frame_size + i] = tmp32;
1206 for (
int speak = 0; speak < K; speak++) {
1207 std::memmove(&st->x[speak * N],
1211 echo_word32_t tmp32 =
1212 far_end[i * K + speak] - st->preemph * st->memX[speak];
1213 st->x[speak * N + i + st->
frame_size] = tmp32;
1214 st->memX[speak] = far_end[i * K + speak];
1219 for (
int speak = 0; speak < K; speak++) {
1220 for (
int j = M - 1; j >= 0; j--) {
1221 std::memmove(&st->X[(j + 1) * N * K + speak * N],
1222 &st->X[j * N * K + speak * N],
1223 N *
sizeof(echo_word16_t));
1225 echo_fft<Allocator>(st->fft_table, st->x + speak * N, &st->X[speak * N]);
1229 echo_word32_t Sxx = 0;
1230 for (
int speak = 0; speak < K; speak++) {
1237 echo_word32_t Sff = 0;
1238 for (
int chan = 0; chan < C; chan++) {
1241 st->Y + chan * N, N, M * K);
1242 echo_ifft<Allocator>(st->fft_table, st->Y + chan * N, st->e + chan * N);
1244 st->e[chan * N + i] = st->input[chan * st->
frame_size + i] -
1251 if (st->adapted)
mdfAdjustProp(st->W, N, M, C * K, st->prop);
1254 if (st->saturated == 0) {
1255 for (
int chan = 0; chan < C; chan++) {
1256 for (
int speak = 0; speak < K; speak++) {
1257 for (
int j = M - 1; j >= 0; j--) {
1259 &st->X[(j + 1) * N * K + speak * N],
1260 st->E + chan * N, st->PHI, N);
1261 for (
int i = 0; i < N; i++)
1262 st->W[chan * N * K * M + j * N * K + speak * N + i] += st->PHI[i];
1271 for (
int chan = 0; chan < C; chan++) {
1272 for (
int speak = 0; speak < K; speak++) {
1273 for (
int j = 0; j < M; j++) {
1274 if (j == 0 || st->cancel_count % (M - 1) == j - 1) {
1275 echo_ifft<Allocator>(
1276 st->fft_table, &st->W[chan * N * K * M + j * N * K + speak * N],
1278 for (
int i = st->
frame_size; i < N; i++) st->wtmp[i] = 0;
1279 echo_fft<Allocator>(
1280 st->fft_table, st->wtmp,
1281 &st->W[chan * N * K * M + j * N * K + speak * N]);
1289 st->Rf[i] = st->Yf[i] = st->Xf[i] = 0;
1291 echo_word32_t Dbf = 0;
1292 echo_word32_t See = 0;
1296 for (
int chan = 0; chan < C; chan++) {
1299 echo_ifft<Allocator>(st->fft_table, st->Y + chan * N, st->y + chan * N);
1301 st->e[chan * N + i] = st->e[chan * N + i + st->
frame_size] -
1306 st->e[chan * N + i] = st->input[chan * st->
frame_size + i] -
1318 st->Davg1 = .6f * st->Davg1 + .4f * (Sff - See);
1319 st->Davg2 = .85f * st->Davg2 + .15f * (Sff - See);
1320 st->Dvar1 = FLOAT_ADD(FLOAT_MULT(
VAR1_SMOOTH, st->Dvar1),
1321 FLOAT_MUL32U(.4f * Sff, .4f * Dbf));
1322 st->Dvar2 = FLOAT_ADD(FLOAT_MULT(
VAR2_SMOOTH, st->Dvar2),
1323 FLOAT_MUL32U(.15f * Sff, .15f * Dbf));
1325 int update_foreground = 0;
1326 if (FLOAT_GT(FLOAT_MUL32U(Sff - See, fabsf(Sff - See)),
1327 FLOAT_MUL32U(Sff, Dbf)))
1328 update_foreground = 1;
1329 else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, fabsf(st->Davg1)),
1331 update_foreground = 1;
1332 else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, fabsf(st->Davg2)),
1334 update_foreground = 1;
1336 if (update_foreground) {
1337 st->Davg1 = st->Davg2 = 0;
1338 st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
1339 std::memcpy(st->foreground, st->W, N * M * C * K *
sizeof(echo_word16_t));
1340 for (
int chan = 0; chan < C; chan++)
1345 st->window[i] * st->y[chan * N + i + st->
frame_size];
1347 int reset_background = 0;
1348 if (FLOAT_GT(FLOAT_MUL32U(-(Sff - See), fabsf(Sff - See)),
1350 reset_background = 1;
1351 if (FLOAT_GT(FLOAT_MUL32U(-st->Davg1, fabsf(st->Davg1)),
1353 reset_background = 1;
1354 if (FLOAT_GT(FLOAT_MUL32U(-st->Davg2, fabsf(st->Davg2)),
1356 reset_background = 1;
1358 if (reset_background) {
1359 std::memcpy(st->W, st->foreground, N * M * C * K *
sizeof(echo_word32_t));
1360 for (
int chan = 0; chan < C; chan++) {
1365 st->e[chan * N + i] = st->input[chan * st->
frame_size + i] -
1369 st->Davg1 = st->Davg2 = 0;
1370 st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
1375 echo_word32_t Sey = 0, Syy = 0, Sdd = 0;
1376 for (
int chan = 0; chan < C; chan++) {
1379 echo_word32_t tmp_out;
1381 tmp_out = st->input[chan * st->
frame_size + i] -
1384 tmp_out = st->input[chan * st->
frame_size + i] -
1387 tmp_out = tmp_out + st->preemph * st->memE[chan];
1388 if (in[i * C + chan] <= -32000 || in[i * C + chan] >= 32000) {
1389 if (st->saturated == 0) st->saturated = 1;
1391 out[i * C + chan] = WORD2INT(tmp_out);
1392 st->memE[chan] = tmp_out;
1397 st->e[chan * N + i + st->
frame_size] = st->e[chan * N + i];
1398 st->e[chan * N + i] = 0;
1410 echo_fft<Allocator>(st->fft_table, st->e + chan * N, st->E + chan * N);
1412 for (
int i = 0; i < st->
frame_size; i++) st->y[i + chan * N] = 0;
1413 echo_fft<Allocator>(st->fft_table, st->y + chan * N, st->Y + chan * N);
1421 if (!(Syy >= 0 && Sxx >= 0 && See >= 0) ||
1422 !(Sff < N * 1e9f && Syy < N * 1e9f && Sxx < N * 1e9f)) {
1423 st->screwed_up += 50;
1424 for (
int i = 0; i < st->
frame_size * C; i++) out[i] = 0;
1425 }
else if (Sff > Sdd + N * 10000.0f) {
1431 if (st->screwed_up >= 50) {
1432 echoWarning(
"Echo canceller reset");
1437 See = MAX32(See, N * 100.0f);
1439 for (
int speak = 0; speak < K; speak++) {
1447 st->power[j] = ss_1 * st->power[j] + 1 + ss * st->Xf[j];
1454 Pey = FLOAT_ADD(Pey, FLOAT_MULT(Eh, Yh));
1455 Pyy = FLOAT_ADD(Pyy, FLOAT_MULT(Yh, Yh));
1457 (1 - st->spec_average) * st->Eh[j] + st->spec_average * st->Rf[j];
1459 (1 - st->spec_average) * st->Yh[j] + st->spec_average * st->Yf[j];
1462 Pyy = FLOAT_SQRT(Pyy);
1463 Pey = FLOAT_DIVU(Pey, Pyy);
1466 echo_word32_t tmp32 = st->beta0 * Syy;
1467 if (tmp32 > st->beta_max * See) tmp32 = st->beta_max * See;
1471 st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1, st->Pey), FLOAT_MULT(alpha, Pey));
1472 st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1, st->Pyy), FLOAT_MULT(alpha, Pyy));
1473 if (FLOAT_LT(st->Pyy, FLOAT_ONE)) st->Pyy = FLOAT_ONE;
1474 if (FLOAT_LT(st->Pey, FLOAT_MULT(
MIN_LEAK, st->Pyy)))
1475 st->Pey = FLOAT_MULT(
MIN_LEAK, st->Pyy);
1476 if (FLOAT_GT(st->Pey, st->Pyy)) st->Pey = st->Pyy;
1479 FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy), 14));
1480 if (st->leak_estimate > 16383)
1481 st->leak_estimate = 32767;
1483 st->leak_estimate = st->leak_estimate * 2;
1487 RER = (.0001f * Sxx + 3.f * st->leak_estimate * Syy) / See;
1488 if (RER < Sey * Sey / (1 + See * Syy)) RER = Sey * Sey / (1 + See * Syy);
1489 if (RER > .5f) RER = .5f;
1491 if (!st->adapted && st->sum_adapt > M &&
1492 st->leak_estimate * Syy > .03f * Syy) {
1498 echo_word32_t r = st->leak_estimate * st->Yf[i];
1499 echo_word32_t e = st->Rf[i] + 1;
1500 if (r > .5f * e) r = .5f * e;
1501 r = .7f * r + .3f * (RER * e);
1502 st->power_1[i] = r / (e * (st->power[i] + 10));
1505 echo_word16_t adapt_rate = 0;
1506 if (Sxx > N * 1000.0f) {
1508 if (tmp32 > .25f * See) tmp32 = .25f * See;
1509 adapt_rate = tmp32 / See;
1512 st->power_1[i] = adapt_rate / (st->power[i] + 10);
1513 st->sum_adapt = st->sum_adapt + adapt_rate;
1516 std::memmove(st->last_y,
1521 st->last_y[st->
frame_size + i] = in[i] - out[i];
1537template <
typename Allocator>
1548 if (!driver->
begin(cfg)) {
1559template <
typename Allocator = std::allocator<u
int8_t>>
1576template <
typename Allocator = std::allocator<u
int8_t>>
1578 echo_word16_t* out) {
1580 if (!st || !st->driver)
return;
1583 for (
int i = 0; i < st->N; i++) {
1584 st->
driver->setValue(i, in[i] / (
float)st->N);
1593 out[0] = st->driver->getValue(0);
1594 for (
int i = 1; i < st->N - 1; i += 2) {
1595 int bin = (i + 1) / 2;
1597 st->driver->getBin(bin, real, img);
1601 out[st->N - 1] = st->driver->getValue(st->N / 2);
1612template <
typename Allocator = std::allocator<u
int8_t>>
1614 echo_word16_t* out) {
1616 if (!st || !st->driver || !st->driver->isReverseFFT())
return;
1620 for (
int i = 1; i < st->N - 1; i += 2) {
1621 int bin = (i + 1) / 2;
1622 st->driver->setBin(bin, in[i], in[i + 1]);
1624 st->driver->setBin(st->N / 2, in[st->N - 1], 0);
1630 for (
int i = 0; i < st->N; i++) {
1631 out[i] = st->driver->getValue(i);
void spectralMulAccum(const echo_word16_t *X, const echo_word32_t *Y, echo_word16_t *acc, int N, int M)
Accumulate spectral multiplication across multiple frames.
Definition MDFEchoCancellation.h:971
int getMicChannels()
Definition MDFEchoCancellation.h:759
void echo_ifft(void *table, echo_word16_t *in, echo_word16_t *out)
Perform inverse FFT.
Definition MDFEchoCancellation.h:1613
void cancel(const echo_int16_t *rec, const echo_int16_t *play, echo_int16_t *out)
Definition MDFEchoCancellation.h:575
int getSamplingRate()
Definition MDFEchoCancellation.h:721
void mdfAdjustProp(const echo_word32_t *W, int N, int M, int P, echo_word16_t *prop)
Adjust proportional adaptation weights.
Definition MDFEchoCancellation.h:1020
void echo_fft(void *table, echo_word16_t *in, echo_word16_t *out)
Perform forward FFT.
Definition MDFEchoCancellation.h:1577
std::vector< float, FloatAllocator > temp_real
Definition MDFEchoCancellation.h:456
~MDFEchoCancellation()
Definition MDFEchoCancellation.h:532
void getImpulseResponse(echo_int32_t *response)
Definition MDFEchoCancellation.h:729
int K
Definition MDFEchoCancellation.h:388
echo_word32_t mdfInnerProd(const echo_word16_t *x, const echo_word16_t *y, int len)
Compute inner product of two vectors.
Definition MDFEchoCancellation.h:925
void setSpeakerChannels(int num)
Definition MDFEchoCancellation.h:764
AudioFFTBase * fft_driver
Definition MDFEchoCancellation.h:791
void setMicChannels(int num)
Definition MDFEchoCancellation.h:750
AudioFFTBase * driver
Definition MDFEchoCancellation.h:454
void * echo_fft_init(int size, AudioFFTBase *driver, const Allocator &alloc)
Initialize FFT state.
Definition MDFEchoCancellation.h:1538
void filterDcNotch16(const echo_int16_t *in, echo_word16_t radius, echo_word16_t *out, int len, echo_mem_t *mem, int stride)
Apply DC notch filter to remove DC offset.
Definition MDFEchoCancellation.h:905
fft_state(int size, AudioFFTBase *drv, const Allocator &alloc=Allocator())
Construct FFT state with specified size and driver.
Definition MDFEchoCancellation.h:465
void echoFree(T *ptr, size_t count=0)
Deallocate memory using custom allocator.
Definition MDFEchoCancellation.h:839
echo_int32_t sampling_rate
Definition MDFEchoCancellation.h:389
int control(int request, void *ptr)
Definition MDFEchoCancellation.h:675
MDFEchoCancellation(int filterLength, AudioFFTBase &fftDriver, const Allocator &alloc=Allocator())
Definition MDFEchoCancellation.h:515
int N
Definition MDFEchoCancellation.h:455
int nb_speakers
Definition MDFEchoCancellation.h:795
int getFilterLength()
Definition MDFEchoCancellation.h:745
void ensureInitialized()
Ensure echo canceller is initialized (lazy initialization)
Definition MDFEchoCancellation.h:801
void echo_fft_destroy(void *table)
Destroy FFT state and release resources.
Definition MDFEchoCancellation.h:1560
void setFilterLength(int len)
Definition MDFEchoCancellation.h:736
void playback(const echo_int16_t *play)
Definition MDFEchoCancellation.h:607
int getImpulseResponseSize()
Definition MDFEchoCancellation.h:724
int getFrameSize()
Definition MDFEchoCancellation.h:713
void powerSpectrum(const echo_word16_t *X, echo_word32_t *ps, int N)
Compute power spectrum from FFT output.
Definition MDFEchoCancellation.h:940
void setSamplingRate(int rate)
Definition MDFEchoCancellation.h:718
EchoState * getState()
Definition MDFEchoCancellation.h:787
EchoState * state
Definition MDFEchoCancellation.h:790
T * echoAlloc(size_t count)
Allocate memory for array of type T using custom allocator.
Definition MDFEchoCancellation.h:821
void powerSpectrumAccum(const echo_word16_t *X, echo_word32_t *ps, int N)
Accumulate power spectrum from FFT output.
Definition MDFEchoCancellation.h:954
std::vector< float, FloatAllocator > temp_img
Definition MDFEchoCancellation.h:457
void capture(const echo_int16_t *rec, echo_int16_t *out)
Definition MDFEchoCancellation.h:585
int nb_mic
Definition MDFEchoCancellation.h:794
typename std::allocator_traits< Allocator >::template rebind_alloc< float > FloatAllocator
Definition MDFEchoCancellation.h:452
void setFFTDriver(AudioFFTBase &fftDriver)
Definition MDFEchoCancellation.h:778
void reset()
Definition MDFEchoCancellation.h:629
int frame_size
Definition MDFEchoCancellation.h:380
MDFEchoCancellation(int filterLength, int nbMic, int nbSpeakers, AudioFFTBase &fftDriver, const Allocator &alloc=Allocator())
Definition MDFEchoCancellation.h:526
float spxExp(float x)
Compute exponential function.
Definition MDFEchoCancellation.h:887
void weightedSpectralMulConj(const echo_float_t *w, const echo_float_t p, const echo_word16_t *X, const echo_word16_t *Y, echo_word32_t *prod, int N)
Compute weighted spectral multiplication with conjugate.
Definition MDFEchoCancellation.h:996
bool initialized
Definition MDFEchoCancellation.h:796
int getSpeakerChannels()
Definition MDFEchoCancellation.h:773
float spxCos(float x)
Compute cosine function.
Definition MDFEchoCancellation.h:894
EchoState * echoStateInitMc(int frame_size, int filter_length, int nb_mic, int nb_speakers)
Initialize multi-channel echo canceller state.
Definition MDFEchoCancellation.h:1055
void echoCancellationImpl(EchoState *st, const echo_int16_t *in, const echo_int16_t *far_end, echo_int16_t *out)
Core echo cancellation implementation.
Definition MDFEchoCancellation.h:1179
Allocator allocator
Definition MDFEchoCancellation.h:792
int filter_length
Definition MDFEchoCancellation.h:793