comparison spandsp-0.0.3/spandsp-0.0.3/tests/dtmf_rx_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 * dtmf_rx_tests.c - Test the DTMF detector against the spec., whatever the spec.
5 * may be :)
6 *
7 * Written by Steve Underwood <steveu@coppice.org>
8 *
9 * Copyright (C) 2001, 2006 Steve Underwood
10 *
11 * All rights reserved.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2, as
15 * published by the Free Software Foundation.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 * $Id: dtmf_rx_tests.c,v 1.23 2006/11/19 14:07:26 steveu Exp $
27 */
28
29 /*
30 * These tests include conversion to and from A-law. I assume the
31 * distortion this produces is comparable to u-law, so it should be
32 * a fair test.
33 *
34 * These tests mirror those on the CM7291 test tape from Mitel.
35 * Many of these tests are highly questionable, but they are a
36 * well accepted industry standard.
37 *
38 * However standard these tests might be, Mitel appears to have stopped
39 * selling copies of their tape.
40 *
41 * For the talk-off test the Bellcore tapes may be used. However, they are
42 * copyright material, so the test data files produced from the Bellcore
43 * tapes cannot be distributed as a part of this package.
44 *
45 */
46
47 /*! \page dtmf_rx_tests_page DTMF receiver tests
48 \section dtmf_rx_tests_page_sec_1 What does it do?
49
50 The DTMF detection test suite performs similar tests to the Mitel test tape,
51 traditionally used for testing DTMF receivers. Mitel seem to have discontinued
52 this product, but all it not lost.
53
54 The first side of the Mitel tape consists of a number of tone and tone+noise
55 based tests. The test suite synthesizes equivalent test data. Being digitally
56 generated, this data is rather more predictable than the test data on the nasty
57 old stretchy cassette tapes which Mitel sold.
58
59 The second side of the Mitel tape contains fragments of real speech from real
60 phone calls captured from the North American telephone network. These are
61 considered troublesome for DTMF detectors. A good detector is expected to
62 achieve a reasonably low number of false detections on this data. Fresh clean
63 copies of this seem to be unobtainable. However, Bellcore produce a much more
64 aggressive set of three cassette tapes. All six side (about 30 minutes each) are
65 filled with much tougher fragments of real speech from the North American
66 telephone network. If you can do well in this test, nobody cares about your
67 results against the Mitel test tape.
68
69 A fresh set of tapes was purchased for these tests, and digitised, producing 6
70 wave files of 16 bit signed PCM data, sampled at 8kHz. They were transcribed
71 using a speed adjustable cassette player. The test tone at the start of the
72 tapes is pretty accurate, and the new tapes should not have had much opportunity
73 to stretch. It is believed these transcriptions are about as good as the source
74 material permits.
75
76 PLEASE NOTE
77
78 These transcriptions may be freely used by anyone who has a legitimate copy of
79 the original tapes. However, if you don't have a legitimate copy of those tapes,
80 you also have no right to use this data. The original tapes are the copyright
81 material of BellCore, and they charge over US$200 for a set. I doubt they sell
82 enough copies to consider this much of a business. However, it is their data,
83 and it is their right to do as they wish with it. Currently I see no indication
84 they wish to give it away for free.
85 */
86
87 #ifdef HAVE_CONFIG_H
88 #include "config.h"
89 #endif
90
91 #include <stdlib.h>
92 #include <inttypes.h>
93 #include <string.h>
94 #if defined(HAVE_TGMATH_H)
95 #include <tgmath.h>
96 #endif
97 #if defined(HAVE_MATH_H)
98 #include <math.h>
99 #endif
100 #include <stdio.h>
101 #include <time.h>
102 #include <fcntl.h>
103 #include <audiofile.h>
104 #include <tiffio.h>
105
106 #include "spandsp.h"
107
108 #include "test_utils.h"
109
110 /* Basic DTMF specs:
111 *
112 * Minimum tone on = 40ms
113 * Minimum tone off = 50ms
114 * Maximum digit rate = 10 per second
115 * Normal twist <= 8dB accepted
116 * Reverse twist <= 4dB accepted
117 * S/N >= 15dB will detect OK
118 * Attenuation <= 26dB will detect OK
119 * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
120 */
121
122 #define DTMF_DURATION 380
123 #define DTMF_PAUSE 400
124 #define DTMF_CYCLE (DTMF_DURATION + DTMF_PAUSE)
125
126 #define ALL_POSSIBLE_DIGITS "123A456B789C*0#D"
127
128 #define MITEL_DIR "../itutests/mitel/"
129 #define BELLCORE_DIR "../itutests/bellcore/"
130
131 const char *bellcore_files[] =
132 {
133 MITEL_DIR "mitel-cm7291-talkoff.wav",
134 BELLCORE_DIR "tr-tsy-00763-1.wav",
135 BELLCORE_DIR "tr-tsy-00763-2.wav",
136 BELLCORE_DIR "tr-tsy-00763-3.wav",
137 BELLCORE_DIR "tr-tsy-00763-4.wav",
138 BELLCORE_DIR "tr-tsy-00763-5.wav",
139 BELLCORE_DIR "tr-tsy-00763-6.wav",
140 ""
141 };
142
143 static tone_gen_descriptor_t my_dtmf_digit_tones[16];
144
145 float dtmf_row[] =
146 {
147 697.0f, 770.0f, 852.0f, 941.0f
148 };
149 float dtmf_col[] =
150 {
151 1209.0f, 1336.0f, 1477.0f, 1633.0f
152 };
153
154 char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
155
156 int callback_hit;
157 int callback_ok;
158 int callback_roll;
159 int step;
160
161 int use_dialtone_filter = FALSE;
162
163 char *decode_test_file = NULL;
164
165 static int16_t amp[1000000];
166 static int16_t amp2[1000000];
167
168 codec_munge_state_t *munge = NULL;
169
170 static void my_dtmf_gen_init(float low_fudge,
171 int low_level,
172 float high_fudge,
173 int high_level,
174 int duration,
175 int gap)
176 {
177 int row;
178 int col;
179
180 for (row = 0; row < 4; row++)
181 {
182 for (col = 0; col < 4; col++)
183 {
184 make_tone_gen_descriptor(&my_dtmf_digit_tones[row*4 + col],
185 dtmf_row[row]*(1.0f + low_fudge),
186 low_level,
187 dtmf_col[col]*(1.0f + high_fudge),
188 high_level,
189 duration,
190 gap,
191 0,
192 0,
193 FALSE);
194 }
195 }
196 }
197 /*- End of function --------------------------------------------------------*/
198
199 static int my_dtmf_generate(int16_t amp[], const char *digits)
200 {
201 int len;
202 char *cp;
203 tone_gen_state_t tone;
204
205 len = 0;
206 while (*digits)
207 {
208 cp = strchr(dtmf_positions, *digits);
209 if (cp)
210 {
211 tone_gen_init(&tone, &my_dtmf_digit_tones[cp - dtmf_positions]);
212 len += tone_gen(&tone, amp + len, 1000);
213 }
214 digits++;
215 }
216 return len;
217 }
218 /*- End of function --------------------------------------------------------*/
219
220 static void digit_delivery(void *data, const char *digits, int len)
221 {
222 int i;
223 int seg;
224 const char *s = ALL_POSSIBLE_DIGITS;
225 const char *t;
226
227 callback_hit = TRUE;
228 if (data == (void *) 0x12345678)
229 {
230 t = s + callback_roll;
231 seg = 16 - callback_roll;
232 for (i = 0; i < len; i += seg, seg = 16)
233 {
234 if (i + seg > len)
235 seg = len - i;
236 if (memcmp(digits + i, t, seg))
237 {
238 callback_ok = FALSE;
239 printf("Fail at %d %d\n", i, seg);
240 break;
241 }
242 t = s;
243 callback_roll = (callback_roll + seg)%16;
244 }
245 }
246 else
247 {
248 callback_ok = FALSE;
249 }
250 }
251 /*- End of function --------------------------------------------------------*/
252
253 static void digit_status(void *data, int signal)
254 {
255 const char *s = ALL_POSSIBLE_DIGITS;
256 int len;
257 static int last_step = 0;
258 static int first = TRUE;
259
260 callback_hit = TRUE;
261 len = step - last_step;
262 if (data == (void *) 0x12345678)
263 {
264 if (len < 320 || len > 480)
265 {
266 if (first)
267 {
268 /* At the beginning the apparent duration is expected to be wrong */
269 first = FALSE;
270 }
271 else
272 {
273 printf("Failed for signal %s length %d at %d\n", (callback_roll & 1) ? "on" : "off", len, step);
274 callback_ok = FALSE;
275 }
276 }
277 if (callback_roll & 1)
278 {
279 if (signal != 0)
280 {
281 printf("Failed for signal 0x%X instead of 0\n", signal);
282 callback_ok = FALSE;
283 }
284 }
285 else
286 {
287 if (signal != s[callback_roll >> 1])
288 {
289 printf("Failed for signal 0x%X instead of 0x%X\n", signal, s[callback_roll >> 1]);
290 callback_ok = FALSE;
291 }
292 }
293 if (++callback_roll >= 32)
294 callback_roll = 0;
295 }
296 else
297 {
298 callback_ok = FALSE;
299 }
300 last_step = step;
301 }
302 /*- End of function --------------------------------------------------------*/
303
304 static void mitel_cm7291_side_1_tests(void)
305 {
306 int i;
307 int j;
308 int len;
309 int sample;
310 const char *s;
311 char digit[2];
312 char buf[128 + 1];
313 int actual;
314 int nplus;
315 int nminus;
316 float rrb;
317 float rcfo;
318 dtmf_rx_state_t dtmf_state;
319 awgn_state_t noise_source;
320
321 dtmf_rx_init(&dtmf_state, NULL, NULL);
322 if (use_dialtone_filter)
323 dtmf_rx_parms(&dtmf_state, TRUE, -1, -1);
324
325 /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step,
326 which has no meaning here. */
327 printf("Test 1: Calibration\n");
328 printf(" Passed\n");
329
330 /* Test 2: Decode check
331 This is a sanity check, that all digits are reliably detected
332 under ideal conditions. Each possible digit repeated 10 times,
333 with 50ms bursts. The level of each tone is about 6dB down from clip.
334 6dB down actually causes trouble with G.726, so we use 7dB down. */
335 printf("Test 2: Decode check\n");
336 my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50);
337 s = ALL_POSSIBLE_DIGITS;
338 digit[1] = '\0';
339 while (*s)
340 {
341 digit[0] = *s++;
342 for (i = 0; i < 10; i++)
343 {
344 len = my_dtmf_generate(amp, digit);
345 codec_munge(munge, amp, len);
346 dtmf_rx(&dtmf_state, amp, len);
347
348 actual = dtmf_rx_get(&dtmf_state, buf, 128);
349
350 if (actual != 1 || buf[0] != digit[0])
351 {
352 printf(" Sent '%s'\n", digit);
353 printf(" Received '%s'\n", buf);
354 printf(" Failed\n");
355 exit(2);
356 }
357 }
358 }
359 printf(" Passed\n");
360
361 /* Test 3: Recognition bandwidth and channel centre frequency check.
362 Use only the diagonal pairs of tones (digits 1, 5, 9 and D). Each
363 tone pair requires four test to complete the check, making 16
364 sections overall. Each section contains 40 pulses of
365 50ms duration, with an amplitude of -20dB from clip per
366 frequency.
367
368 Four sections covering the tests for one tone (1 digit) are:
369 a. H frequency at 0% deviation from center, L frequency at +0.1%.
370 L frequency is then increments in +01.% steps up to +4%. The
371 number of tone bursts is noted and designated N+.
372 b. H frequency at 0% deviation, L frequency at -0.1%. L frequency
373 is then incremental in -0.1% steps, up to -4%. The number of
374 tone bursts is noted and designated N-.
375 c. The test in (a) is repeated with the L frequency at 0% and the
376 H frequency varied up to +4%.
377 d. The test in (b) is repeated with the L frequency and 0% and the
378 H frequency varied to -4%.
379
380 Receiver Recognition Bandwidth (RRB) is calculated as follows:
381 RRB% = (N+ + N-)/10
382 Receiver Center Frequency Offset (RCFO) is calculated as follows:
383 RCFO% = X + (N+ - N-)/20
384
385 Note that this test doesn't test what it says it is testing at all,
386 and the results are quite inaccurate, if not a downright lie! However,
387 it follows the Mitel procedure, so how can it be bad? :)
388 */
389 printf("Test 3: Recognition bandwidth and channel centre frequency check\n");
390 s = "159D";
391 digit[1] = '\0';
392 while (*s)
393 {
394 digit[0] = *s++;
395 for (nplus = 0, i = 1; i <= 60; i++)
396 {
397 my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50);
398 len = my_dtmf_generate(amp, digit);
399 codec_munge(munge, amp, len);
400 dtmf_rx(&dtmf_state, amp, len);
401 nplus += dtmf_rx_get(&dtmf_state, buf, 128);
402 }
403 for (nminus = 0, i = -1; i >= -60; i--)
404 {
405 my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50);
406 len = my_dtmf_generate(amp, digit);
407 codec_munge(munge, amp, len);
408 dtmf_rx(&dtmf_state, amp, len);
409 nminus += dtmf_rx_get(&dtmf_state, buf, 128);
410 }
411 rrb = (float) (nplus + nminus)/10.0f;
412 rcfo = (float) (nplus - nminus)/10.0f;
413 printf(" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
414 digit[0],
415 rrb,
416 rcfo,
417 (float) nminus/10.0f,
418 (float) nplus/10.0f);
419 if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo)
420 {
421 printf(" Failed\n");
422 exit(2);
423 }
424
425 for (nplus = 0, i = 1; i <= 60; i++)
426 {
427 my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50);
428 len = my_dtmf_generate(amp, digit);
429 codec_munge(munge, amp, len);
430 dtmf_rx(&dtmf_state, amp, len);
431 nplus += dtmf_rx_get(&dtmf_state, buf, 128);
432 }
433 for (nminus = 0, i = -1; i >= -60; i--)
434 {
435 my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50);
436 len = my_dtmf_generate(amp, digit);
437 codec_munge(munge, amp, len);
438 dtmf_rx(&dtmf_state, amp, len);
439 nminus += dtmf_rx_get(&dtmf_state, buf, 128);
440 }
441 rrb = (float) (nplus + nminus)/10.0f;
442 rcfo = (float) (nplus - nminus)/10.0f;
443 printf(" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
444 digit[0],
445 rrb,
446 rcfo,
447 (float) nminus/10.0f,
448 (float) nplus/10.0f);
449 if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo)
450 {
451 printf(" Failed\n");
452 exit(2);
453 }
454 }
455 printf(" Passed\n");
456
457 /* Test 4: Acceptable amplitude ratio (twist).
458 Use only the diagonal pairs of tones (digits 1, 5, 9 and D).
459 There are eight sections to the test. Each section contains 200
460 pulses with a 50ms duration for each pulse. Initially the amplitude
461 of both tones is 6dB down from clip. The two sections to test one
462 tone pair are:
463
464 a. Standard Twist: H tone amplitude is maintained at -6dB from clip,
465 L tone amplitude is attenuated gradually until the amplitude ratio
466 L/H is -20dB. Note the number of responses from the receiver.
467 b. Reverse Twist: L tone amplitude is maintained at -6dB from clip,
468 H tone amplitude is attenuated gradually until the amplitude ratio
469 is 20dB. Note the number of responses from the receiver.
470
471 All tone bursts are of 50ms duration.
472
473 The Acceptable Amplitude Ratio in dB is equal to the number of
474 responses registered in (a) or (b), divided by 10.
475
476 TODO: This is supposed to work in 1/10dB steps, but here I used 1dB
477 steps, as the current tone generator has its amplitude set in
478 1dB steps.
479 */
480 printf("Test 4: Acceptable amplitude ratio (twist)\n");
481 s = "159D";
482 digit[1] = '\0';
483 while (*s)
484 {
485 digit[0] = *s++;
486 for (nplus = 0, i = -30; i >= -230; i--)
487 {
488 my_dtmf_gen_init(0.0f, -3, 0.0f, i/10, 50, 50);
489
490 len = my_dtmf_generate(amp, digit);
491 codec_munge(munge, amp, len);
492 dtmf_rx(&dtmf_state, amp, len);
493 nplus += dtmf_rx_get(&dtmf_state, buf, 128);
494 }
495 printf(" %c normal twist = %.2fdB\n", digit[0], (float) nplus/10.0);
496 if (nplus < 80)
497 {
498 printf(" Failed\n");
499 exit(2);
500 }
501 for (nminus = 0, i = -30; i >= -230; i--)
502 {
503 my_dtmf_gen_init(0.0f, i/10, 0.0f, -3, 50, 50);
504
505 len = my_dtmf_generate(amp, digit);
506 codec_munge(munge, amp, len);
507 dtmf_rx(&dtmf_state, amp, len);
508 nminus += dtmf_rx_get(&dtmf_state, buf, 128);
509 }
510 printf(" %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0);
511 if (nminus < 40)
512 {
513 printf(" Failed\n");
514 exit(2);
515 }
516 }
517 printf(" Passed\n");
518
519 /* Test 5: Dynamic range
520 This test utilizes tone pair L1 H1 (digit 1). Thirty-five tone pair
521 pulses are transmitted, with both frequencies stating at -6dB from
522 clip. The amplitude of each is gradually attenuated by -35dB at a
523 rate of 1dB per pulse. The Dynamic Range in dB is equal to the
524 number of responses from the receiver during the test.
525
526 Well not really, but that is the Mitel test. Lets sweep a bit further,
527 and see what the real range is */
528 printf("Test 5: Dynamic range\n");
529 for (nplus = 0, i = +3; i >= -50; i--)
530 {
531 my_dtmf_gen_init(0.0f, i, 0.0f, i, 50, 50);
532
533 len = my_dtmf_generate(amp, "1");
534 codec_munge(munge, amp, len);
535 dtmf_rx(&dtmf_state, amp, len);
536 nplus += dtmf_rx_get(&dtmf_state, buf, 128);
537 }
538 printf(" Dynamic range = %ddB\n", nplus);
539 printf(" Passed\n");
540
541 /* Test 6: Guard time
542 This test utilizes tone pair L1 H1 (digit 1). Four hundred pulses
543 are transmitted at an amplitude of -6dB from clip per frequency.
544 Pulse duration starts at 49ms and is gradually reduced to 10ms.
545 Guard time in ms is equal to (500 - number of responses)/10.
546
547 That is the Mitel test, and we will follow it. Its totally bogus,
548 though. Just what the heck is a pass or fail here? */
549
550 printf("Test 6: Guard time\n");
551 for (nplus = 0, i = 490; i >= 100; i--)
552 {
553 my_dtmf_gen_init(0.0f, -3, 0.0f, -3, i/10, 50);
554
555 len = my_dtmf_generate(amp, "1");
556 codec_munge(munge, amp, len);
557 dtmf_rx(&dtmf_state, amp, len);
558 nplus += dtmf_rx_get(&dtmf_state, buf, 128);
559 }
560 printf(" Guard time = %dms\n", (500 - nplus)/10);
561 printf(" Passed\n");
562
563 /* Test 7: Acceptable signal to noise ratio
564 This test utilizes tone pair L1 H1, transmitted on a noise background.
565 The test consists of three sections in which the tone pair is
566 transmitted 1000 times at an amplitude -6dB from clip per frequency,
567 but with a different white noise level for each section. The first
568 level is -24dBV, the second -18dBV and the third -12dBV.. The
569 acceptable signal to noise ratio is the lowest ratio of signal
570 to noise in the test where the receiver responds to all 1000 pulses.
571
572 Well, that is the Mitel test, but it doesn't tell you what the
573 decoder can really do. Lets do a more comprehensive test */
574
575 printf("Test 7: Acceptable signal to noise ratio\n");
576 my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50);
577
578 for (j = -13; j > -50; j--)
579 {
580 awgn_init_dbm0(&noise_source, 1234567, (float) j);
581 for (i = 0; i < 1000; i++)
582 {
583 len = my_dtmf_generate(amp, "1");
584
585 // TODO: Clip
586 for (sample = 0; sample < len; sample++)
587 amp[sample] = saturate(amp[sample] + awgn(&noise_source));
588
589 codec_munge(munge, amp, len);
590 dtmf_rx(&dtmf_state, amp, len);
591
592 if (dtmf_rx_get(&dtmf_state, buf, 128) != 1)
593 break;
594 }
595 if (i == 1000)
596 break;
597 }
598 printf(" Acceptable S/N ratio is %ddB\n", -4 - j);
599 if (-4 - j > 26)
600 {
601 printf(" Failed\n");
602 exit(2);
603 }
604 printf(" Passed\n");
605 }
606 /*- End of function --------------------------------------------------------*/
607
608 static void mitel_cm7291_side_2_and_bellcore_tests(void)
609 {
610 int i;
611 int j;
612 int len;
613 int hits;
614 int hit_types[256];
615 char buf[128 + 1];
616 AFfilehandle inhandle;
617 int frames;
618 float x;
619 dtmf_rx_state_t dtmf_state;
620
621 dtmf_rx_init(&dtmf_state, NULL, NULL);
622 if (use_dialtone_filter)
623 dtmf_rx_parms(&dtmf_state, TRUE, -1, -1);
624
625 /* The remainder of the Mitel tape is the talk-off test */
626 /* Here we use the Bellcore test tapes (much tougher), in six
627 wave files - 1 from each side of the original 3 cassette tapes */
628 /* Bellcore say you should get no more than 470 false detections with
629 a good receiver. Dialogic claim 20. Of course, we can do better than
630 that, eh? */
631 printf("Test 8: Talk-off test\n");
632 memset(hit_types, '\0', sizeof(hit_types));
633 for (j = 0; bellcore_files[j][0]; j++)
634 {
635 if ((inhandle = afOpenFile(bellcore_files[j], "r", 0)) == AF_NULL_FILEHANDLE)
636 {
637 printf(" Cannot open speech file '%s'\n", bellcore_files[j]);
638 exit(2);
639 }
640 if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0)
641 {
642 printf(" Unexpected frame size in speech file '%s'\n", bellcore_files[j]);
643 exit(2);
644 }
645 if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE)
646 {
647 printf(" Unexpected sample rate in speech file '%s'\n", bellcore_files[j]);
648 exit(2);
649 }
650 if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0)
651 {
652 printf(" Unexpected number of channels in speech file '%s'\n", bellcore_files[j]);
653 exit(2);
654 }
655 hits = 0;
656 while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, SAMPLE_RATE)))
657 {
658 dtmf_rx(&dtmf_state, amp, frames);
659 len = dtmf_rx_get(&dtmf_state, buf, 128);
660 if (len > 0)
661 {
662 for (i = 0; i < len; i++)
663 hit_types[(int) buf[i]]++;
664 hits += len;
665 }
666 }
667 if (afCloseFile(inhandle) != 0)
668 {
669 printf(" Cannot close speech file '%s'\n", bellcore_files[j]);
670 exit(2);
671 }
672 printf(" File %d gave %d false hits.\n", j + 1, hits);
673 }
674 for (i = 0, j = 0; i < 256; i++)
675 {
676 if (hit_types[i])
677 {
678 printf(" Digit %c had %d false hits\n", i, hit_types[i]);
679 j += hit_types[i];
680 }
681 }
682 printf(" %d hits in total\n", j);
683 if (j > 470)
684 {
685 printf(" Failed\n");
686 exit(2);
687 }
688 printf(" Passed\n");
689 }
690 /*- End of function --------------------------------------------------------*/
691
692 static void dial_tone_tolerance_tests(void)
693 {
694 int i;
695 int j;
696 int len;
697 int sample;
698 char buf[128 + 1];
699 dtmf_rx_state_t dtmf_state;
700 tone_gen_descriptor_t dial_tone_desc;
701 tone_gen_state_t dial_tone;
702
703 dtmf_rx_init(&dtmf_state, NULL, NULL);
704 if (use_dialtone_filter)
705 dtmf_rx_parms(&dtmf_state, TRUE, -1, -1);
706
707 /* Test dial tone tolerance */
708 printf("Test: Dial tone tolerance.\n");
709 my_dtmf_gen_init(0.0f, -15, 0.0f, -15, 50, 50);
710
711 for (j = -30; j < -3; j++)
712 {
713 make_tone_gen_descriptor(&dial_tone_desc, 350, j, 440, j, 1, 0, 0, 0, TRUE);
714 tone_gen_init(&dial_tone, &dial_tone_desc);
715 for (i = 0; i < 10; i++)
716 {
717 len = my_dtmf_generate(amp, ALL_POSSIBLE_DIGITS);
718 tone_gen(&dial_tone, amp2, len);
719
720 for (sample = 0; sample < len; sample++)
721 amp[sample] = saturate(amp[sample] + amp2[sample]);
722 codec_munge(munge, amp, len);
723 dtmf_rx(&dtmf_state, amp, len);
724
725 if (dtmf_rx_get(&dtmf_state, buf, 128) != strlen(ALL_POSSIBLE_DIGITS))
726 break;
727 }
728 if (i != 10)
729 break;
730 }
731 printf(" Acceptable signal to dial tone ratio is %ddB\n", -15 - j);
732 if ((use_dialtone_filter && (-15 - j) > -12)
733 ||
734 (!use_dialtone_filter && (-15 - j) > 10))
735 {
736 printf(" Failed\n");
737 exit(2);
738 }
739 printf(" Passed\n");
740 }
741 /*- End of function --------------------------------------------------------*/
742
743 static void callback_function_tests(void)
744 {
745 int i;
746 int j;
747 int len;
748 int sample;
749 dtmf_rx_state_t dtmf_state;
750
751 /* Test the callback mode for delivering detected digits */
752 printf("Test: Callback digit delivery mode.\n");
753 callback_hit = FALSE;
754 callback_ok = TRUE;
755 callback_roll = 0;
756 dtmf_rx_init(&dtmf_state, digit_delivery, (void *) 0x12345678);
757 if (use_dialtone_filter)
758 dtmf_rx_parms(&dtmf_state, TRUE, -1, -1);
759 my_dtmf_gen_init(0.0f, -10, 0.0f, -10, 50, 50);
760 for (i = 1; i < 10; i++)
761 {
762 len = 0;
763 for (j = 0; j < i; j++)
764 len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS);
765 dtmf_rx(&dtmf_state, amp, len);
766 if (!callback_hit || !callback_ok)
767 break;
768 }
769 if (!callback_hit || !callback_ok)
770 {
771 printf(" Failed\n");
772 exit(2);
773 }
774 printf(" Passed\n");
775
776 /* Test the realtime callback mode for reporting detected digits */
777 printf("Test: Realtime callback digit delivery mode.\n");
778 callback_hit = FALSE;
779 callback_ok = TRUE;
780 callback_roll = 0;
781 dtmf_rx_init(&dtmf_state, NULL, NULL);
782 dtmf_rx_set_realtime_callback(&dtmf_state, digit_status, (void *) 0x12345678);
783 if (use_dialtone_filter)
784 dtmf_rx_parms(&dtmf_state, TRUE, -1, -1);
785 my_dtmf_gen_init(0.0f, -10, 0.0f, -10, 50, 50);
786 step = 0;
787 for (i = 1; i < 10; i++)
788 {
789 len = 0;
790 for (j = 0; j < i; j++)
791 len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS);
792 for (sample = 0, j = 160; sample < len; sample += 160, j = ((len - sample) >= 160) ? 160 : (len - sample))
793 {
794 dtmf_rx(&dtmf_state, &amp[sample], j);
795 if (!callback_ok)
796 break;
797 step += j;
798 }
799 if (!callback_hit || !callback_ok)
800 break;
801 }
802 if (!callback_hit || !callback_ok)
803 {
804 printf(" Failed\n");
805 exit(2);
806 }
807 }
808 /*- End of function --------------------------------------------------------*/
809
810 static void decode_test(const char *test_file)
811 {
812 int16_t amp[160];
813 AFfilehandle inhandle;
814 dtmf_rx_state_t dtmf_state;
815 char buf[128 + 1];
816 int actual;
817 int samples;
818 int total;
819
820 dtmf_rx_init(&dtmf_state, NULL, NULL);
821 if (use_dialtone_filter)
822 dtmf_rx_parms(&dtmf_state, TRUE, -1, -1);
823
824 /* We will decode the audio from a wave file. */
825
826 if ((inhandle = afOpenFile(decode_test_file, "r", NULL)) == AF_NULL_FILEHANDLE)
827 {
828 fprintf(stderr, " Cannot open wave file '%s'\n", decode_test_file);
829 exit(2);
830 }
831
832 total = 0;
833 while ((samples = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, 160)) > 0)
834 {
835 codec_munge(munge, amp, samples);
836 dtmf_rx(&dtmf_state, amp, samples);
837 if ((actual = dtmf_rx_get(&dtmf_state, buf, 128)) > 0)
838 printf("Received '%s'\n", buf);
839 total += actual;
840 }
841 printf("%d digits received\n", total);
842 }
843 /*- End of function --------------------------------------------------------*/
844
845 int main(int argc, char *argv[])
846 {
847 int duration;
848 int i;
849 time_t now;
850 int channel_codec;
851
852 use_dialtone_filter = FALSE;
853 channel_codec = MUNGE_CODEC_NONE;
854 decode_test_file = NULL;
855 for (i = 1; i < argc; i++)
856 {
857 if (strcmp(argv[i], "-c") == 0)
858 {
859 channel_codec = atoi(argv[++i]);
860 continue;
861 }
862 if (strcmp(argv[i], "-d") == 0)
863 {
864 decode_test_file = argv[++i];
865 continue;
866 }
867 if (strcmp(argv[i], "-f") == 0)
868 {
869 use_dialtone_filter = TRUE;
870 continue;
871 }
872 }
873 munge = codec_munge_init(channel_codec);
874
875 if (decode_test_file)
876 {
877 decode_test(decode_test_file);
878 }
879 else
880 {
881 time(&now);
882 mitel_cm7291_side_1_tests();
883 mitel_cm7291_side_2_and_bellcore_tests();
884 dial_tone_tolerance_tests();
885 callback_function_tests();
886 printf(" Passed\n");
887 duration = time(NULL) - now;
888 printf("Tests passed in %ds\n", duration);
889 }
890
891 return 0;
892 }
893 /*- End of function --------------------------------------------------------*/
894 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.