summaryrefslogtreecommitdiff
path: root/mec2.h
diff options
context:
space:
mode:
authorkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-12-19 04:04:16 +0000
committerkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-12-19 04:04:16 +0000
commit4a8f1fb6fa4e4ad06f171c30d129dfeef6d07867 (patch)
tree9489f3307b1958505c482cccf5c5a06fe7da6fdf /mec2.h
parente68e5ec9adb20f793ad0319b181cfdeea336826d (diff)
add ability to provide parameters to echo cancelers on a per-channel basis, and remove the three versions of the 'Mark' echo canceler (later replaced by KB1 and then by MG2)
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3524 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'mec2.h')
-rw-r--r--mec2.h436
1 files changed, 0 insertions, 436 deletions
diff --git a/mec2.h b/mec2.h
deleted file mode 100644
index 98061ff..0000000
--- a/mec2.h
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * 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
-//
-struct echo_can_state {
- /* 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;
-
-};
-
-static void echo_can_init(void)
-{
- printk("Zaptel Echo Canceller: MARK2%s\n", ZAPTEL_ECHO_AGGRESSIVE);
-}
-
-static void echo_can_identify(char *buf, size_t len)
-{
- strncpy(buf, "MARK2", len);
-}
-
-static void echo_can_shutdown(void)
-{
-}
-
-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(struct echo_can_state *ec, int N, int maxy, int maxu) {
-
- void *ptr = ec;
- unsigned long tmp;
- /* double-word align past end of state */
- ptr += sizeof(struct echo_can_state);
- 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;
- ec->Lu_i = DEFAULT_CUTOFF_I;
-
- // reset the near-end speech detector
- //
- ec->s_tilde_i = 0;
- ec->y_tilde_i = 0;
- ec->HCNTR_d = (int)0;
-
- // exit gracefully
- //
-}
-
-static inline void echo_can_free(struct echo_can_state *ec)
-{
- FREE(ec);
-}
-
-static inline short echo_can_update(struct echo_can_state *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_YT_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
- */
- if (!ec->HCNTR_d) {
- Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
- Py_i >>= 15;
- } else {
- 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
-#ifdef AGGRESSIVE_SUPPRESSOR
-#ifdef AGGRESSIVE_TIMELIMIT /* This allows the aggressive suppressor to turn off after set amount of time */
- if (ec->i_d > AGGRESSIVE_TIMELIMIT ) {
- 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);
- }
- }
- else {
-#endif
- if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
- u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
- u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
- }
-#ifdef AGGRESSIVE_TIMELIMIT
- }
-#endif
-#else
- 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
-#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 struct echo_can_state *echo_can_create(int len, int adaption_mode)
-{
- struct echo_can_state *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 = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) +
- 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(struct echo_can_state) +
- 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;
-}
-
-static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
-{
- /* Reset hang counter to avoid adjustments after
- initial forced training */
- ec->HCNTR_d = ec->N_d << 1;
- if (pos >= ec->N_d)
- return 1;
- ec->a_i[pos] = val << 17;
- ec->a_s[pos] = val << 1;
- if (++pos >= ec->N_d)
- return 1;
- return 0;
-}
-
-#endif