~ubuntu-branches/ubuntu/quantal/zaptel/quantal

« back to all changes in this revision

Viewing changes to mec2.h

  • Committer: Bazaar Package Importer
  • Author(s): Tzafrir Cohen
  • Date: 2008-08-28 22:58:23 UTC
  • mfrom: (11.1.11 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080828225823-r8bdunirm8hmc76m
Tags: 1:1.4.11~dfsg-2
* Patch xpp_fxs_power: Fixed an issue with hook detection of the Astribank
  FXS module.
* Don't fail init.d script if fxotune fails. This may happen if running it
  when Asterisk is already running.
* Bump standards version to 3.8.0.0 .
* Ignore false lintian warning ("m-a a-i" has "a a").
* Patch xpp_fxo_cid_always: do always pass PCM if that's what the user
  asked.
* Patch vzaphfc_proc_root_dir: fix vzaphfc on 2.6.26.
* Patch wcte12xp_flags: Proper time for irq save flags.
* Patch headers_2627: Fix location of semaphore.h for 2.6.27 .
* Patch xpp_fxs_dtmf_leak: Don't play DTMFs to the wrong channel.
* Patch wctdm_fix_alarm: Fix sending channel alarms.
* Patch device_class_2626: Fix building 2.6.26 (Closes: #493397).
* Using dh_lintian for lintian overrides, hence requiring debhelper 6.0.7.
* Lintian: we know we have direct changes. Too bad we're half-upstream :-(
* Fix doc-base section names. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Mark's Second Echo Canceller
3
 
 * 
4
 
 * Copyright (C) 2002, Digium, Inc.
5
 
 *
6
 
 * This program is free software and may be used and
7
 
 * distributed according to the terms of the GNU
8
 
 * General Public License, incorporated herein by
9
 
 * reference.
10
 
 *
11
 
 */
12
 
#ifndef _MARK2_ECHO_H
13
 
#define _MARK2_ECHO_H
14
 
 
15
 
#ifdef __KERNEL__
16
 
#include <linux/kernel.h>
17
 
#include <linux/slab.h>
18
 
#define MALLOC(a) kmalloc((a), GFP_KERNEL)
19
 
#define FREE(a) kfree(a)
20
 
#else
21
 
#include <stdlib.h>
22
 
#include <unistd.h>
23
 
#include <stdint.h>
24
 
#include <string.h>
25
 
#include <math.h>
26
 
#define MALLOC(a) malloc(a)
27
 
#define FREE(a) free(a)
28
 
#endif
29
 
 
30
 
/* Get optimized routines for math */
31
 
#include "arith.h"
32
 
 
33
 
#ifndef NULL
34
 
#define NULL 0
35
 
#endif
36
 
#ifndef FALSE
37
 
#define FALSE 0
38
 
#endif
39
 
#ifndef TRUE
40
 
#define TRUE (!FALSE)
41
 
#endif
42
 
 
43
 
#include "mec2_const.h"
44
 
 
45
 
/* Circular buffer definition */
46
 
typedef struct {
47
 
  int idx_d;
48
 
  int size_d;
49
 
  short *buf_d; /* Twice as large as we need */
50
 
} echo_can_cb_s;
51
 
 
52
 
// class definition
53
 
//
54
 
typedef struct  {
55
 
  /* Echo canceller definition */
56
 
 
57
 
  /* absolute time */
58
 
  int i_d;
59
 
  
60
 
  /* pre-computed constants */
61
 
 
62
 
  int N_d;
63
 
  int beta2_i;
64
 
 
65
 
  // declare accumulators for power computations
66
 
  //
67
 
  int Ly_i;
68
 
  int Lu_i;
69
 
 
70
 
  // declare an accumulator for the near-end signal detector
71
 
  //
72
 
  int s_tilde_i;
73
 
  int HCNTR_d;
74
 
 
75
 
  // circular buffers and coefficients
76
 
  //
77
 
  int *a_i;
78
 
  short *a_s;
79
 
  echo_can_cb_s y_s;
80
 
  echo_can_cb_s s_s;
81
 
  echo_can_cb_s u_s;
82
 
  echo_can_cb_s y_tilde_s;
83
 
  int y_tilde_i;
84
 
 
85
 
  /* Max memory */
86
 
  short max_y_tilde;
87
 
  int max_y_tilde_pos;
88
 
 
89
 
} echo_can_state_t;
90
 
 
91
 
static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
92
 
{
93
 
        cb->buf_d = (short *)where;
94
 
        cb->idx_d = 0;
95
 
        cb->size_d = len;
96
 
}
97
 
 
98
 
static inline void add_cc_s(echo_can_cb_s *cb, short newval)
99
 
{
100
 
    /* Can't use modulus because N+M isn't a power of two (generally) */
101
 
    cb->idx_d--;
102
 
    if (cb->idx_d < (int)0)
103
 
     {cb->idx_d += cb->size_d;}
104
 
        /* Load two copies into memory */
105
 
        cb->buf_d[cb->idx_d] = newval;
106
 
        cb->buf_d[cb->idx_d + cb->size_d] = newval;
107
 
}
108
 
 
109
 
static inline short get_cc_s(echo_can_cb_s *cb, int pos)
110
 
{
111
 
        /* Load two copies into memory */
112
 
        return cb->buf_d[cb->idx_d + pos];
113
 
}
114
 
 
115
 
static inline void init_cc(echo_can_state_t *ec, int N, int maxy, int maxu) {
116
 
 
117
 
  void *ptr = ec;
118
 
  unsigned long tmp;
119
 
  /* double-word align past end of state */
120
 
  ptr += sizeof(echo_can_state_t);
121
 
  tmp = (unsigned long)ptr;
122
 
  tmp += 3;
123
 
  tmp &= ~3L;
124
 
  ptr = (void *)tmp;
125
 
  
126
 
  // reset parameters
127
 
  //
128
 
  ec->N_d = N;
129
 
  ec->beta2_i = DEFAULT_BETA1_I;
130
 
  
131
 
  // allocate coefficient memory
132
 
  //
133
 
  ec->a_i = ptr;
134
 
  ptr += (sizeof(int) * ec->N_d);
135
 
  ec->a_s = ptr;
136
 
  ptr += (sizeof(short) * ec->N_d);
137
 
 
138
 
  /* Reset Y circular buffer (short version) */
139
 
  init_cb_s(&ec->y_s, maxy, ptr);
140
 
  ptr += (sizeof(short) * (maxy) * 2);
141
 
  
142
 
  /* Reset Sig circular buffer (short version for FIR filter) */
143
 
  init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
144
 
  ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
145
 
 
146
 
  init_cb_s(&ec->u_s, maxu, ptr);
147
 
  ptr += (sizeof(short) * maxu * 2);
148
 
 
149
 
  // allocate a buffer for the reference signal power computation
150
 
  //
151
 
  init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
152
 
 
153
 
 
154
 
  // reset absolute time
155
 
  //
156
 
  ec->i_d = (int)0;
157
 
  
158
 
  // reset the power computations (for y and u)
159
 
  //
160
 
  ec->Ly_i = DEFAULT_CUTOFF_I;
161
 
  ec->Lu_i = DEFAULT_CUTOFF_I;
162
 
 
163
 
  // reset the near-end speech detector
164
 
  //
165
 
  ec->s_tilde_i = 0;
166
 
  ec->y_tilde_i = 0;
167
 
  ec->HCNTR_d = (int)0;
168
 
 
169
 
  // exit gracefully
170
 
  //
171
 
}
172
 
 
173
 
static inline void echo_can_free(echo_can_state_t *ec)
174
 
{
175
 
        FREE(ec);
176
 
}
177
 
 
178
 
static inline short echo_can_update(echo_can_state_t *ec, short iref, short isig) {
179
 
 
180
 
  /* declare local variables that are used more than once
181
 
  */
182
 
  int k;
183
 
  int rs;
184
 
  short u;
185
 
  int Py_i;
186
 
  int two_beta_i;
187
 
  
188
 
  /***************************************************************************
189
 
  //
190
 
  // flow A on pg. 428
191
 
  //
192
 
   ***************************************************************************/
193
 
 
194
 
  /* eq. (16): high-pass filter the input to generate the next value;
195
 
  //           push the current value into the circular buffer
196
 
  //
197
 
  // sdc_im1_d = sdc_d;
198
 
  // sdc_d = sig;
199
 
  //  s_i_d = sdc_d;
200
 
  //  s_d = s_i_d;
201
 
  //  s_i_d = (float)(1.0 - gamma_d) * s_i_d
202
 
     + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */
203
 
  
204
 
  
205
 
  /* Delete last sample from power estimate */
206
 
  ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
207
 
  /* push the reference data onto the circular buffer */
208
 
  add_cc_s(&ec->y_s, iref);
209
 
 
210
 
  /* eq. (2): compute r in fixed-point */
211
 
  rs = CONVOLVE2(ec->a_s, ec->y_s.buf_d + ec->y_s.idx_d, ec->N_d);
212
 
  rs >>= 15;
213
 
 
214
 
  /* eq. (3): compute the output value (see figure 3) and the error
215
 
  // note: the error is the same as the output signal when near-end
216
 
  // speech is not present
217
 
  */
218
 
  u = isig - rs;  
219
 
  
220
 
  add_cc_s(&ec->u_s, u);
221
 
  
222
 
 
223
 
 
224
 
  /* Delete oldest part of received s_tilde */
225
 
  ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
226
 
 
227
 
  /* push the signal on the circular buffer, too */
228
 
  add_cc_s(&ec->s_s, isig);
229
 
  ec->s_tilde_i += abs(isig);
230
 
  ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_YT_I;
231
 
 
232
 
  /* Add to our list of recent y_tilde's */
233
 
  add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);              
234
 
 
235
 
  /****************************************************************************
236
 
  //
237
 
  // flow B on pg. 428
238
 
  // 
239
 
   ****************************************************************************/
240
 
  
241
 
  /* compute the new convergence factor
242
 
  */
243
 
  if (!ec->HCNTR_d) {
244
 
        Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
245
 
        Py_i >>= 15;
246
 
  } else {
247
 
        Py_i = (1 << 15);
248
 
  }
249
 
  
250
 
#if 0
251
 
  printf("Py: %e, Py_i: %e\n", Py, Py_i * AMPL_SCALE_1);
252
 
#endif  
253
 
 
254
 
  /* Vary rate of adaptation depending on position in the file
255
 
  // Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
256
 
  // has begun of the file to allow the echo cancellor to estimate the
257
 
  // channel accurately
258
 
  */
259
 
#if 0
260
 
  if (ec->start_speech_d != 0 ){
261
 
    if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
262
 
      ec->beta2_d = max_cc_float(MIN_BETA,
263
 
                       DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) -
264
 
                                                 DEFAULT_T0 -
265
 
                                                 ec->start_speech_d)));
