summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2002-10-28 22:08:48 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2002-10-28 22:08:48 +0000
commit7f5c6e162a9c5ff654115136ccc6783a67749a72 (patch)
treee78add6b051106cf07f5d7fe67b0a591574377de
parentcd0da1d15c640b4a63fe9e0222b216bebaf0b08f (diff)
Version 0.3.2 from FTP
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@124 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-xMakefile9
-rwxr-xr-xarith.h252
-rwxr-xr-xmec2.h389
-rwxr-xr-xmec2_const.h25
-rwxr-xr-xzaptel.h21
5 files changed, 682 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index b72670d..4cb8fff 100755
--- a/Makefile
+++ b/Makefile
@@ -37,9 +37,10 @@ KFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-msoft-float -fsigned-char
#
# Pick your echo canceller: MARK, STEVE, or STEVE2 :)
#
-KFLAGS+=-DECHO_CAN_STEVE
+#KFLAGS+=-DECHO_CAN_STEVE
#KFLAGS+=-DECHO_CAN_STEVE2
#KFLAGS+=-DECHO_CAN_MARK
+KFLAGS+=-DECHO_CAN_MARK2
#
# Uncomment -DCONFIG_ZAPATA_NET to enable SyncPPP, CiscoHDLC, and Frame Relay
# support.
@@ -78,12 +79,12 @@ all: $(MODULES) ztcfg torisatool makefw ztmonitor ztspeed $(ZTTOOL)
devel: tor2ee
-tests: patgen pattest hdlcstress hdlctest
+tests: patgen pattest patlooptest hdlcstress hdlctest
tor2.o: tor2.c tor2-hw.h tor.h tor2fw.h zaptel.h
gcc $(KFLAGS) -c tor2.c
-zaptel.o: zaptel.c zaptel.h digits.h arith.h
+zaptel.o: zaptel.c zaptel.h digits.h arith.h sec.h mec.h sec-2.h
gcc $(KFLAGS) -c zaptel.c
torisa.o: torisa.c zaptel.h torisa.h
@@ -136,7 +137,7 @@ tor2fw.h: makefw tormenta2.rbt
gendigits: gendigits.o
$(CC) -o gendigits gendigits.o -lm
-zaptel.c: tones.h
+zaptel.c: tones.h
zttool.o: zttool.c zaptel.h
diff --git a/arith.h b/arith.h
index 7ae859d..96541c8 100755
--- a/arith.h
+++ b/arith.h
@@ -1,3 +1,5 @@
+#ifndef _ZAPTEL_ARITH_H
+#define _ZAPTEL_ARITH_H
/*
* Handy add/subtract functions to operate on chunks of shorts.
* Feel free to add customizations for additional architectures
@@ -5,7 +7,7 @@
*/
#ifdef CONFIG_ZAPTEL_MMX
-
+#ifdef ZT_CHUNKSIZE
static inline void __ACSS(volatile short *dst, const short *src)
{
__asm__ __volatile__ (
@@ -46,6 +48,7 @@ static inline void __SCSS(volatile short *dst, const short *src)
);
}
+
#if (ZT_CHUNKSIZE == 8)
#define ACSS(a,b) __ACSS(a,b)
#define SCSS(a,b) __SCSS(a,b)
@@ -65,9 +68,197 @@ static inline void SCSS(volatile short *dst, const short *src)
#else
#error No MMX for ZT_CHUNKSIZE < 8
#endif
+#endif
+static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
+{
+ int sum;
+ /* Divide length by 16 */
+ len >>= 4;
+
+ /* Clear our accumulator, mm4 */
+
+ /*
+
+ For every set of eight...
+
+ Load 16 coefficients into four registers...
+ Shift each word right 16 to make them shorts...
+ Pack the resulting shorts into two registers...
+ With the coefficients now in mm0 and mm2, load the
+ history into mm1 and mm3...
+ Multiply/add mm1 into mm0, and mm3 into mm2...
+ Add mm2 into mm0 (without saturation, alas). Now we have two half-results.
+ Accumulate in mm4 (again, without saturation, alas)
+ */
+ __asm__ (
+ "pxor %%mm4, %%mm4;\n"
+ "mov %1, %%edi;\n"
+ "mov %2, %%esi;\n"
+ "mov %3, %%ecx;\n"
+ "1:"
+ "movq 0(%%edi), %%mm0;\n"
+ "movq 8(%%edi), %%mm1;\n"
+ "movq 16(%%edi), %%mm2;\n"
+ "movq 24(%%edi), %%mm3;\n"
+ /* can't use 4/5 since 4 is the accumulator for us */
+ "movq 32(%%edi), %%mm6;\n"
+ "movq 40(%%edi), %%mm7;\n"
+ "psrad $16, %%mm0;\n"
+ "psrad $16, %%mm1;\n"
+ "psrad $16, %%mm2;\n"
+ "psrad $16, %%mm3;\n"
+ "psrad $16, %%mm6;\n"
+ "psrad $16, %%mm7;\n"
+ "packssdw %%mm1, %%mm0;\n"
+ "packssdw %%mm3, %%mm2;\n"
+ "packssdw %%mm7, %%mm6;\n"
+ "movq 0(%%esi), %%mm1;\n"
+ "movq 8(%%esi), %%mm3;\n"
+ "movq 16(%%esi), %%mm7;\n"
+ "pmaddwd %%mm1, %%mm0;\n"
+ "pmaddwd %%mm3, %%mm2;\n"
+ "pmaddwd %%mm7, %%mm6;\n"
+ "paddd %%mm6, %%mm4;\n"
+ "paddd %%mm2, %%mm4;\n"
+ "paddd %%mm0, %%mm4;\n"
+ /* Come back and do for the last few bytes */
+ "movq 48(%%edi), %%mm6;\n"
+ "movq 56(%%edi), %%mm7;\n"
+ "psrad $16, %%mm6;\n"
+ "psrad $16, %%mm7;\n"
+ "packssdw %%mm7, %%mm6;\n"
+ "movq 24(%%esi), %%mm7;\n"
+ "pmaddwd %%mm7, %%mm6;\n"
+ "paddd %%mm6, %%mm4;\n"
+ "add $64, %%edi;\n"
+ "add $32, %%esi;\n"
+ "dec %%ecx;\n"
+ "jnz 1b;\n"
+ "movq %%mm4, %%mm0;\n"
+ "psrlq $32, %%mm0;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movd %%mm4, %0;\n"
+ : "=r" (sum)
+ : "r" (coeffs), "r" (hist), "r" (len)
+ : "%ecx", "%edi", "%esi"
+ );
+
+ return sum;
+}
+
+static inline void UPDATE(volatile int *taps, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ }
+}
+
+static inline void UPDATE2(volatile int *taps, volatile short *taps_short, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+#if 0
+ ntaps >>= 4;
+ /* First, load up taps, */
+ __asm__ (
+ "pxor %%mm4, %%mm4;\n"
+ "mov %0, %%edi;\n"
+ "mov %1, %%esi;\n"
+ "mov %3, %%ecx;\n"
+ "1:"
+ "jnz 1b;\n"
+ "movq %%mm4, %%mm0;\n"
+ "psrlq $32, %%mm0;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movd %%mm4, %0;\n"
+ : "=r" (taps), "=r" (taps_short)
+ : "r" (history), "r" (nsuppr), "r" (ntaps), "0" (taps)
+ : "%ecx", "%edi", "%esi"
+ );
+#endif
+#if 1
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ taps_short[i] = taps[i] >> 16;
+ }
+#endif
+}
+
+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
+{
+ int sum;
+ /* Divide length by 16 */
+ len >>= 4;
+
+ /* Clear our accumulator, mm4 */
+
+ /*
+
+ For every set of eight...
+ Load in eight coefficients and eight historic samples, multliply add and
+ accumulate the result
+ */
+ __asm__ (
+ "pxor %%mm4, %%mm4;\n"
+ "mov %1, %%edi;\n"
+ "mov %2, %%esi;\n"
+ "mov %3, %%ecx;\n"
+ "1:"
+ "movq 0(%%edi), %%mm0;\n"
+ "movq 8(%%edi), %%mm2;\n"
+ "movq 0(%%esi), %%mm1;\n"
+ "movq 8(%%esi), %%mm3;\n"
+ "pmaddwd %%mm1, %%mm0;\n"
+ "pmaddwd %%mm3, %%mm2;\n"
+ "paddd %%mm2, %%mm4;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movq 16(%%edi), %%mm0;\n"
+ "movq 24(%%edi), %%mm2;\n"
+ "movq 16(%%esi), %%mm1;\n"
+ "movq 24(%%esi), %%mm3;\n"
+ "pmaddwd %%mm1, %%mm0;\n"
+ "pmaddwd %%mm3, %%mm2;\n"
+ "paddd %%mm2, %%mm4;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "add $32, %%edi;\n"
+ "add $32, %%esi;\n"
+ "dec %%ecx;\n"
+ "jnz 1b;\n"
+ "movq %%mm4, %%mm0;\n"
+ "psrlq $32, %%mm0;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movd %%mm4, %0;\n"
+ : "=r" (sum)
+ : "r" (coeffs), "r" (hist), "r" (len)
+ : "%ecx", "%edi", "%esi"
+ );
+
+ return sum;
+}
+static inline short MAX16(const short *y, int len, int *pos)
+{
+ int k;
+ short max = 0;
+ int bestpos = 0;
+ for (k=0;k<len;k++) {
+ if (max < y[k]) {
+ bestpos = k;
+ max = y[k];
+ }
+ }
+ *pos = (len - 1 - bestpos);
+ return max;
+}
+
+
#else
+#ifdef ZT_CHUNKSIZE
static inline void ACSS(short *dst, short *src)
{
int x,sum;
@@ -96,4 +287,61 @@ static inline void SCSS(short *dst, short *src)
}
}
-#endif
+#endif /* ZT_CHUNKSIZE */
+
+static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
+{
+ int x;
+ int sum = 0;
+ for (x=0;x<len;x++)
+ sum += (coeffs[x] >> 16) * hist[x];
+ return sum;
+}
+
+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
+{
+ int x;
+ int sum = 0;
+ for (x=0;x<len;x++)
+ sum += coeffs[x] * hist[x];
+ return sum;
+}
+
+static inline void UPDATE(int *taps, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ }
+}
+
+static inline void UPDATE2(int *taps, short *taps_short, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ taps_short[i] = taps[i] >> 16;
+ }
+}
+
+static inline short MAX16(const short *y, int len, int *pos)
+{
+ int k;
+ short max = 0;
+ int bestpos = 0;
+ for (k=0;k<len;k++) {
+ if (max < y[k]) {
+ bestpos = k;
+ max = y[k];
+ }
+ }
+ *pos = (len - 1 - bestpos);
+ return max;
+}
+
+#endif /* MMX */
+#endif /* _ZAPTEL_ARITH_H */
diff --git a/mec2.h b/mec2.h
new file mode 100755
index 0000000..36bc042
--- /dev/null
+++ b/mec2.h
@@ -0,0 +1,389 @@
+/*
+ * Mark's Second Echo Canceller
+ *
+ * Copyright (C) 2002, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ */
+#ifndef _MARK2_ECHO_H
+#define _MARK2_ECHO_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_KERNEL)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+/* Get optimized routines for math */
+#include "arith.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#include "mec2_const.h"
+
+/* Circular buffer definition */
+typedef struct {
+ int idx_d;
+ int size_d;
+ short *buf_d; /* Twice as large as we need */
+} echo_can_cb_s;
+
+// class definition
+//
+typedef struct {
+ /* Echo canceller definition */
+
+ /* absolute time */
+ int i_d;
+
+ /* pre-computed constants */
+
+ int N_d;
+ int beta2_i;
+
+ // declare accumulators for power computations
+ //
+ int Ly_i;
+ int Lu_i;
+
+ // declare an accumulator for the near-end signal detector
+ //
+ int s_tilde_i;
+ int HCNTR_d;
+
+ // circular buffers and coefficients
+ //
+ int *a_i;
+ short *a_s;
+ echo_can_cb_s y_s;
+ echo_can_cb_s s_s;
+ echo_can_cb_s u_s;
+ echo_can_cb_s y_tilde_s;
+ int y_tilde_i;
+
+ /* Max memory */
+ short max_y_tilde;
+ int max_y_tilde_pos;
+
+} echo_can_state_t;
+
+static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
+{
+ cb->buf_d = (short *)where;
+ cb->idx_d = 0;
+ cb->size_d = len;
+}
+
+static inline void add_cc_s(echo_can_cb_s *cb, short newval)
+{
+ /* Can't use modulus because N+M isn't a power of two (generally) */
+ cb->idx_d--;
+ if (cb->idx_d < (int)0)
+ {cb->idx_d += cb->size_d;}
+ /* Load two copies into memory */
+ cb->buf_d[cb->idx_d] = newval;
+ cb->buf_d[cb->idx_d + cb->size_d] = newval;
+}
+
+static inline short get_cc_s(echo_can_cb_s *cb, int pos)
+{
+ /* Load two copies into memory */
+ return cb->buf_d[cb->idx_d + pos];
+}
+
+static inline void init_cc(echo_can_state_t *ec, int N, int maxy, int maxu) {
+
+ void *ptr = ec;
+ unsigned long tmp;
+ /* double-word align past end of state */
+ ptr += sizeof(echo_can_state_t);
+ tmp = (unsigned long)ptr;
+ tmp += 3;
+ tmp &= ~3L;
+ ptr = (void *)tmp;
+
+ // reset parameters
+ //
+ ec->N_d = N;
+ ec->beta2_i = DEFAULT_BETA1_I;
+
+ // allocate coefficient memory
+ //
+ ec->a_i = ptr;
+ ptr += (sizeof(int) * ec->N_d);
+ ec->a_s = ptr;
+ ptr += (sizeof(short) * ec->N_d);
+
+ /* Reset Y circular buffer (short version) */
+ init_cb_s(&ec->y_s, maxy, ptr);
+ ptr += (sizeof(short) * (maxy) * 2);
+
+ /* Reset Sig circular buffer (short version for FIR filter) */
+ init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
+ ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
+
+ init_cb_s(&ec->u_s, maxu, ptr);
+ ptr += (sizeof(short) * maxu * 2);
+
+ // allocate a buffer for the reference signal power computation
+ //
+ init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
+
+
+ // reset absolute time
+ //
+ ec->i_d = (int)0;
+
+ // reset the power computations (for y and u)
+ //
+ ec->Ly_i = DEFAULT_CUTOFF_I;
+
+ // reset the near-end speech detector
+ //
+ ec->s_tilde_i = 0;
+ ec->HCNTR_d = (int)0;
+
+ // exit gracefully
+ //
+}
+
+static inline void echo_can_free(echo_can_state_t *ec)
+{
+ FREE(ec);
+}
+
+static inline short echo_can_update(echo_can_state_t *ec, short iref, short isig) {
+
+ /* declare local variables that are used more than once
+ */
+ int k;
+ int rs;
+ short u;
+ int Py_i;
+ int two_beta_i;
+
+ /***************************************************************************
+ //
+ // flow A on pg. 428
+ //
+ ***************************************************************************/
+
+ /* eq. (16): high-pass filter the input to generate the next value;
+ // push the current value into the circular buffer
+ //
+ // sdc_im1_d = sdc_d;
+ // sdc_d = sig;
+ // s_i_d = sdc_d;
+ // s_d = s_i_d;
+ // s_i_d = (float)(1.0 - gamma_d) * s_i_d
+ + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */
+
+
+ /* Delete last sample from power estimate */
+ ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
+ /* push the reference data onto the circular buffer */
+ add_cc_s(&ec->y_s, iref);
+
+ /* eq. (2): compute r in fixed-point */
+ rs = CONVOLVE2(ec->a_s, ec->y_s.buf_d + ec->y_s.idx_d, ec->N_d);
+ rs >>= 15;
+
+ /* eq. (3): compute the output value (see figure 3) and the error
+ // note: the error is the same as the output signal when near-end
+ // speech is not present
+ */
+ u = isig - rs;
+
+ add_cc_s(&ec->u_s, u);
+
+
+
+ /* Delete oldest part of received s_tilde */
+ ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
+
+ /* push the signal on the circular buffer, too */
+ add_cc_s(&ec->s_s, isig);
+ ec->s_tilde_i += abs(isig);
+ ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I;
+
+ /* Add to our list of recent y_tilde's */
+ add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);
+
+ /****************************************************************************
+ //
+ // flow B on pg. 428
+ //
+ ****************************************************************************/
+
+ /* compute the new convergence factor
+ */
+ Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
+ Py_i >>= 15;
+ if (ec->HCNTR_d > 0) {
+ Py_i = (1 << 15);
+ }
+
+#if 0
+ printf("Py: %e, Py_i: %e\n", Py, Py_i * AMPL_SCALE_1);
+#endif
+
+ /* Vary rate of adaptation depending on position in the file
+ // Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
+ // has begun of the file to allow the echo cancellor to estimate the
+ // channel accurately
+ */
+#if 0
+ if (ec->start_speech_d != 0 ){
+ if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
+ ec->beta2_d = max_cc_float(MIN_BETA,
+ DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) -
+ DEFAULT_T0 -
+ ec->start_speech_d)));
+ }
+ }
+ else {ec->beta2_d = DEFAULT_BETA1;}
+#endif
+
+ ec->beta2_i = DEFAULT_BETA1_I; /* Fixed point, inverted */
+
+ two_beta_i = (ec->beta2_i * Py_i) >> 15; /* Fixed point version, inverted */
+ if (!two_beta_i)
+ two_beta_i++;
+
+ /* Update Lu_i (Suppressed power estimate) */
+ ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
+ ec->Lu_i += abs(u);
+
+ /* eq. (10): update power estimate of the reference
+ */
+ ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
+ ec->Ly_i += abs(iref);
+
+ if (ec->Ly_i < DEFAULT_CUTOFF_I)
+ ec->Ly_i = DEFAULT_CUTOFF_I;
+
+#if 0
+ printf("Float: %e, Int: %e\n", ec->Ly_d, (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * AMPL_SCALE_1);
+#endif
+
+ if (ec->y_tilde_i > ec->max_y_tilde) {
+ /* New highest y_tilde with full life */
+ ec->max_y_tilde = ec->y_tilde_i;
+ ec->max_y_tilde_pos = ec->N_d - 1;
+ } else if (--ec->max_y_tilde_pos < 0) {
+ /* Time to find new max y tilde... */
+ ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
+ }
+
+ if ((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
+ {
+ ec->HCNTR_d = DEFAULT_HANGT;
+ }
+ else if (ec->HCNTR_d > (int)0)
+ {
+ ec->HCNTR_d--;
+ }
+
+ /* update coefficients if no near-end speech and we have enough signal
+ * to bother trying to update.
+ */
+ if (!ec->HCNTR_d && !(ec->i_d % DEFAULT_M) &&
+ (ec->Lu_i > MIN_UPDATE_THRESH_I)) {
+ // loop over all filter coefficients
+ //
+ for (k=0; k<ec->N_d; k++) {
+
+ // eq. (7): compute an expectation over M_d samples
+ //
+ int grad2;
+ grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
+ ec->y_s.buf_d + ec->y_s.idx_d + k, DEFAULT_M);
+ // eq. (7): update the coefficient
+ //
+ ec->a_i[k] += grad2 / two_beta_i;
+ ec->a_s[k] = ec->a_i[k] >> 16;
+ }
+ }
+
+ /* paragraph below eq. (15): if no near-end speech,
+ // check for residual error suppression
+ */
+#ifndef NO_ECHO_SUPPRESSOR
+ if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
+ }
+#endif
+
+#if 0
+ if ((ec->HCNTR_d == 0) && ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
+ (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) {
+ suppr_factor = (10/(float)(SUPPR_FLOOR-SUPPR_CEIL))*log(ec->Lu_d/ec->Ly_d)
+ - SUPPR_CEIL/(float)(SUPPR_FLOOR - SUPPR_CEIL);
+
+ u_suppr = pow(10.0,(suppr_factor)*RES_SUPR_FACTOR/10.0)*u_suppr;
+
+ }
+#endif
+ ec->i_d++;
+ return u;
+}
+
+static inline echo_can_state_t *echo_can_create(int len, int adaption_mode)
+{
+ echo_can_state_t *ec;
+ int maxy;
+ int maxu;
+ maxy = len + DEFAULT_M;
+ maxu = DEFAULT_M;
+ if (maxy < (1 << DEFAULT_ALPHA_YT_I))
+ maxy = (1 << DEFAULT_ALPHA_YT_I);
+ if (maxy < (1 << DEFAULT_SIGMA_LY_I))
+ maxy = (1 << DEFAULT_SIGMA_LY_I);
+ if (maxu < (1 << DEFAULT_SIGMA_LU_I))
+ maxu = (1 << DEFAULT_SIGMA_LU_I);
+ ec = (echo_can_state_t *)MALLOC(sizeof(echo_can_state_t) +
+ 4 + /* align */
+ sizeof(int) * len + /* a_i */
+ sizeof(short) * len + /* a_s */
+ 2 * sizeof(short) * (maxy) + /* y_s */
+ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+ 2 * sizeof(short) * (maxu) + /* u_s */
+ 2 * sizeof(short) * len); /* y_tilde_s */
+ if (ec) {
+ memset(ec, 0, sizeof(echo_can_state_t) +
+ 4 + /* align */
+ sizeof(int) * len + /* a_i */
+ sizeof(short) * len + /* a_s */
+ 2 * sizeof(short) * (maxy) + /* y_s */
+ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+ 2 * sizeof(short) * (maxu) + /* u_s */
+ 2 * sizeof(short) * len); /* y_tilde_s */
+ init_cc(ec, len, maxy, maxu);
+ }
+ return ec;
+}
+
+
+
+#endif
diff --git a/mec2_const.h b/mec2_const.h
new file mode 100755
index 0000000..e4df09c
--- /dev/null
+++ b/mec2_const.h
@@ -0,0 +1,25 @@
+/*
+ Important constants for tuning mec2 echo can
+ */
+#ifndef _MEC2_CONST_H
+#define _MEC2_CONST_H
+
+
+/* Convergence speed -- higher means slower */
+#define DEFAULT_BETA1_I 2048
+#define DEFAULT_SIGMA_LY_I 7
+#define DEFAULT_SIGMA_LU_I 7
+#define DEFAULT_ALPHA_ST_I 5
+#define DEFAULT_ALPHA_YT_I 5
+#define DEFAULT_CUTOFF_I 128
+#define DEFAULT_HANGT 600
+#define DEFAULT_SUPPR_I 16
+#define MIN_UPDATE_THRESH_I 4096
+#define DEFAULT_M 16
+#define SUPPR_FLOOR -64
+#define SUPPR_CEIL -24
+#define RES_SUPR_FACTOR -20
+
+
+#endif /* _MEC2_CONST_H */
+
diff --git a/zaptel.h b/zaptel.h
index b3d83f0..57d085a 100755
--- a/zaptel.h
+++ b/zaptel.h
@@ -39,14 +39,6 @@
#endif
#include <linux/fs.h>
-#if defined(ECHO_CAN_STEVE)
-#include "sec.h"
-#elif defined(ECHO_CAN_STEVE2)
-#include "sec-2.h"
-#else
-#include "mec.h"
-#endif
-
#include "ecdis.h"
#include "fasthdlc.h"
#endif
@@ -127,6 +119,19 @@
#define ZT_POLICY_IMMEDIATE 0 /* Start play/record immediately */
#define ZT_POLICY_WHEN_FULL 1 /* Start play/record when buffer is full */
+#ifdef __KERNEL__
+/* Echo cancellation */
+#if defined(ECHO_CAN_STEVE)
+#include "sec.h"
+#elif defined(ECHO_CAN_STEVE2)
+#include "sec-2.h"
+#elif defined(ECHO_CAN_MARK)
+#include "mec.h"
+#else
+#include "mec2.h"
+#endif
+#endif
+
typedef struct zt_params
{
int channo; /* Channel number */