Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/tests/echo_tests.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * echo_tests.c | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2001 Steve Underwood | |
9 * | |
10 * Based on a bit from here, a bit from there, eye of toad, | |
11 * ear of bat, etc - plus, of course, my own 2 cents. | |
12 * | |
13 * All rights reserved. | |
14 * | |
15 * This program is free software; you can redistribute it and/or modify | |
16 * it under the terms of the GNU General Public License version 2, as | |
17 * published by the Free Software Foundation. | |
18 * | |
19 * This program is distributed in the hope that it will be useful, | |
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 * GNU General Public License for more details. | |
23 * | |
24 * You should have received a copy of the GNU General Public License | |
25 * along with this program; if not, write to the Free Software | |
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
27 * | |
28 * $Id: echo_tests.c,v 1.27 2006/11/19 14:07:27 steveu Exp $ | |
29 */ | |
30 | |
31 /*! \page echo_can_tests_page Line echo cancellation for voice tests | |
32 | |
33 \section echo_can_tests_page_sec_1 What does it do? | |
34 The echo cancellation tests test the echo cancellor against the G.168 spec. Not | |
35 all the tests in G.168 are fully implemented at this time. | |
36 | |
37 \section echo_can_tests_page_sec_2 How does it work? | |
38 | |
39 \section echo_can_tests_page_sec_2 How do I use it? | |
40 | |
41 */ | |
42 | |
43 #ifdef HAVE_CONFIG_H | |
44 #include "config.h" | |
45 #endif | |
46 | |
47 #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) | |
48 #define ENABLE_GUI | |
49 #endif | |
50 | |
51 #define _GNU_SOURCE | |
52 | |
53 #include <unistd.h> | |
54 #include <inttypes.h> | |
55 #include <stdlib.h> | |
56 #include <stdio.h> | |
57 #include <string.h> | |
58 #include <strings.h> | |
59 #if defined(HAVE_TGMATH_H) | |
60 #include <tgmath.h> | |
61 #endif | |
62 #if defined(HAVE_MATH_H) | |
63 #include <math.h> | |
64 #endif | |
65 #include <assert.h> | |
66 #include <audiofile.h> | |
67 #include <tiffio.h> | |
68 | |
69 #define GEN_CONST | |
70 #include <math.h> | |
71 | |
72 #include "spandsp.h" | |
73 #include "spandsp/g168models.h" | |
74 #if defined(ENABLE_GUI) | |
75 #include "echo_monitor.h" | |
76 #endif | |
77 | |
78 #define TEST_EC_TAPS 256 | |
79 | |
80 #if !defined(NULL) | |
81 #define NULL (void *) 0 | |
82 #endif | |
83 | |
84 typedef struct | |
85 { | |
86 const char *name; | |
87 int max; | |
88 int cur; | |
89 AFfilehandle handle; | |
90 int16_t signal[SAMPLE_RATE]; | |
91 } signal_source_t; | |
92 | |
93 typedef struct | |
94 { | |
95 int type; | |
96 fir_float_state_t *fir; | |
97 float history[35*8]; | |
98 int pos; | |
99 float factor; | |
100 float power; | |
101 } level_measurement_device_t; | |
102 | |
103 signal_source_t local_css; | |
104 signal_source_t far_css; | |
105 | |
106 fir32_state_t line_model; | |
107 float model_ki, erl; | |
108 | |
109 AFfilehandle residuehandle; | |
110 int16_t residue_sound[SAMPLE_RATE]; | |
111 int residue_cur = 0; | |
112 int munge; | |
113 | |
114 FILE *fdump; | |
115 | |
116 float clip(float x); | |
117 float clip(float x) { | |
118 if (x > 32767.0) x = 32767.0; | |
119 if (x < -32767.0) x = -32767.0; | |
120 | |
121 return x; | |
122 } | |
123 /*- End of function --------------------------------------------------------*/ | |
124 | |
125 static inline void put_residue(int16_t amp) | |
126 { | |
127 int outframes; | |
128 | |
129 residue_sound[residue_cur++] = amp; | |
130 if (residue_cur >= SAMPLE_RATE) { | |
131 outframes = afWriteFrames(residuehandle, | |
132 AF_DEFAULT_TRACK, | |
133 residue_sound, | |
134 residue_cur); | |
135 if (outframes != residue_cur) | |
136 { | |
137 fprintf(stderr, " Error writing residue sound\n"); | |
138 exit(2); | |
139 } | |
140 residue_cur = 0; | |
141 } | |
142 } | |
143 /*- End of function --------------------------------------------------------*/ | |
144 | |
145 static void signal_load(signal_source_t *sig, const char *name) | |
146 { | |
147 float x; | |
148 | |
149 sig->name = name; | |
150 if ((sig->handle = afOpenFile(sig->name, "r", 0)) == AF_NULL_FILEHANDLE) | |
151 { | |
152 fprintf(stderr, " Cannot open wave file '%s'\n", sig->name); | |
153 exit(2); | |
154 } | |
155 if ((x = afGetFrameSize(sig->handle, AF_DEFAULT_TRACK, 1)) != 2.0) | |
156 { | |
157 fprintf(stderr, " Unexpected frame size in wave file '%s'\n", sig->name); | |
158 exit(2); | |
159 } | |
160 if ((x = afGetRate(sig->handle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) | |
161 { | |
162 printf(" Unexpected sample rate in wave file '%s'\n", sig->name); | |
163 exit(2); | |
164 } | |
165 if ((x = afGetChannels(sig->handle, AF_DEFAULT_TRACK)) != 1.0) | |
166 { | |
167 printf(" Unexpected number of channels in wave file '%s'\n", sig->name); | |
168 exit(2); | |
169 } | |
170 sig->max = afReadFrames(sig->handle, AF_DEFAULT_TRACK, sig->signal, SAMPLE_RATE); | |
171 if (sig->max < 0) | |
172 { | |
173 fprintf(stderr, " Error reading sound file '%s'\n", sig->name); | |
174 exit(2); | |
175 } | |
176 } | |
177 /*- End of function --------------------------------------------------------*/ | |
178 | |
179 static AFfilehandle af_file_open_for_read(const char *name) | |
180 { | |
181 float x; | |
182 AFfilehandle handle; | |
183 | |
184 if ((handle = afOpenFile(name, "r", 0)) == AF_NULL_FILEHANDLE) | |
185 { | |
186 fprintf(stderr, " Cannot open wave file '%s'\n", name); | |
187 exit(2); | |
188 } | |
189 if ((x = afGetFrameSize(handle, AF_DEFAULT_TRACK, 1)) != 2.0) | |
190 { | |
191 fprintf(stderr, " Unexpected frame size in wave file '%s'\n", name); | |
192 exit(2); | |
193 } | |
194 if ((x = afGetRate(handle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) | |
195 { | |
196 printf(" Unexpected sample rate in wave file '%s'\n", name); | |
197 exit(2); | |
198 } | |
199 if ((x = afGetChannels(handle, AF_DEFAULT_TRACK)) != 1.0) | |
200 { | |
201 printf(" Unexpected number of channels in wave file '%s'\n", name); | |
202 exit(2); | |
203 } | |
204 | |
205 return handle; | |
206 } | |
207 /*- End of function --------------------------------------------------------*/ | |
208 | |
209 static AFfilehandle af_file_open_for_write(const char *name) | |
210 { | |
211 AFfilesetup setup; | |
212 AFfilehandle handle; | |
213 | |
214 setup = afNewFileSetup(); | |
215 if (setup == AF_NULL_FILESETUP) | |
216 { | |
217 fprintf(stderr, " %s: Failed to create file setup\n", name); | |
218 exit(2); | |
219 } | |
220 afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); | |
221 afInitRate(setup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); | |
222 afInitFileFormat(setup, AF_FILE_WAVE); | |
223 afInitChannels(setup, AF_DEFAULT_TRACK, 1); | |
224 handle = afOpenFile(name, "w", setup); | |
225 | |
226 if (handle == AF_NULL_FILEHANDLE) | |
227 { | |
228 fprintf(stderr, " Failed to open result file\n"); | |
229 exit(2); | |
230 } | |
231 afFreeFileSetup(setup); | |
232 | |
233 return handle; | |
234 } | |
235 /*- End of function --------------------------------------------------------*/ | |
236 | |
237 static void signal_restart(signal_source_t *sig) | |
238 { | |
239 sig->cur = 0; | |
240 } | |
241 /*- End of function --------------------------------------------------------*/ | |
242 | |
243 static int16_t signal_amp(signal_source_t *sig) | |
244 { | |
245 int16_t tx; | |
246 | |
247 tx = sig->signal[sig->cur++]; | |
248 if (sig->cur >= sig->max) | |
249 sig->cur = 0; | |
250 return tx; | |
251 } | |
252 /*- End of function --------------------------------------------------------*/ | |
253 | |
254 /* note mu-law used, alaw has big DC Offsets that causes probs with G168 | |
255 tests, due to alaw idle values being passed thru when NLP opens for | |
256 very low level signals. Probably need a DC blocking filter in e/c | |
257 */ | |
258 static inline int16_t codec_munge(int16_t amp) | |
259 { | |
260 return ulaw_to_linear(linear_to_ulaw(amp)); | |
261 } | |
262 /*- End of function --------------------------------------------------------*/ | |
263 | |
264 static int channel_model_create(int model) | |
265 { | |
266 static const int32_t *line_models[] = | |
267 { | |
268 line_model_d2_coeffs, | |
269 line_model_d3_coeffs, | |
270 line_model_d4_coeffs, | |
271 line_model_d5_coeffs, | |
272 line_model_d6_coeffs, | |
273 line_model_d7_coeffs, | |
274 line_model_d8_coeffs, | |
275 line_model_d9_coeffs | |
276 }; | |
277 | |
278 static int line_model_sizes[] = | |
279 { | |
280 sizeof(line_model_d2_coeffs)/sizeof(int32_t), | |
281 sizeof(line_model_d3_coeffs)/sizeof(int32_t), | |
282 sizeof(line_model_d4_coeffs)/sizeof(int32_t), | |
283 sizeof(line_model_d5_coeffs)/sizeof(int32_t), | |
284 sizeof(line_model_d6_coeffs)/sizeof(int32_t), | |
285 sizeof(line_model_d7_coeffs)/sizeof(int32_t), | |
286 sizeof(line_model_d8_coeffs)/sizeof(int32_t), | |
287 sizeof(line_model_d9_coeffs)/sizeof(int32_t) | |
288 }; | |
289 | |
290 static float ki[] = | |
291 { | |
292 1.39E-5, 1.44E-5, 1.52E-5, 1.77E-5, 9.33E-6, 1.51E-5, 2.33E-5, 1.33E-5 | |
293 }; | |
294 | |
295 if (model < 1 || model > (int) (sizeof(line_model_sizes)/sizeof(line_model_sizes[0]))) | |
296 return -1; | |
297 fir32_create(&line_model, line_models[model-1], line_model_sizes[model-1]); | |
298 | |
299 model_ki = ki[model-1]; | |
300 | |
301 return 0; | |
302 } | |
303 /*- End of function --------------------------------------------------------*/ | |
304 | |
305 static int16_t channel_model(int16_t *new_local, int16_t *new_far, int16_t local, int16_t far) | |
306 { | |
307 int16_t echo; | |
308 int16_t rx; | |
309 | |
310 /* Channel modelling is merely simulating the effects of A-law or u-law distortion | |
311 and using one of the echo models from G.168. Simulating the codec is very important, | |
312 as this is usually the limiting factor in how much echo reduction is achieved. */ | |
313 | |
314 /* The local tx signal will usually have gone through an A-law munging before | |
315 it reached the line's analogue area, where the echo occurs. */ | |
316 if (munge == TRUE) | |
317 local = codec_munge(local); | |
318 /* Now we need to model the echo. We only model a single analogue segment, as per | |
319 the G.168 spec. However, there will generally be near end and far end analogue/echoey | |
320 segments in the real world, unless an end is purely digital. */ | |
321 echo = fir32(&line_model, local*erl*(32768.0*model_ki)); | |
322 /* The far end signal will have been through an A-law munging, although | |
323 this should not affect things. */ | |
324 if (munge == TRUE) | |
325 rx = clip(echo + codec_munge(far)); | |
326 else | |
327 rx = clip(echo + far); | |
328 | |
329 /* This mixed echo and far end signal will have been through an A-law munging | |
330 when it came back into the digital network. */ | |
331 if (munge == TRUE) | |
332 rx = codec_munge(rx); | |
333 if (new_far) | |
334 *new_far = rx; | |
335 if (new_local) | |
336 *new_local = local; | |
337 return rx; | |
338 } | |
339 /*- End of function --------------------------------------------------------*/ | |
340 | |
341 /* | |
342 250Hz HP filter, designed using this excellent site: | |
343 | |
344 http://www-users.cs.york.ac.uk/~fisher/mkfilter/ | |
345 | |
346 Included as preliminary test to see if this sort of filter will help | |
347 hum removal from low cost X100P type cards. Unfortunately I couldn't | |
348 get thios to work well in fixed point, so had to leave it out of | |
349 treh core echo canceller. | |
350 */ | |
351 | |
352 #define NZEROS 4 | |
353 #define NPOLES 4 | |
354 | |
355 #define FIXED | |
356 #ifdef FIXED | |
357 #define GAIN 1.293080949e+00 | |
358 #define QCONST32(x,bits) ((int)((x)*(1<<(bits)))) | |
359 | |
360 static int hp_filter(int xv[], int yv[], int x) | |
361 { | |
362 xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; | |
363 xv[4] = x * (int)((1<<5)/GAIN); | |
364 yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; | |
365 yv[4] = (xv[0] + xv[4]) - 4 * (xv[1] + xv[3]) + 6 * xv[2]; | |
366 yv[4] += (QCONST32(-0.5980652616f, 10) * yv[0]) >> 10; | |
367 yv[4] += (QCONST32( 2.6988843913f, 10) * yv[1]) >> 10; | |
368 yv[4] += (QCONST32(-4.5892912321f, 10) * yv[2]) >> 10; | |
369 yv[4] += (QCONST32( 3.4873077415f, 10) * yv[3]) >> 10; | |
370 | |
371 return yv[4] >> 5; | |
372 } | |
373 | |
374 #else | |
375 #define GAIN 1.293080949e+00 | |
376 | |
377 static float hp_filter(float xv[], float yv[], float x) | |
378 { | |
379 xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; | |
380 xv[4] = x / GAIN; | |
381 yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; | |
382 yv[4] = (xv[0] + xv[4]) - 4 * (xv[1] + xv[3]) + 6 * xv[2] | |
383 + ( -0.5980652616 * yv[0]) + ( 2.6988843913 * yv[1]) | |
384 + ( -4.5892912321 * yv[2]) + ( 3.4873077415 * yv[3]); | |
385 return yv[4]; | |
386 } | |
387 #endif | |
388 | |
389 static level_measurement_device_t *level_measurement_device_create(int type) | |
390 { | |
391 level_measurement_device_t *dev; | |
392 int i; | |
393 | |
394 dev = (level_measurement_device_t *) malloc(sizeof(level_measurement_device_t)); | |
395 dev->fir = (fir_float_state_t *) malloc(sizeof(fir_float_state_t)); | |
396 fir_float_create(dev->fir, | |
397 level_measurement_bp_coeffs, | |
398 sizeof(level_measurement_bp_coeffs)/sizeof(float)); | |
399 for (i = 0; i < 35*8; i++) | |
400 dev->history[i] = 0.0; | |
401 dev->pos = 0; | |
402 dev->factor = exp(-1.0/((float) SAMPLE_RATE*0.035)); | |
403 dev->power = 0; | |
404 dev->type = type; | |
405 return dev; | |
406 } | |
407 /*- End of function --------------------------------------------------------*/ | |
408 | |
409 static void level_measurement_device_reset(level_measurement_device_t *dev) | |
410 { | |
411 int i; | |
412 | |
413 for (i = 0; i < 35*8; i++) | |
414 dev->history[i] = 0.0; | |
415 dev->pos = 0; | |
416 dev->power = 0; | |
417 } | |
418 /*- End of function --------------------------------------------------------*/ | |
419 | |
420 static int level_measurement_device_release(level_measurement_device_t *s) | |
421 { | |
422 fir_float_free(s->fir); | |
423 free(s->fir); | |
424 free(s); | |
425 return 0; | |
426 } | |
427 /*- End of function --------------------------------------------------------*/ | |
428 | |
429 static float level_measurement_device(level_measurement_device_t *dev, int16_t amp) | |
430 { | |
431 float signal; | |
432 | |
433 signal = fir_float(dev->fir, amp); | |
434 signal *= signal; | |
435 if (dev->type == 0) | |
436 { | |
437 dev->power = dev->power*dev->factor + signal*(1.0 - dev->factor); | |
438 signal = sqrt(dev->power); | |
439 } | |
440 else | |
441 { | |
442 dev->power -= dev->history[dev->pos]; | |
443 dev->power += signal; | |
444 dev->history[dev->pos++] = signal; | |
445 signal = sqrt(dev->power/(35.8*8.0)); | |
446 } | |
447 if (signal > 0.0) | |
448 return DBM0_MAX_POWER + 20.0*log10(signal/32767.0); | |
449 else | |
450 return -1000.0; | |
451 } | |
452 /*- End of function --------------------------------------------------------*/ | |
453 | |
454 /* Globals used for performing tests */ | |
455 | |
456 echo_can_state_t *ctx; | |
457 awgn_state_t sgen_noise_source; | |
458 awgn_state_t rin_noise_source; | |
459 | |
460 level_measurement_device_t *Rin_power_meter; | |
461 level_measurement_device_t *Sgen_power_meter; | |
462 level_measurement_device_t *Sin_power_meter; | |
463 level_measurement_device_t *Sout_power_meter; | |
464 | |
465 float LRin, maxLRin; | |
466 float LSgen, maxLSgen; | |
467 float LSin, maxLSin; | |
468 float LSout, maxLSout; | |
469 float Lres, maxLres; | |
470 float test_clock; | |
471 float maxHoth; | |
472 | |
473 float Rin_level, Sgen_level; | |
474 FILE *flevel; | |
475 int Rin_type, Sgen_type; | |
476 int failed; | |
477 int verbose, quiet; | |
478 float threshold; | |
479 int model_number; | |
480 char test_name[80]; | |
481 | |
482 tone_gen_state_t rin_tone_state; | |
483 tone_gen_state_t sgen_tone_state; | |
484 | |
485 /* | |
486 Test callback functions are called one for every processed sample | |
487 during run_test(). They are user supplied, and return TRUE if the | |
488 test is passing or FALSE if a combination of variables mean that | |
489 the test has failed (for example Lres exceeding some threshold). | |
490 | |
491 Different test callback functions are required for each G168 test. | |
492 */ | |
493 int (*test_callback)(void); | |
494 | |
495 /* macros to convert units for run_test */ | |
496 | |
497 #define MSEC (SAMPLE_RATE/1000) | |
498 #define SEC SAMPLE_RATE | |
499 | |
500 /* Sgen signal generator types */ | |
501 | |
502 #define NONE 0 | |
503 #define CSS 1 | |
504 #define HOTH 2 | |
505 #define TONE 3 | |
506 | |
507 /* Experimentally generated constants to normalise levels to dBm0 */ | |
508 | |
509 #define HOTH_SCALE 2.40 | |
510 #define CSS_SCALE 5.60 | |
511 | |
512 static void reset_all(void) { | |
513 echo_can_flush(ctx); | |
514 maxLRin = maxLSgen = maxLSin = maxLSout = maxLres = -100.0; | |
515 signal_restart(&local_css); | |
516 signal_restart(&far_css); | |
517 test_callback = NULL; | |
518 Rin_type = CSS; | |
519 Sgen_type = NONE; | |
520 failed = FALSE; | |
521 test_clock = 0.0; | |
522 } | |
523 | |
524 static void reset_meter_peaks(void) { | |
525 maxLRin = maxLSgen = maxLSin = maxLSout = maxLres = -100.0; | |
526 } | |
527 | |
528 static void install_test_callback(int (*f)(void)) { | |
529 test_callback = f; | |
530 } | |
531 | |
532 /* note: maybe we should use absolute levels rather than gain? Need to | |
533 normalise levels from various signal types to do this */ | |
534 | |
535 static void set_Sgen(int source_type, float gain) { | |
536 Sgen_type = source_type; | |
537 Sgen_level = pow(10.0, gain/20.0); | |
538 } | |
539 | |
540 static void set_Rin(int source_type, float gain) { | |
541 Rin_type = source_type; | |
542 Rin_level = pow(10.0, gain/20.0); | |
543 } | |
544 | |
545 static void mute_Rin(void) { | |
546 Rin_type = NONE; | |
547 } | |
548 | |
549 static void unmute_Rin(void) { | |
550 Rin_type = CSS; | |
551 } | |
552 | |
553 static void update_levels(int16_t rin, int16_t sin, int16_t sout, int16_t sgen) | |
554 { | |
555 LRin = level_measurement_device(Rin_power_meter, rin); | |
556 LSin = level_measurement_device(Sin_power_meter, sin); | |
557 LSout = level_measurement_device(Sout_power_meter, sout); | |
558 LSgen = level_measurement_device(Sgen_power_meter, sgen); | |
559 if (LRin > maxLRin) maxLRin = LRin; | |
560 if (LSin > maxLSin) maxLSin = LSin; | |
561 if (LSout > maxLSout) maxLSout = LSout; | |
562 if (LSgen > maxLSgen) maxLSgen = LSgen; | |
563 } | |
564 | |
565 static void write_log_files(int16_t rout, int16_t sin) | |
566 { | |
567 fprintf(flevel, "%f\t%f\t%f\t%f\n",LRin, LSin, LSout, LSgen); | |
568 fprintf(fdump, "%d %d %d", ctx->tx, ctx->rx, ctx->clean); | |
569 fprintf(fdump, " %d %d %d %d %d %d %d %d %d %d\n", ctx->clean_nlp, ctx->Ltx, | |
570 ctx->Lrx, ctx->Lclean, | |
571 (ctx->nonupdate_dwell > 0), ctx->adapt, ctx->Lclean_bg, ctx->Pstates, | |
572 ctx->Lbgn_upper, ctx->Lbgn); | |
573 } | |
574 | |
575 static void run_test(float time, float units) { | |
576 int i; | |
577 int samples; | |
578 int16_t rout, rin=0, sin; | |
579 int16_t sgen=0, sout; | |
580 float rin_hoth_noise = 0; | |
581 float sgen_hoth_noise = 0; | |
582 | |
583 samples = time * units; | |
584 | |
585 for (i = 0; i < samples; i++) { | |
586 | |
587 switch(Rin_type) { | |
588 case NONE: | |
589 rin = 0; | |
590 break; | |
591 case CSS: | |
592 rin = clip(Rin_level*signal_amp(&local_css)*CSS_SCALE); | |
593 break; | |
594 case HOTH: | |
595 rin_hoth_noise = rin_hoth_noise*0.625 + awgn(&rin_noise_source)*0.375; | |
596 rin = clip(Rin_level*rin_hoth_noise*HOTH_SCALE); | |
597 break; | |
598 case TONE: | |
599 tone_gen(&rin_tone_state, &rin, 1); | |
600 break; | |
601 } | |
602 | |
603 switch(Sgen_type) { | |
604 case NONE: | |
605 sgen = 0; | |
606 break; | |
607 case CSS: | |
608 sgen = clip(Sgen_level*signal_amp(&far_css)*CSS_SCALE); | |
609 break; | |
610 case HOTH: | |
611 sgen_hoth_noise = sgen_hoth_noise*0.625 + awgn(&sgen_noise_source)*0.375; | |
612 sgen = clip(Sgen_level*sgen_hoth_noise*HOTH_SCALE); | |
613 break; | |
614 case TONE: | |
615 tone_gen(&sgen_tone_state, &sgen, 1); | |
616 break; | |
617 } | |
618 | |
619 rout = echo_can_hpf_tx(ctx, rin); | |
620 channel_model(&rout, &sin, rin, sgen); | |
621 sout = echo_can_update(ctx, rout, sin); | |
622 update_levels(rin, sin, sout, sgen); | |
623 write_log_files(rout, sin); | |
624 | |
625 /* now test for fail condition */ | |
626 if (test_callback != NULL) { | |
627 if ( (failed == FALSE) && (test_callback() == FALSE)) { | |
628 /* test has failed */ | |
629 failed = TRUE; | |
630 } | |
631 } | |
632 | |
633 /* stop clock on fail - points to time of failure in test */ | |
634 | |
635 if (failed == FALSE) | |
636 test_clock += (float)1/SAMPLE_RATE; | |
637 } | |
638 } | |
639 | |
640 static void print_title(const char *title) { | |
641 if (quiet == FALSE) | |
642 printf(title); | |
643 } | |
644 | |
645 static void print_results(void) { | |
646 | |
647 if (quiet == FALSE) | |
648 printf("test model ERL time Max Rin Max Sin Max Sgen Max Sout Result\n"); | |
649 printf("%-4s %-1d %-5.1f%6.2fs%9.2f%9.2f%10.2f%10.2f ", | |
650 test_name, model_number, 20.0*log10(erl), | |
651 test_clock, maxLRin, maxLSin, maxLSgen, maxLSout); | |
652 if (failed == TRUE) | |
653 printf("FAIL\n"); | |
654 else | |
655 printf("PASS\n"); | |
656 } | |
657 | |
658 static int test_2a(void) { | |
659 if (LSout > -65.0) | |
660 return FALSE; | |
661 else | |
662 return TRUE; | |
663 } | |
664 | |
665 static int test_2c(void) { | |
666 if (LSout > maxHoth) | |
667 return FALSE; | |
668 else | |
669 return TRUE; | |
670 } | |
671 | |
672 static int test_3a(void) { | |
673 if (LSout > maxLSgen) | |
674 return FALSE; | |
675 else | |
676 return TRUE; | |
677 } | |
678 | |
679 static int test_3b(void) { | |
680 if (LSout > threshold) | |
681 return FALSE; | |
682 else | |
683 return TRUE; | |
684 } | |
685 | |
686 static int test_3c_t2(void) { | |
687 if (LSout > maxLSgen) | |
688 return FALSE; | |
689 else | |
690 return TRUE; | |
691 } | |
692 | |
693 static int test_3c_t4t5(void) { | |
694 if (LSout > (maxLSgen+6.0)) | |
695 return FALSE; | |
696 else | |
697 return TRUE; | |
698 } | |
699 | |
700 static int test_9(void) { | |
701 if (fabs(LSout - LSgen) > 2.0) | |
702 return FALSE; | |
703 else | |
704 return TRUE; | |
705 } | |
706 | |
707 #define N_TESTS 9 | |
708 static const char *supported_tests[] = {"ut1", "2aa", "2ca", "3a", "3ba", | |
709 "3bb", "3c", "6", "9"}; | |
710 | |
711 static int is_test_supported(char *test) { | |
712 int i; | |
713 for(i=0; i<N_TESTS; i++) { | |
714 if (!strcasecmp(test, supported_tests[i])) | |
715 return TRUE; | |
716 } | |
717 | |
718 return FALSE; | |
719 } | |
720 | |
721 /* dump estimate echo response */ | |
722 static void dump_h(void) { | |
723 int i; | |
724 FILE *f = fopen("h.txt","wt"); | |
725 for(i=0; i<TEST_EC_TAPS; i++) { | |
726 fprintf(f, "%f\n", (float)ctx->fir_taps16[0][i]/(1<<15)); | |
727 } | |
728 fclose(f); | |
729 } | |
730 | |
731 int main(int argc, char *argv[]) | |
732 { | |
733 //awgn_state_t local_noise_source; | |
734 int i; | |
735 //int j; | |
736 //int k; | |
737 //tone_gen_descriptor_t tone_desc; | |
738 //tone_gen_state_t tone_state; | |
739 //int16_t local_sound[40000]; | |
740 //int local_max; | |
741 //int local_cur; | |
742 int far_cur; | |
743 int result_cur; | |
744 AFfilehandle txfile, rxfile, ecfile; | |
745 time_t now; | |
746 int tone_burst_step; | |
747 float X_level, Sgen_leveldB; | |
748 #ifdef FIXED | |
749 int xvrx[NZEROS+1], yvrx[NPOLES+1]; | |
750 int xvtx[NZEROS+1], yvtx[NPOLES+1]; | |
751 #else | |
752 float xvrx[NZEROS+1], yvrx[NPOLES+1]; | |
753 float xvtx[NZEROS+1], yvtx[NPOLES+1]; | |
754 #endif | |
755 | |
756 int file_mode; | |
757 float tmp; | |
758 int cng; | |
759 int hpf; | |
760 | |
761 /* default config ------------------------------------------------*/ | |
762 | |
763 model_number = 1; | |
764 erl = pow(10.0, -10.0/20.0); | |
765 verbose = quiet = FALSE; | |
766 file_mode = FALSE; | |
767 Rin_level = pow(10.0, -15.0/20.0); | |
768 Sgen_leveldB = -15.0; | |
769 Sgen_level = pow(10.0, Sgen_leveldB/20.0); | |
770 X_level = pow(10.0, 6.0/20.0); | |
771 tone_burst_step = 0; | |
772 txfile = rxfile = ecfile = NULL; | |
773 munge = TRUE; | |
774 cng = FALSE; | |
775 hpf = TRUE; | |
776 for(i=0; i<NPOLES+1; i++) { | |
777 xvtx[i] = yvtx[i] = xvrx[i] = yvrx[i] = 0.0; | |
778 } | |
779 | |
780 /* Check which tests we should run ----------------------------------------*/ | |
781 | |
782 if (argc < 2) { | |
783 fprintf(stderr, "Usage: echo [2aa] [2ca] [3a] [3ba] [3bb] [3c] [6] [9]\n" | |
784 "[-m ChannelModelNumber]\n" | |
785 "[-erl ERL_in_dB\n" | |
786 "[-file RinInputFile.wav SinInputFile.wav SoutOutputFile.wav\n" | |
787 "[-r RinLeveldBm0] [-s SgenLeveldBm0] [-x XLeveldB]\n" | |
788 "[-nomunge]\n" | |
789 "[-cng]\n" | |
790 "[-nohpf] Disable DC block HPF (-file mode)\n"); | |
791 | |
792 exit(1); | |
793 } | |
794 | |
795 for (i = 1; i < argc; i++) | |
796 { | |
797 if (is_test_supported(argv[i])) { | |
798 } | |
799 else if (strcmp(argv[i], "-m") == 0) | |
800 { | |
801 if (++i < argc) | |
802 model_number = atoi(argv[i]); | |
803 } | |
804 else if (strcmp(argv[i], "-r") == 0) | |
805 { | |
806 if (++i < argc) | |
807 Rin_level = pow(10.0, atof(argv[i])/20.0); | |
808 } | |
809 else if (strcmp(argv[i], "-s") == 0) | |
810 { | |
811 if (++i < argc) { | |
812 Sgen_leveldB = atof(argv[i]); | |
813 Sgen_level = pow(10.0, Sgen_leveldB/20.0); | |
814 } | |
815 } | |
816 else if (strcmp(argv[i], "-x") == 0) | |
817 { | |
818 if (++i < argc) | |
819 X_level = pow(10.0, atof(argv[i])/20.0); | |
820 } | |
821 else if (strcmp(argv[i], "-erl") == 0) | |
822 { | |
823 if (++i < argc) { | |
824 erl = atof(argv[i]); | |
825 if (erl < 0.0) { | |
826 printf("ERL must be >= 0.0 dB\n"); | |
827 exit(1); | |
828 } | |
829 erl = pow(10.0, -erl/20.0); | |
830 } | |
831 } | |
832 else if (strcmp(argv[i], "-v") == 0) | |
833 { | |
834 verbose = TRUE; | |
835 } | |
836 else if (strcmp(argv[i], "-q") == 0) | |
837 { | |
838 quiet = TRUE; | |
839 } | |
840 else if (strcmp(argv[i], "-file") == 0) | |
841 { | |
842 file_mode = TRUE; | |
843 if (argc < (i+3)) { | |
844 printf("not enough arguments for --file\n"); | |
845 exit(2); | |
846 } | |
847 txfile = af_file_open_for_read(argv[i+1]); | |
848 rxfile = af_file_open_for_read(argv[i+2]); | |
849 ecfile = af_file_open_for_write(argv[i+3]); | |
850 i += 3; | |
851 } | |
852 else if (strcmp(argv[i], "-nomunge") == 0) | |
853 { | |
854 munge = FALSE; | |
855 } | |
856 else if (strcmp(argv[i], "-cng") == 0) | |
857 { | |
858 cng = TRUE; | |
859 } | |
860 else if (strcmp(argv[i], "-nohpf") == 0) | |
861 { | |
862 hpf = FALSE; | |
863 } | |
864 else | |
865 { | |
866 fprintf(stderr, "Unknown test/option '%s' specified\n", argv[i]); | |
867 exit(2); | |
868 } | |
869 } | |
870 | |
871 /* initialise a bunch of modules we need ------------------------------*/ | |
872 | |
873 time(&now); | |
874 | |
875 ctx = echo_can_create(TEST_EC_TAPS, 0); | |
876 awgn_init_dbm0(&rin_noise_source, 7162534, 0.0f); | |
877 awgn_init_dbm0(&sgen_noise_source, 7162534, 0.0f); | |
878 Rin_power_meter = level_measurement_device_create(0); | |
879 Sgen_power_meter = level_measurement_device_create(0); | |
880 Sin_power_meter = level_measurement_device_create(0); | |
881 Sout_power_meter = level_measurement_device_create(0); | |
882 if (channel_model_create(model_number)) | |
883 { | |
884 fprintf(stderr, " Failed to create line model\n"); | |
885 exit(2); | |
886 } | |
887 | |
888 far_cur = 0; | |
889 result_cur = 0; | |
890 | |
891 if (verbose == TRUE) { | |
892 printf("ERL (linear)......: %6.2f (%5.2f)\n" | |
893 "Rin level (linear).: %6.2f (%5.2f)\n" | |
894 "Sgen level (linear): %6.2f (%5.2f)\n", | |
895 20.0*log10(erl), erl, | |
896 20.0*log10(Rin_level), Rin_level, | |
897 20.0*log10(Sgen_level), Sgen_level); | |
898 } | |
899 | |
900 fdump = fopen("dump.txt","wt"); | |
901 assert(fdump != NULL); | |
902 flevel = fopen("level.txt","wt"); | |
903 assert(flevel != NULL); | |
904 | |
905 if (file_mode == TRUE) { | |
906 /* process wave files instead of running tests, useful for | |
907 testing real world signals */ | |
908 int ntx, nrx, nec; | |
909 int16_t rin, rout, sin, sout; | |
910 int mode; | |
911 | |
912 mode = ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP; | |
913 if (cng) | |
914 mode |= ECHO_CAN_USE_CNG; | |
915 else | |
916 mode |= ECHO_CAN_USE_CLIP; | |
917 if (hpf) { | |
918 mode |= ECHO_CAN_USE_TX_HPF; | |
919 mode |= ECHO_CAN_USE_RX_HPF; | |
920 } | |
921 echo_can_adaption_mode(ctx, mode); | |
922 do { | |
923 ntx = afReadFrames(txfile, AF_DEFAULT_TRACK, &rin, 1); | |
924 if (ntx < 0) { | |
925 fprintf(stderr, " Error reading tx sound file\n"); | |
926 exit(2); | |
927 } | |
928 nrx = afReadFrames(rxfile, AF_DEFAULT_TRACK, &sin, 1); | |
929 if (nrx < 0) { | |
930 fprintf(stderr, " Error reading rx sound file\n"); | |
931 exit(2); | |
932 } | |
933 | |
934 rout = echo_can_hpf_tx(ctx, rin); | |
935 sout = echo_can_update(ctx, rout, sin); | |
936 | |
937 nec = afWriteFrames(ecfile, AF_DEFAULT_TRACK, &sout, 1); | |
938 if (nec != 1) { | |
939 fprintf(stderr, " Error writing ec sound file\n"); | |
940 exit(2); | |
941 } | |
942 | |
943 update_levels(rin, sin, sout, 0); | |
944 write_log_files(rin, sin); | |
945 | |
946 } while (ntx && nrx); | |
947 | |
948 dump_h(); | |
949 | |
950 afCloseFile(txfile); | |
951 afCloseFile(rxfile); | |
952 afCloseFile(ecfile); | |
953 exit(0); | |
954 } | |
955 | |
956 signal_load(&local_css, "sound_c1_8k.wav"); | |
957 signal_load(&far_css, "sound_c3_8k.wav"); | |
958 | |
959 strcpy(test_name, argv[1]); | |
960 | |
961 /* basic unit test used in e/c dvelopment */ | |
962 | |
963 if (!strcasecmp(argv[1], "ut1")) { | |
964 int16_t rin, sin, rout, sout, sgen; | |
965 | |
966 print_title("Performing Unit Test 1 - DC inputs\n"); | |
967 reset_all(); | |
968 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
969 | |
970 rout = rin = 2000; | |
971 sin = 1000; | |
972 sgen = 0; | |
973 for(i=0; i<10; i++) { | |
974 rout = 2000+2*i; | |
975 sout = echo_can_update(ctx, rout, sin); | |
976 update_levels(rin, sin, sout, sgen); | |
977 write_log_files(rout, sin); | |
978 } | |
979 dump_h(); | |
980 } | |
981 | |
982 /* Test 1 - Steady state residual and returned echo level test */ | |
983 /* This functionality has been merged with test 2 in newer versions of G.168, | |
984 so test 1 no longer exists. */ | |
985 | |
986 /* Test 2 - Convergence and steady state residual and returned echo level test */ | |
987 | |
988 /* | |
989 NOTE: This test is only partially implemented, only the conidtion after | |
990 1s is tested and I am still not sure if LSout == Lres in the part | |
991 of the test after 1s. | |
992 */ | |
993 | |
994 if (!strcasecmp(argv[1], "2aa")) { | |
995 | |
996 print_title("Performing test 2A(a) - Convergence with NLP enabled\n"); | |
997 reset_all(); | |
998 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP); | |
999 | |
1000 /* initial zero input as reqd by G168 */ | |
1001 | |
1002 mute_Rin(); | |
1003 run_test(200, MSEC); | |
1004 unmute_Rin(); | |
1005 | |
1006 /* Now test convergence */ | |
1007 | |
1008 run_test(1, SEC); | |
1009 reset_meter_peaks(); | |
1010 install_test_callback(test_2a); | |
1011 run_test(10, SEC); | |
1012 | |
1013 print_results(); | |
1014 } | |
1015 | |
1016 #ifdef OTHER_TESTS | |
1017 if ((test_list & PERFORM_TEST_2B)) | |
1018 { | |
1019 printf("Performing test 2B - Re-convergence with NLP disabled\n"); | |
1020 | |
1021 /* Test 2B - Re-convergence with NLP disabled */ | |
1022 | |
1023 echo_can_flush(ctx); | |
1024 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1025 | |
1026 /* Converge a canceller */ | |
1027 | |
1028 signal_restart(&local_css); | |
1029 for (i = 0; i < 800*2; i++) | |
1030 { | |
1031 clean = echo_can_update(ctx, 0, 0); | |
1032 put_residue(clean); | |
1033 } | |
1034 | |
1035 for (i = 0; i < SAMPLE_RATE*5; i++) | |
1036 { | |
1037 tx = signal_amp(&local_css); | |
1038 channel_model(&tx, &rx, tx, 0); | |
1039 clean = echo_can_update(ctx, tx, rx); | |
1040 put_residue(clean); | |
1041 #if defined(ENABLE_GUI) | |
1042 if (use_gui) | |
1043 echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS); | |
1044 #endif | |
1045 } | |
1046 #if defined(ENABLE_GUI) | |
1047 if (use_gui) | |
1048 echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS); | |
1049 #endif | |
1050 } | |
1051 #endif | |
1052 | |
1053 if (!strcasecmp(argv[1], "2ca")) { | |
1054 float SgenLeveldB; | |
1055 | |
1056 print_title("Performing test 2C(a) - Convergence with background noise present\n"); | |
1057 reset_all(); | |
1058 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP); | |
1059 | |
1060 /* Converge canceller with background noise */ | |
1061 | |
1062 mute_Rin(); | |
1063 run_test(200, MSEC); | |
1064 unmute_Rin(); | |
1065 | |
1066 SgenLeveldB = 20.0*log10(Rin_level) - 15.0; | |
1067 if (SgenLeveldB > -30.0) SgenLeveldB = -30.0; | |
1068 set_Sgen(HOTH, SgenLeveldB); | |
1069 run_test(1, SEC); | |
1070 maxHoth = maxLSgen; | |
1071 | |
1072 /* After 1 second freeze adaption, switch off noise. */ | |
1073 | |
1074 mute_Rin(); | |
1075 run_test(150, MSEC); | |
1076 | |
1077 echo_can_adaption_mode(ctx, ECHO_CAN_USE_NLP); | |
1078 run_test(1, SEC); | |
1079 | |
1080 unmute_Rin(); | |
1081 set_Sgen(NONE, 0.0); | |
1082 run_test(500, MSEC); | |
1083 | |
1084 /* now measure the echo */ | |
1085 | |
1086 reset_meter_peaks(); | |
1087 maxLSgen = maxHoth; /* keep this peak for print out but reset the rest */ | |
1088 install_test_callback(test_2c); | |
1089 set_Sgen(NONE, 0.0); | |
1090 run_test(5, SEC); | |
1091 | |
1092 print_results(); | |
1093 } | |
1094 | |
1095 /* Test 3 - Performance under double talk conditions */ | |
1096 | |
1097 if (!strcasecmp(argv[1], "3a")) { | |
1098 print_title("Performing test 3A - Double talk test with low cancelled-end levels\n"); | |
1099 reset_all(); | |
1100 | |
1101 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1102 set_Sgen(CSS, -15.0 + 20.0*log10(Rin_level)); | |
1103 run_test(5, SEC); | |
1104 tmp = maxLSgen; | |
1105 | |
1106 /* now freeze adaption */ | |
1107 | |
1108 echo_can_adaption_mode(ctx, 0); | |
1109 set_Sgen(NONE, 0.0); | |
1110 run_test(500, MSEC); | |
1111 | |
1112 /* Now measure the echo */ | |
1113 | |
1114 reset_meter_peaks(); | |
1115 maxLSgen = tmp; | |
1116 install_test_callback(test_3a); | |
1117 run_test(5, SEC); | |
1118 | |
1119 print_results(); | |
1120 } | |
1121 | |
1122 if (!strcasecmp(argv[1], "3ba")) { | |
1123 float fig11; | |
1124 | |
1125 print_title("Performing test 3B(a) - Double talk stability test with high cancelled-end levels\n"); | |
1126 reset_all(); | |
1127 | |
1128 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1129 run_test(5, SEC); | |
1130 | |
1131 /* Apply double talk */ | |
1132 | |
1133 set_Sgen(CSS, 20.0*log10(Sgen_level)); | |
1134 run_test(5, SEC); | |
1135 tmp = maxLSgen; | |
1136 | |
1137 /* freeze adaption and measure echo */ | |
1138 | |
1139 mute_Rin(); | |
1140 run_test(150, MSEC); | |
1141 | |
1142 echo_can_adaption_mode(ctx, 0); | |
1143 run_test(1, SEC); | |
1144 | |
1145 unmute_Rin(); | |
1146 set_Sgen(NONE, 0.0); | |
1147 run_test(500, MSEC); | |
1148 | |
1149 /* Now measure the echo */ | |
1150 | |
1151 fig11 = (25.0/30.0)*maxLRin - 30.0; /* pass/fail based on clean level @ tx peak */ | |
1152 threshold = fig11 + 10.0; | |
1153 reset_meter_peaks(); | |
1154 maxLSgen = tmp; | |
1155 install_test_callback(test_3b); | |
1156 run_test(5, SEC); | |
1157 | |
1158 print_results(); | |
1159 } | |
1160 | |
1161 if (!strcasecmp(argv[1], "3bb")) { | |
1162 float fig11; | |
1163 | |
1164 print_title("Performing test 3B(b) - Double talk stability test with low cancelled-end levels\n"); | |
1165 reset_all(); | |
1166 | |
1167 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1168 run_test(5, SEC); | |
1169 | |
1170 /* Apply double talk */ | |
1171 | |
1172 set_Sgen(CSS, 20.0*log10(Rin_level) - 20.0*log10(X_level)); | |
1173 run_test(5, SEC); | |
1174 tmp = maxLSgen; | |
1175 | |
1176 /* freeze adaption and measure echo */ | |
1177 | |
1178 mute_Rin(); | |
1179 run_test(150, MSEC); | |
1180 | |
1181 echo_can_adaption_mode(ctx, 0); | |
1182 run_test(1, SEC); | |
1183 | |
1184 unmute_Rin(); | |
1185 set_Sgen(NONE, 0.0); | |
1186 run_test(500, MSEC); | |
1187 | |
1188 /* Now measure the echo */ | |
1189 | |
1190 fig11 = (25.0/30.0)*maxLRin - 30.0; /* pass/fail based on clean level @ tx peak */ | |
1191 threshold = fig11 + 3.0; | |
1192 reset_meter_peaks(); | |
1193 maxLSgen = tmp; | |
1194 install_test_callback(test_3b); | |
1195 run_test(5, SEC); | |
1196 | |
1197 print_results(); | |
1198 } | |
1199 | |
1200 if (!strcasecmp(argv[1], "3c")) { | |
1201 print_title("Performing test 3C - Double talk test under simulated conversation\n"); | |
1202 reset_all(); | |
1203 | |
1204 /* t1 (5.6s) - double talk */ | |
1205 | |
1206 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP); | |
1207 set_Sgen(CSS, Sgen_leveldB); | |
1208 run_test(5600, MSEC); | |
1209 | |
1210 /* t2 (1.4s) - to pass Sout <= Sgen */ | |
1211 | |
1212 set_Sgen(NONE, 0.0); | |
1213 install_test_callback(test_3c_t2); | |
1214 run_test(1400, MSEC); | |
1215 | |
1216 /* t3 - (5s) - single talk to converge e/c */ | |
1217 | |
1218 run_test(5000, MSEC); | |
1219 | |
1220 /* t4 - (5.6s) - double talk again */ | |
1221 | |
1222 install_test_callback(test_3c_t4t5); | |
1223 set_Sgen(CSS, Sgen_leveldB); | |
1224 run_test(5600, MSEC); | |
1225 | |
1226 /* t5 - (5.6s) - near end single talk */ | |
1227 | |
1228 mute_Rin(); | |
1229 run_test(5600, MSEC); | |
1230 | |
1231 print_results(); | |
1232 } | |
1233 | |
1234 #ifdef OTHER_TESTS | |
1235 if ((test_list & PERFORM_TEST_4)) | |
1236 { | |
1237 printf("Performing test 4 - Leak rate test\n"); | |
1238 /* Test 4 - Leak rate test */ | |
1239 echo_can_flush(ctx); | |
1240 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1241 /* Converge a canceller */ | |
1242 signal_restart(&local_css); | |
1243 for (i = 0; i < SAMPLE_RATE*5; i++) | |
1244 { | |
1245 tx = signal_amp(&local_css); | |
1246 channel_model(&tx, &rx, tx, 0); | |
1247 clean = echo_can_update(ctx, tx, rx); | |
1248 put_residue(clean); | |
1249 } | |
1250 /* Put 2 minutes of silence through it */ | |
1251 for (i = 0; i < SAMPLE_RATE*120; i++) | |
1252 { | |
1253 clean = echo_can_update(ctx, 0, 0); | |
1254 put_residue(clean); | |
1255 } | |
1256 /* Now freeze it, and check if it is still well adapted. */ | |
1257 echo_can_adaption_mode(ctx, 0); | |
1258 for (i = 0; i < SAMPLE_RATE*5; i++) | |
1259 { | |
1260 tx = signal_amp(&local_css); | |
1261 channel_model(&tx, &rx, tx, 0); | |
1262 clean = echo_can_update(ctx, tx, rx); | |
1263 put_residue(clean); | |
1264 } | |
1265 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1266 #if defined(ENABLE_GUI) | |
1267 if (use_gui) | |
1268 echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS); | |
1269 #endif | |
1270 } | |
1271 | |
1272 if ((test_list & PERFORM_TEST_5)) | |
1273 { | |
1274 printf("Performing test 5 - Infinite return loss convergence test\n"); | |
1275 /* Test 5 - Infinite return loss convergence test */ | |
1276 echo_can_flush(ctx); | |
1277 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1278 /* Converge the canceller */ | |
1279 signal_restart(&local_css); | |
1280 for (i = 0; i < SAMPLE_RATE*5; i++) | |
1281 { | |
1282 tx = signal_amp(&local_css); | |
1283 channel_model(&tx, &rx, tx, 0); | |
1284 clean = echo_can_update(ctx, tx, rx); | |
1285 put_residue(clean); | |
1286 } | |
1287 /* Now stop echoing, and see we don't do anything unpleasant as the | |
1288 echo path is open looped. */ | |
1289 for (i = 0; i < SAMPLE_RATE*5; i++) | |
1290 { | |
1291 tx = signal_amp(&local_css); | |
1292 rx = 0; | |
1293 tx = codec_munge(tx); | |
1294 clean = echo_can_update(ctx, tx, rx); | |
1295 put_residue(clean); | |
1296 } | |
1297 #if defined(ENABLE_GUI) | |
1298 if (use_gui) | |
1299 echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS); | |
1300 #endif | |
1301 } | |
1302 | |
1303 #endif | |
1304 | |
1305 if (!strcasecmp(argv[1], "6")) | |
1306 { | |
1307 int k; | |
1308 float fig11; | |
1309 | |
1310 printf("Performing test 6 - Non-divergence on narrow-band signals\n"); | |
1311 | |
1312 reset_all(); | |
1313 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1314 run_test(5, SEC); | |
1315 | |
1316 /* Now put 5s bursts of a list of tones through the converged canceller, and check | |
1317 that nothing unpleasant happens. */ | |
1318 | |
1319 for (k = 0; tones_6_4_2_7[k][0]; k++) | |
1320 { | |
1321 tone_gen_descriptor_t tone_desc; | |
1322 | |
1323 /* 5 secs of each tone */ | |
1324 | |
1325 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1326 set_Rin(TONE, 20.0*log10(Rin_level)); /* level actually set by next func */ | |
1327 make_tone_gen_descriptor(&tone_desc, | |
1328 tones_6_4_2_7[k][0], | |
1329 -11, | |
1330 tones_6_4_2_7[k][1], | |
1331 -9, | |
1332 1, | |
1333 0, | |
1334 0, | |
1335 0, | |
1336 1); | |
1337 tone_gen_init(&rin_tone_state, &tone_desc); | |
1338 run_test(5, SEC); | |
1339 } | |
1340 | |
1341 /* disable adaption, back to speech */ | |
1342 | |
1343 echo_can_adaption_mode(ctx, 0); | |
1344 set_Rin(CSS, 20.0*log10(Rin_level)); | |
1345 run_test(1, SEC); | |
1346 | |
1347 /* now test convergence as per test 2 fig 11 */ | |
1348 | |
1349 fig11 = (25.0/30.0)*maxLRin - 30.0; /* pass/fail based on clean level @ tx peak */ | |
1350 threshold = fig11 + 10.0; | |
1351 reset_meter_peaks(); | |
1352 install_test_callback(test_3b); | |
1353 run_test(5, SEC); | |
1354 | |
1355 print_results(); | |
1356 } | |
1357 | |
1358 #ifdef OTHER_TESTS | |
1359 | |
1360 if ((test_list & PERFORM_TEST_7)) | |
1361 { | |
1362 printf("Performing test 7 - Stability\n"); | |
1363 /* Test 7 - Stability */ | |
1364 /* Put tones through an unconverged canceller, and check nothing unpleasant | |
1365 happens. */ | |
1366 echo_can_flush(ctx); | |
1367 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION); | |
1368 make_tone_gen_descriptor(&tone_desc, | |
1369 tones_6_4_2_7[0][0], | |
1370 -11, | |
1371 tones_6_4_2_7[0][1], | |
1372 -9, | |
1373 1, | |
1374 0, | |
1375 0, | |
1376 0, | |
1377 1); | |
1378 tone_gen_init(&tone_state, &tone_desc); | |
1379 j = 0; | |
1380 for (i = 0; i < 120; i++) | |
1381 { | |
1382 local_max = tone_gen(&tone_state, local_sound, SAMPLE_RATE); | |
1383 for (j = 0; j < SAMPLE_RATE; j++) | |
1384 { | |
1385 tx = local_sound[j]; | |
1386 channel_model(&tx, &rx, tx, 0); | |
1387 clean = echo_can_update(ctx, tx, rx); | |
1388 put_residue(clean); | |
1389 } | |
1390 #if defined(ENABLE_GUI) | |
1391 if (use_gui) | |
1392 { | |
1393 echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS); | |
1394 echo_can_monitor_update_display(); | |
1395 usleep(100000); | |
1396 } | |
1397 #endif | |
1398 } | |
1399 #if defined(ENABLE_GUI) | |
1400 if (use_gui) | |
1401 echo_can_monitor_can_update(ctx->fir_taps16[ctx->tap_set], TEST_EC_TAPS); | |
1402 #endif | |
1403 } | |
1404 | |
1405 if ((test_list & PERFORM_TEST_8)) | |
1406 { | |
1407 printf("Performing test 8 - Non-convergence on No 5, 6, and 7 in-band signalling\n"); | |
1408 /* Test 8 - Non-convergence on No 5, 6, and 7 in-band signalling */ | |
1409 fprintf(stderr, "Test 8 not yet implemented\n"); | |
1410 } | |
1411 #endif | |
1412 | |
1413 if (!strcasecmp(argv[1], "9")) | |
1414 { | |
1415 printf("Performing test 9 - Comfort noise test\n"); | |
1416 | |
1417 echo_can_flush(ctx); | |
1418 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | |
1419 | ECHO_CAN_USE_NLP | |
1420 | ECHO_CAN_USE_CNG); | |
1421 | |
1422 /* Test 9 Part 1 - matching */ | |
1423 | |
1424 set_Sgen(HOTH, -45.0); | |
1425 mute_Rin(); | |
1426 run_test(5, SEC); /* should be 30s but I wanted to speed up sim */ | |
1427 set_Rin(HOTH, -10.0); | |
1428 run_test(2, SEC); | |
1429 | |
1430 reset_meter_peaks(); | |
1431 install_test_callback(test_9); | |
1432 run_test(700, MSEC); | |
1433 | |
1434 /* Test 9 Part 2 - adjustment down */ | |
1435 | |
1436 install_test_callback(NULL); | |
1437 set_Sgen(HOTH, -55.0); | |
1438 mute_Rin(); | |
1439 run_test(5, SEC); /* should be 10s but I wanted to speed up sim */ | |
1440 set_Rin(HOTH, -10.0); | |
1441 run_test(2, SEC); | |
1442 | |
1443 reset_meter_peaks(); | |
1444 install_test_callback(test_9); | |
1445 run_test(700, MSEC); | |
1446 | |
1447 /* Test 9 Part 3 - adjustment up */ | |
1448 | |
1449 install_test_callback(NULL); | |
1450 set_Sgen(HOTH, -45.0); | |
1451 mute_Rin(); | |
1452 run_test(5, SEC); /* should be 10s but I wanted to speed up sim */ | |
1453 set_Rin(HOTH, -10.0); | |
1454 run_test(2, SEC); | |
1455 | |
1456 reset_meter_peaks(); | |
1457 install_test_callback(test_9); | |
1458 run_test(700, MSEC); | |
1459 | |
1460 print_results(); | |
1461 } | |
1462 | |
1463 #ifdef OTHER_TESTS | |
1464 /* Test 10 - FAX test during call establishment phase */ | |
1465 if ((test_list & PERFORM_TEST_10A)) | |
1466 { | |
1467 printf("Performing test 10A - Canceller operation on the calling station side\n"); | |
1468 /* Test 10A - Canceller operation on the calling station side */ | |
1469 fprintf(stderr, "Test 10A not yet implemented\n"); | |
1470 } | |
1471 | |
1472 if ((test_list & PERFORM_TEST_10B)) | |
1473 { | |
1474 printf("Performing test 10B - Canceller operation on the called station side\n"); | |
1475 /* Test 10B - Canceller operation on the called station side */ | |
1476 fprintf(stderr, "Test 10B not yet implemented\n"); | |
1477 } | |
1478 | |
1479 if ((test_list & PERFORM_TEST_10C)) | |
1480 { | |
1481 printf("Performing test 10C - Canceller operation on the calling station side during page\n" | |
1482 "transmission and page breaks (for further study)\n"); | |
1483 /* Test 10C - Canceller operation on the calling station side during page | |
1484 transmission and page breaks (for further study) */ | |
1485 fprintf(stderr, "Test 10C not yet implemented\n"); | |
1486 } | |
1487 | |
1488 if ((test_list & PERFORM_TEST_11)) | |
1489 { | |
1490 printf("Performing test 11 - Tandem echo canceller test (for further study)\n"); | |
1491 /* Test 11 - Tandem echo canceller test (for further study) */ | |
1492 fprintf(stderr, "Test 11 not yet implemented\n"); | |
1493 } | |
1494 | |
1495 if ((test_list & PERFORM_TEST_12)) | |
1496 { | |
1497 printf("Performing test 12 - Residual acoustic echo test (for further study)\n"); | |
1498 /* Test 12 - Residual acoustic echo test (for further study) */ | |
1499 fprintf(stderr, "Test 12 not yet implemented\n"); | |
1500 } | |
1501 | |
1502 if ((test_list & PERFORM_TEST_13)) | |
1503 { | |
1504 printf("Performing test 13 - Performance with ITU-T low-bit rate coders in echo path (Optional, under study)\n"); | |
1505 /* Test 13 - Performance with ITU-T low-bit rate coders in echo path | |
1506 (Optional, under study) */ | |
1507 fprintf(stderr, "Test 13 not yet implemented\n"); | |
1508 } | |
1509 | |
1510 if ((test_list & PERFORM_TEST_14)) | |
1511 { | |
1512 printf("Performing test 14 - Performance with V-series low-speed data modems\n"); | |
1513 /* Test 14 - Performance with V-series low-speed data modems */ | |
1514 fprintf(stderr, "Test 14 not yet implemented\n"); | |
1515 } | |
1516 | |
1517 if ((test_list & PERFORM_TEST_15)) | |
1518 { | |
1519 printf("Performing test 15 - PCM offset test (Optional)\n"); | |
1520 /* Test 15 - PCM offset test (Optional) */ | |
1521 fprintf(stderr, "Test 15 not yet implemented\n"); | |
1522 } | |
1523 | |
1524 echo_can_free(ctx); | |
1525 | |
1526 signal_free(&local_css); | |
1527 signal_free(&far_css); | |
1528 | |
1529 if (afCloseFile(resulthandle) != 0) | |
1530 { | |
1531 fprintf(stderr, " Cannot close speech file '%s'\n", "result_sound.wav"); | |
1532 exit(2); | |
1533 } | |
1534 if (afCloseFile(residuehandle) != 0) | |
1535 { | |
1536 fprintf(stderr, " Cannot close speech file '%s'\n", "residue_sound.wav"); | |
1537 exit(2); | |
1538 } | |
1539 afFreeFileSetup(filesetup); | |
1540 afFreeFileSetup(filesetup2); | |
1541 | |
1542 #if defined(XYZZY) | |
1543 for (j = 0; j < ctx->taps; j++) | |
1544 { | |
1545 for (i = 0; i < coeff_index; i++) | |
1546 fprintf(stderr, "%d ", coeffs[i][j]); | |
1547 fprintf(stderr, "\n"); | |
1548 } | |
1549 #endif | |
1550 #endif | |
1551 if (verbose == TRUE) | |
1552 printf("Run time %lds\n", time(NULL) - now); | |
1553 | |
1554 #if defined(ENABLE_GUI) | |
1555 if (use_gui) | |
1556 echo_can_monitor_wait_to_end(); | |
1557 #endif | |
1558 | |
1559 | |
1560 fclose(fdump); | |
1561 fclose(flevel); | |
1562 | |
1563 return 0; | |
1564 } | |
1565 /*- End of function --------------------------------------------------------*/ | |
1566 /*- End of file ------------------------------------------------------------*/ |