266
 
    }
267
 
  }
268
 
  else {ec->beta2_d = DEFAULT_BETA1;}
269
 
#endif
270
 
  
271
 
  ec->beta2_i = DEFAULT_BETA1_I;        /* Fixed point, inverted */
272
 
  
273
 
  two_beta_i = (ec->beta2_i * Py_i) >> 15;      /* Fixed point version, inverted */
274
 
  if (!two_beta_i)
275
 
        two_beta_i++;
276
 
 
277
 
  /* Update Lu_i (Suppressed power estimate) */
278
 
  ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
279
 
  ec->Lu_i += abs(u);
280
 
 
281
 
  /* eq. (10): update power estimate of the reference
282
 
  */
283
 
  ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
284
 
  ec->Ly_i += abs(iref);
285
 
 
286
 
  if (ec->Ly_i < DEFAULT_CUTOFF_I)
287
 
        ec->Ly_i = DEFAULT_CUTOFF_I;
288
 
 
289
 
#if 0
290
 
  printf("Float: %e, Int: %e\n", ec->Ly_d, (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * AMPL_SCALE_1);
291
 
#endif
292
 
  
293
 
  if (ec->y_tilde_i > ec->max_y_tilde) {
294
 
        /* New highest y_tilde with full life */
295
 
        ec->max_y_tilde = ec->y_tilde_i;
296
 
        ec->max_y_tilde_pos = ec->N_d - 1;
297
 
  } else if (--ec->max_y_tilde_pos < 0) {
298
 
    /* Time to find new max y tilde... */
299
 
        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);
300
 
  }
301
 
 
302
 
  if ((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
303
 
    {
304
 
      ec->HCNTR_d = DEFAULT_HANGT;
305
 
    }
306
 
  else if (ec->HCNTR_d > (int)0)
307
 
    {
308
 
      ec->HCNTR_d--;
309
 
    }
310
 
 
311
 
  /* update coefficients if no near-end speech and we have enough signal
312
 
   * to bother trying to update.
313
 
  */
314
 
  if (!ec->HCNTR_d && !(ec->i_d % DEFAULT_M) && 
315
 
      (ec->Lu_i > MIN_UPDATE_THRESH_I)) {
316
 
            // loop over all filter coefficients
317
 
            //
318
 
            for (k=0; k<ec->N_d; k++) {
319
 
              
320
 
              // eq. (7): compute an expectation over M_d samples 
321
 
              //
322
 
                  int grad2;
323
 
              grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
324
 
                                                        ec->y_s.buf_d + ec->y_s.idx_d + k, DEFAULT_M);
325
 
              // eq. (7): update the coefficient
326
 
              //
327
 
              ec->a_i[k] += grad2 / two_beta_i;
328
 
                  ec->a_s[k] = ec->a_i[k] >> 16;
329
 
            }
330
 
  }
331
 
 
332
 
  /* paragraph below eq. (15): if no near-end speech,
333
 
  // check for residual error suppression
334
 
  */
335
 
#ifndef NO_ECHO_SUPPRESSOR
336
 
#ifdef AGGRESSIVE_SUPPRESSOR
337
 
#ifdef AGGRESSIVE_TIMELIMIT /* This allows the aggressive suppressor to turn off after set amount of time */
338
 
  if (ec->i_d > AGGRESSIVE_TIMELIMIT ) {
339
 
        if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
340
 
                u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
341
 
        }
342
 
  }
343
 
  else {
344
 
#endif
345
 
        if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
346
 
                u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
347
 
                u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
348
 
        }
349
 
#ifdef AGGRESSIVE_TIMELIMIT  
350
 
  }
351
 
#endif
352
 
#else   
353
 
  if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
354
 
        u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
355
 
  }
356
 
#endif  
357
 
#endif  
358
 
 
359
 
#if 0
360
 
  if ((ec->HCNTR_d == 0) && ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
361
 
      (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) { 
362
 
    suppr_factor = (10/(float)(SUPPR_FLOOR-SUPPR_CEIL))*log(ec->Lu_d/ec->Ly_d)
363
 
      - SUPPR_CEIL/(float)(SUPPR_FLOOR - SUPPR_CEIL);
364
 
 
365
 
    u_suppr = pow(10.0,(suppr_factor)*RES_SUPR_FACTOR/10.0)*u_suppr;
366
 
    
367
 
  }
368
 
#endif  
369
 
  ec->i_d++;
370
 
  return u;
371
 
}
372
 
 
373
 
static inline echo_can_state_t *echo_can_create(int len, int adaption_mode)
374
 
{
375
 
        echo_can_state_t *ec;
376
 
        int maxy;
377
 
        int maxu;
378
 
        maxy = len + DEFAULT_M;
379
 
        maxu = DEFAULT_M;
380
 
        if (maxy < (1 << DEFAULT_ALPHA_YT_I))
381
 
                maxy = (1 << DEFAULT_ALPHA_YT_I);
382
 
        if (maxy < (1 << DEFAULT_SIGMA_LY_I))
383
 
                maxy = (1 << DEFAULT_SIGMA_LY_I);
384
 
        if (maxu < (1 << DEFAULT_SIGMA_LU_I))
385
 
                maxu = (1 << DEFAULT_SIGMA_LU_I);
386
 
        ec = (echo_can_state_t *)MALLOC(sizeof(echo_can_state_t) +
387
 
                                                                        4 +                                             /* align */
388
 
                                                                        sizeof(int) * len +                     /* a_i */
389
 
                                                                        sizeof(short) * len +           /* a_s */
390
 
                                                                        2 * sizeof(short) * (maxy) +    /* y_s */
391
 
                                                                        2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
392
 
                                                                        2 * sizeof(short) * (maxu) +            /* u_s */
393
 
                                                                        2 * sizeof(short) * len);                       /* y_tilde_s */
394
 
        if (ec) {
395
 
                memset(ec, 0, sizeof(echo_can_state_t) +
396
 
                                                                        4 +                                             /* align */
397
 
                                                                        sizeof(int) * len +                     /* a_i */
398
 
                                                                        sizeof(short) * len +           /* a_s */
399
 
                                                                        2 * sizeof(short) * (maxy) +    /* y_s */
400
 
                                                                        2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
401
 
                                                                        2 * sizeof(short) * (maxu) +            /* u_s */
402
 
                                                                        2 * sizeof(short) * len);                       /* y_tilde_s */
403
 
          init_cc(ec, len, maxy, maxu);
404
 
        }
405
 
        return ec;
406
 
}
407
 
 
408
 
static inline int echo_can_traintap(echo_can_state_t *ec, int pos, short val)
409
 
{
410
 
        /* Reset hang counter to avoid adjustments after
411
 
           initial forced training */
412
 
        ec->HCNTR_d = ec->N_d << 1;
413
 
        if (pos >= ec->N_d)
414
 
                return 1;
415
 
        ec->a_i[pos] = val << 17;
416
 
        ec->a_s[pos] = val << 1;
417
 
        if (++pos >= ec->N_d)
418
 
                return 1;
419
 
        return 0;
420
 
}
421
 
 
422
 
#endif