comparison spandsp-0.0.6pre17/tests/dtmf_rx_tests.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
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.45 2009/05/30 15:23:13 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 #if defined(HAVE_CONFIG_H)
88 #include "config.h"
89 #endif
90
91 #include <stdlib.h>
92 #include <string.h>
93 #include <stdio.h>
94 #include <fcntl.h>
95 #include <unistd.h>
96 #include <time.h>
97 #include <sndfile.h>
98
99 //#if defined(WITH_SPANDSP_INTERNALS)
100 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
101 //#endif
102
103 #include "spandsp.h"
104 #include "spandsp-sim.h"
105
106 /* Basic DTMF specs:
107 *
108 * Minimum tone on = 40ms
109 * Minimum tone off = 50ms
110 * Maximum digit rate = 10 per second
111 * Normal twist <= 8dB accepted
112 * Reverse twist <= 4dB accepted
113 * S/N >= 15dB will detect OK
114 * Attenuation <= 26dB will detect OK
115 * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
116 */
117
118 #define DEFAULT_DTMF_TX_LEVEL -10
119 #define DEFAULT_DTMF_TX_ON_TIME 50
120 #define DEFAULT_DTMF_TX_OFF_TIME 50
121
122 #define SAMPLES_PER_CHUNK 160
123
124 #define ALL_POSSIBLE_DIGITS "123A456B789C*0#D"
125
126 #define MITEL_DIR "../test-data/mitel/"
127 #define BELLCORE_DIR "../test-data/bellcore/"
128
129 const char *bellcore_files[] =
130 {
131 MITEL_DIR "mitel-cm7291-talkoff.wav",
132 BELLCORE_DIR "tr-tsy-00763-1.wav",
133 BELLCORE_DIR "tr-tsy-00763-2.wav",
134 BELLCORE_DIR "tr-tsy-00763-3.wav",
135 BELLCORE_DIR "tr-tsy-00763-4.wav",
136 BELLCORE_DIR "tr-tsy-00763-5.wav",
137 BELLCORE_DIR "tr-tsy-00763-6.wav",
138 ""
139 };
140
141 static tone_gen_descriptor_t my_dtmf_digit_tones[16];
142
143 float dtmf_row[] =
144 {
145 697.0f, 770.0f, 852.0f, 941.0f
146 };
147 float dtmf_col[] =
148 {
149 1209.0f, 1336.0f, 1477.0f, 1633.0f
150 };
151
152 char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
153
154 int callback_hit;
155 int callback_ok;
156 int callback_roll;
157 int step;
158
159 int use_dialtone_filter = FALSE;
160
161 char *decode_test_file = NULL;
162
163 static int16_t amp[1000000];
164 static int16_t amp2[1000000];
165
166 codec_munge_state_t *munge = NULL;
167
168 static void my_dtmf_gen_init(float low_fudge,
169 int low_level,
170 float high_fudge,
171 int high_level,
172 int duration,
173 int gap)
174 {
175 int row;
176 int col;
177
178 for (row = 0; row < 4; row++)
179 {
180 for (col = 0; col < 4; col++)
181 {
182 make_tone_gen_descriptor(&my_dtmf_digit_tones[row*4 + col],
183 dtmf_row[row]*(1.0f + low_fudge),
184 low_level,
185 dtmf_col[col]*(1.0f + high_fudge),
186 high_level,
187 duration,
188 gap,
189 0,
190 0,
191 FALSE);
192 }
193 }
194 }
195 /*- End of function --------------------------------------------------------*/
196
197 static int my_dtmf_generate(int16_t amp[], const char *digits)
198 {
199 int len;
200 char *cp;
201 tone_gen_state_t tone;
202
203 len = 0;
204 while (*digits)
205 {
206 cp = strchr(dtmf_positions, *digits);
207 if (cp)
208 {
209 tone_gen_init(&tone, &my_dtmf_digit_tones[cp - dtmf_positions]);
210 len += tone_gen(&tone, amp + len, 1000);
211 }
212 digits++;
213 }
214 return len;
215 }
216 /*- End of function --------------------------------------------------------*/
217
218 static void digit_delivery(void *data, const char *digits, int len)
219 {
220 int i;
221 int seg;
222 const char *s = ALL_POSSIBLE_DIGITS;
223 const char *t;
224
225 callback_hit = TRUE;
226 if (data == (void *) 0x12345678)
227 {
228 t = s + callback_roll;
229 seg = 16 - callback_roll;
230 for (i = 0; i < len; i += seg, seg = 16)
231 {
232 if (i + seg > len)
233 seg = len - i;
234 if (memcmp(digits + i, t, seg))
235 {
236 callback_ok = FALSE;
237 printf("Fail at %d %d\n", i, seg);
238 break;
239 }
240 t = s;
241 callback_roll = (callback_roll + seg)%16;
242 }
243 }
244 else
245 {
246 callback_ok = FALSE;
247 }
248 }
249 /*- End of function --------------------------------------------------------*/
250
251 static void digit_status(void *data, int signal, int level, int delay)
252 {
253 const char *s = ALL_POSSIBLE_DIGITS;
254 int len;
255 static int last_step = 0;
256 static int first = TRUE;
257
258 callback_hit = TRUE;
259 len = step - last_step;
260 if (data == (void *) 0x12345678)
261 {
262 if (len < 320 || len > 480)
263 {
264 if (first)
265 {
266 /* At the beginning the apparent duration is expected to be wrong */
267 first = FALSE;
268 }
269 else
270 {
271 printf("Failed for signal %s length %d at %d\n", (callback_roll & 1) ? "on" : "off", len, step);
272 callback_ok = FALSE;
273 }
274 }
275 if (callback_roll & 1)
276 {
277 if (signal != 0)
278 {
279 printf("Failed for signal 0x%X instead of 0\n", signal);
280 callback_ok = FALSE;
281 }
282 }
283 else
284 {
285 if (signal != s[callback_roll >> 1])
286 {
287 printf("Failed for signal 0x%X instead of 0x%X\n", signal, s[callback_roll >> 1]);
288 callback_ok = FALSE;
289 }
290 if (level < DEFAULT_DTMF_TX_LEVEL + 3 - 1 || level > DEFAULT_DTMF_TX_LEVEL + 3 + 1)
291 {
292 printf("Failed for level %d instead of %d\n", level, DEFAULT_DTMF_TX_LEVEL + 3);
293 callback_ok = FALSE;
294 }
295 }
296 if (++callback_roll >= 32)
297 callback_roll = 0;
298 }
299 else
300 {
301 callback_ok = FALSE;
302 }
303 last_step = step;
304 }
305 /*- End of function --------------------------------------------------------*/
306
307 static void mitel_cm7291_side_1_tests(void)
308 {
309 int i;
310 int j;
311 int len;
312 int sample;
313 const char *s;
314 char digit[2];
315 char buf[128 + 1];
316 int actual;
317 int nplus;
318 int nminus;
319 float rrb;
320 float rcfo;
321 dtmf_rx_state_t *dtmf_state;
322 awgn_state_t noise_source;
323
324 dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
325 if (use_dialtone_filter)
326 dtmf_rx_parms(dtmf_state, TRUE, -1, -1, -99);
327
328 /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step,
329 which has no meaning here. */
330 printf("Test 1: Calibration\n");
331 printf(" Passed\n");
332
333 /* Test 2: Decode check
334 This is a sanity check, that all digits are reliably detected
335 under ideal conditions. Each possible digit repeated 10 times,
336 with 50ms bursts. The level of each tone is about 6dB down from clip.
337 6dB down actually causes trouble with G.726, so we use 7dB down. */
338 printf("Test 2: Decode check\n");
339 my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50);
340 s = ALL_POSSIBLE_DIGITS;
341 digit[1] = '\0';
342 while (*s)
343 {
344 digit[0] = *s++;
345 for (i = 0; i < 10; i++)
346 {
347 len = my_dtmf_generate(amp, digit);
348 codec_munge(munge, amp, len);
349 dtmf_rx(dtmf_state, amp, len);
350
351 actual = dtmf_rx_get(dtmf_state, buf, 128);
352
353 if (actual != 1 || buf[0] != digit[0])
354 {
355 printf(" Sent '%s'\n", digit);
356 printf(" Received '%s'\n", buf);
357 printf(" Failed\n");
358 exit(2);
359 }
360 }
361 }
362 printf(" Passed\n");
363
364 /* Test 3: Recognition bandwidth and channel centre frequency check.
365 Use only the diagonal pairs of tones (digits 1, 5, 9 and D). Each
366 tone pair requires four test to complete the check, making 16
367 sections overall. Each section contains 40 pulses of
368 50ms duration, with an amplitude of -20dB from clip per
369 frequency.
370
371 Four sections covering the tests for one tone (1 digit) are:
372 a. H frequency at 0% deviation from center, L frequency at +0.1%.
373 L frequency is then increments in +01.% steps up to +4%. The
374 number of tone bursts is noted and designated N+.
375 b. H frequency at 0% deviation, L frequency at -0.1%. L frequency
376 is then incremental in -0.1% steps, up to -4%. The number of
377 tone bursts is noted and designated N-.
378 c. The test in (a) is repeated with the L frequency at 0% and the
379 H frequency varied up to +4%.
380 d. The test in (b) is repeated with the L frequency and 0% and the
381 H frequency varied to -4%.
382
383 Receiver Recognition Bandwidth (RRB) is calculated as follows:
384 RRB% = (N+ + N-)/10
385 Receiver Center Frequency Offset (RCFO) is calculated as follows:
386 RCFO% = X + (N+ - N-)/20
387
388 Note that this test doesn't test what it says it is testing at all,
389 and the results are quite inaccurate, if not a downright lie! However,
390 it follows the Mitel procedure, so how can it be bad? :)
391 */
392 printf("Test 3: Recognition bandwidth and channel centre frequency check\n");
393 s = "159D";
394 digit[1] = '\0';
395 while (*s)
396 {
397 digit[0] = *s++;
398 for (nplus = 0, i = 1; i <= 60; i++)
399 {
400 my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50);
401 len = my_dtmf_generate(amp, digit);
402 codec_munge(munge, amp, len);
403 dtmf_rx(dtmf_state, amp, len);
404 nplus += dtmf_rx_get(dtmf_state, buf, 128);
405 }
406 for (nminus = 0, i = -1; i >= -60; i--)
407 {
408 my_dtmf_gen_init((float) i/1000.0f, -17, 0.0f, -17, 50, 50);
409 len = my_dtmf_generate(amp, digit);
410 codec_munge(munge, amp, len);
411 dtmf_rx(dtmf_state, amp, len);
412 nminus += dtmf_rx_get(dtmf_state, buf, 128);
413 }
414 rrb = (float) (nplus + nminus)/10.0f;
415 rcfo = (float) (nplus - nminus)/10.0f;
416 printf(" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
417 digit[0],
418 rrb,
419 rcfo,
420 (float) nminus/10.0f,
421 (float) nplus/10.0f);
422 if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo)
423 {
424 printf(" Failed\n");
425 exit(2);
426 }
427
428 for (nplus = 0, i = 1; i <= 60; i++)
429 {
430 my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50);
431 len = my_dtmf_generate(amp, digit);
432 codec_munge(munge, amp, len);
433 dtmf_rx(dtmf_state, amp, len);
434 nplus += dtmf_rx_get(dtmf_state, buf, 128);
435 }
436 for (nminus = 0, i = -1; i >= -60; i--)
437 {
438 my_dtmf_gen_init(0.0f, -17, (float) i/1000.0f, -17, 50, 50);
439 len = my_dtmf_generate(amp, digit);
440 codec_munge(munge, amp, len);
441 dtmf_rx(dtmf_state, amp, len);
442 nminus += dtmf_rx_get(dtmf_state, buf, 128);
443 }
444 rrb = (float) (nplus + nminus)/10.0f;
445 rcfo = (float) (nplus - nminus)/10.0f;
446 printf(" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n",
447 digit[0],
448 rrb,
449 rcfo,
450 (float) nminus/10.0f,
451 (float) nplus/10.0f);
452 if (rrb < 3.0f + rcfo || rrb >= 15.0f + rcfo)
453 {
454 printf(" Failed\n");
455 exit(2);
456 }
457 }
458 printf(" Passed\n");
459
460 /* Test 4: Acceptable amplitude ratio (twist).
461 Use only the diagonal pairs of tones (digits 1, 5, 9 and D).
462 There are eight sections to the test. Each section contains 200
463 pulses with a 50ms duration for each pulse. Initially the amplitude
464 of both tones is 6dB down from clip. The two sections to test one
465 tone pair are:
466
467 a. Standard Twist: H tone amplitude is maintained at -6dB from clip,
468 L tone amplitude is attenuated gradually until the amplitude ratio
469 L/H is -20dB. Note the number of responses from the receiver.
470 b. Reverse Twist: L tone amplitude is maintained at -6dB from clip,
471 H tone amplitude is attenuated gradually until the amplitude ratio
472 is 20dB. Note the number of responses from the receiver.
473
474 All tone bursts are of 50ms duration.
475
476 The Acceptable Amplitude Ratio in dB is equal to the number of
477 responses registered in (a) or (b), divided by 10.
478
479 TODO: This is supposed to work in 1/10dB steps, but here I used 1dB
480 steps, as the current tone generator has its amplitude set in
481 1dB steps.
482 */
483 printf("Test 4: Acceptable amplitude ratio (twist)\n");
484 s = "159D";
485 digit[1] = '\0';
486 while (*s)
487 {
488 digit[0] = *s++;
489 for (nplus = 0, i = -30; i >= -230; i--)
490 {
491 my_dtmf_gen_init(0.0f, -3, 0.0f, i/10, 50, 50);
492
493 len = my_dtmf_generate(amp, digit);
494 codec_munge(munge, amp, len);
495 dtmf_rx(dtmf_state, amp, len);
496 nplus += dtmf_rx_get(dtmf_state, buf, 128);
497 }
498 printf(" %c normal twist = %.2fdB\n", digit[0], (float) nplus/10.0);
499 if (nplus < 80)
500 {
501 printf(" Failed\n");
502 exit(2);
503 }
504 for (nminus = 0, i = -30; i >= -230; i--)
505 {
506 my_dtmf_gen_init(0.0f, i/10, 0.0f, -3, 50, 50);
507
508 len = my_dtmf_generate(amp, digit);
509 codec_munge(munge, amp, len);
510 dtmf_rx(dtmf_state, amp, len);
511 nminus += dtmf_rx_get(dtmf_state, buf, 128);
512 }
513 printf(" %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0);
514 if (nminus < 40)
515 {
516 printf(" Failed\n");
517 exit(2);
518 }
519 }
520 printf(" Passed\n");
521
522 /* Test 5: Dynamic range
523 This test utilizes tone pair L1 H1 (digit 1). Thirty-five tone pair
524 pulses are transmitted, with both frequencies stating at -6dB from
525 clip. The amplitude of each is gradually attenuated by -35dB at a
526 rate of 1dB per pulse. The Dynamic Range in dB is equal to the
527 number of responses from the receiver during the test.
528
529 Well not really, but that is the Mitel test. Lets sweep a bit further,
530 and see what the real range is */
531 printf("Test 5: Dynamic range\n");
532 for (nplus = 0, i = +3; i >= -50; i--)
533 {
534 my_dtmf_gen_init(0.0f, i, 0.0f, i, 50, 50);
535
536 len = my_dtmf_generate(amp, "1");
537 codec_munge(munge, amp, len);
538 dtmf_rx(dtmf_state, amp, len);
539 nplus += dtmf_rx_get(dtmf_state, buf, 128);
540 }
541 printf(" Dynamic range = %ddB\n", nplus);
542 /* We ought to set some pass/fail condition, even if Mitel did not. If
543 we don't, regression testing is weakened. */
544 if (nplus < 35)
545 {
546 printf(" Failed\n");
547 exit(2);
548 }
549 printf(" Passed\n");
550
551 /* Test 6: Guard time
552 This test utilizes tone pair L1 H1 (digit 1). Four hundred pulses
553 are transmitted at an amplitude of -6dB from clip per frequency.
554 Pulse duration starts at 49ms and is gradually reduced to 10ms.
555 Guard time in ms is equal to (500 - number of responses)/10.
556
557 That is the Mitel test, and we will follow it. Its totally bogus,
558 though. Just what the heck is a pass or fail here? */
559
560 printf("Test 6: Guard time\n");
561 for (nplus = 0, i = 490; i >= 100; i--)
562 {
563 my_dtmf_gen_init(0.0f, -3, 0.0f, -3, i/10, 50);
564
565 len = my_dtmf_generate(amp, "1");
566 codec_munge(munge, amp, len);
567 dtmf_rx(dtmf_state, amp, len);
568 nplus += dtmf_rx_get(dtmf_state, buf, 128);
569 }
570 printf(" Guard time = %dms\n", (500 - nplus)/10);
571 printf(" Passed\n");
572
573 /* Test 7: Acceptable signal to noise ratio
574 This test utilizes tone pair L1 H1, transmitted on a noise background.
575 The test consists of three sections in which the tone pair is
576 transmitted 1000 times at an amplitude -6dB from clip per frequency,
577 but with a different white noise level for each section. The first
578 level is -24dBV, the second -18dBV and the third -12dBV.. The
579 acceptable signal to noise ratio is the lowest ratio of signal
580 to noise in the test where the receiver responds to all 1000 pulses.
581
582 Well, that is the Mitel test, but it doesn't tell you what the
583 decoder can really do. Lets do a more comprehensive test */
584
585 printf("Test 7: Acceptable signal to noise ratio\n");
586 my_dtmf_gen_init(0.0f, -4, 0.0f, -4, 50, 50);
587
588 for (j = -13; j > -50; j--)
589 {
590 awgn_init_dbm0(&noise_source, 1234567, (float) j);
591 for (i = 0; i < 1000; i++)
592 {
593 len = my_dtmf_generate(amp, "1");
594
595 // TODO: Clip
596 for (sample = 0; sample < len; sample++)
597 amp[sample] = saturate(amp[sample] + awgn(&noise_source));
598
599 codec_munge(munge, amp, len);
600 dtmf_rx(dtmf_state, amp, len);
601
602 if (dtmf_rx_get(dtmf_state, buf, 128) != 1)
603 break;
604 }
605 if (i == 1000)
606 break;
607 }
608 printf(" Acceptable S/N ratio is %ddB\n", -4 - j);
609 if (-4 - j > 26)
610 {
611 printf(" Failed\n");
612 exit(2);
613 }
614 printf(" Passed\n");
615 }
616 /*- End of function --------------------------------------------------------*/
617
618 static void mitel_cm7291_side_2_and_bellcore_tests(void)
619 {
620 int i;
621 int j;
622 int len;
623 int hits;
624 int hit_types[256];
625 char buf[128 + 1];
626 SNDFILE *inhandle;
627 int frames;
628 dtmf_rx_state_t *dtmf_state;
629
630 dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
631 if (use_dialtone_filter)
632 dtmf_rx_parms(dtmf_state, TRUE, -1, -1, -99);
633
634 /* The remainder of the Mitel tape is the talk-off test */
635 /* Here we use the Bellcore test tapes (much tougher), in six
636 files - 1 from each side of the original 3 cassette tapes */
637 /* Bellcore say you should get no more than 470 false detections with
638 a good receiver. Dialogic claim 20. Of course, we can do better than
639 that, eh? */
640 printf("Test 8: Talk-off test\n");
641 memset(hit_types, '\0', sizeof(hit_types));
642 for (j = 0; bellcore_files[j][0]; j++)
643 {
644 if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL)
645 {
646 printf(" Cannot open speech file '%s'\n", bellcore_files[j]);
647 exit(2);
648 }
649 hits = 0;
650 while ((frames = sf_readf_short(inhandle, amp, SAMPLE_RATE)))
651 {
652 dtmf_rx(dtmf_state, amp, frames);
653 len = dtmf_rx_get(dtmf_state, buf, 128);
654 if (len > 0)
655 {
656 for (i = 0; i < len; i++)
657 hit_types[(int) buf[i]]++;
658 hits += len;
659 }
660 }
661 if (sf_close(inhandle) != 0)
662 {
663 printf(" Cannot close speech file '%s'\n", bellcore_files[j]);
664 exit(2);
665 }
666 printf(" File %d gave %d false hits.\n", j + 1, hits);
667 }
668 for (i = 0, j = 0; i < 256; i++)
669 {
670 if (hit_types[i])
671 {
672 printf(" Digit %c had %d false hits\n", i, hit_types[i]);
673 j += hit_types[i];
674 }
675 }
676 printf(" %d hits in total\n", j);
677 if (j > 470)
678 {
679 printf(" Failed\n");
680 exit(2);
681 }
682 printf(" Passed\n");
683 }
684 /*- End of function --------------------------------------------------------*/
685
686 static void dial_tone_tolerance_tests(void)
687 {
688 int i;
689 int j;
690 int len;
691 int sample;
692 char buf[128 + 1];
693 dtmf_rx_state_t *dtmf_state;
694 tone_gen_descriptor_t dial_tone_desc;
695 tone_gen_state_t dial_tone;
696
697 dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
698 if (use_dialtone_filter)
699 dtmf_rx_parms(dtmf_state, TRUE, -1, -1, -99);
700
701 /* Test dial tone tolerance */
702 printf("Test: Dial tone tolerance.\n");
703 my_dtmf_gen_init(0.0f, -15, 0.0f, -15, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME);
704
705 for (j = -30; j < -3; j++)
706 {
707 make_tone_gen_descriptor(&dial_tone_desc, 350, j, 440, j, 1, 0, 0, 0, TRUE);
708 tone_gen_init(&dial_tone, &dial_tone_desc);
709 for (i = 0; i < 10; i++)
710 {
711 len = my_dtmf_generate(amp, ALL_POSSIBLE_DIGITS);
712 tone_gen(&dial_tone, amp2, len);
713
714 for (sample = 0; sample < len; sample++)
715 amp[sample] = saturate(amp[sample] + amp2[sample]);
716 codec_munge(munge, amp, len);
717 dtmf_rx(dtmf_state, amp, len);
718
719 if (dtmf_rx_get(dtmf_state, buf, 128) != strlen(ALL_POSSIBLE_DIGITS))
720 break;
721 }
722 if (i != 10)
723 break;
724 }
725 printf(" Acceptable signal to dial tone ratio is %ddB\n", -15 - j);
726 if ((use_dialtone_filter && (-15 - j) > -12)
727 ||
728 (!use_dialtone_filter && (-15 - j) > 10))
729 {
730 printf(" Failed\n");
731 exit(2);
732 }
733 printf(" Passed\n");
734 }
735 /*- End of function --------------------------------------------------------*/
736
737 static void callback_function_tests(void)
738 {
739 int i;
740 int j;
741 int len;
742 int sample;
743 dtmf_rx_state_t *dtmf_state;
744
745 /* Test the callback mode for delivering detected digits */
746 printf("Test: Callback digit delivery mode.\n");
747 callback_hit = FALSE;
748 callback_ok = TRUE;
749 callback_roll = 0;
750 dtmf_state = dtmf_rx_init(NULL, digit_delivery, (void *) 0x12345678);
751 if (use_dialtone_filter)
752 dtmf_rx_parms(dtmf_state, TRUE, -1, -1, -99);
753 my_dtmf_gen_init(0.0f, DEFAULT_DTMF_TX_LEVEL, 0.0f, DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME);
754 for (i = 1; i < 10; i++)
755 {
756 len = 0;
757 for (j = 0; j < i; j++)
758 len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS);
759 dtmf_rx(dtmf_state, amp, len);
760 if (!callback_hit || !callback_ok)
761 break;
762 }
763 if (!callback_hit || !callback_ok)
764 {
765 printf(" Failed\n");
766 exit(2);
767 }
768 printf(" Passed\n");
769
770 /* Test the realtime callback mode for reporting detected digits */
771 printf("Test: Realtime callback digit delivery mode.\n");
772 callback_hit = FALSE;
773 callback_ok = TRUE;
774 callback_roll = 0;
775 dtmf_rx_init(dtmf_state, NULL, NULL);
776 dtmf_rx_set_realtime_callback(dtmf_state, digit_status, (void *) 0x12345678);
777 if (use_dialtone_filter)
778 dtmf_rx_parms(dtmf_state, TRUE, -1, -1, -99);
779 my_dtmf_gen_init(0.0f, DEFAULT_DTMF_TX_LEVEL, 0.0f, DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME, DEFAULT_DTMF_TX_OFF_TIME);
780 step = 0;
781 for (i = 1; i < 10; i++)
782 {
783 len = 0;
784 for (j = 0; j < i; j++)
785 len += my_dtmf_generate(amp + len, ALL_POSSIBLE_DIGITS);
786 for (sample = 0, j = SAMPLES_PER_CHUNK; sample < len; sample += SAMPLES_PER_CHUNK, j = ((len - sample) >= SAMPLES_PER_CHUNK) ? SAMPLES_PER_CHUNK : (len - sample))
787 {
788 dtmf_rx(dtmf_state, &amp[sample], j);
789 if (!callback_ok)
790 break;
791 step += j;
792 }
793 if (!callback_hit || !callback_ok)
794 break;
795 }
796 if (!callback_hit || !callback_ok)
797 {
798 printf(" Failed\n");
799 exit(2);
800 }
801 }
802 /*- End of function --------------------------------------------------------*/
803
804 static void decode_test(const char *test_file)
805 {
806 int16_t amp[SAMPLES_PER_CHUNK];
807 SNDFILE *inhandle;
808 dtmf_rx_state_t *dtmf_state;
809 char buf[128 + 1];
810 int actual;
811 int samples;
812 int total;
813
814 dtmf_state = dtmf_rx_init(NULL, NULL, NULL);
815 if (use_dialtone_filter)
816 dtmf_rx_parms(dtmf_state, TRUE, -1, -1, -99);
817
818 /* We will decode the audio from a file. */
819
820 if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL)
821 {
822 fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file);
823 exit(2);
824 }
825
826 total = 0;
827 while ((samples = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK)) > 0)
828 {
829 codec_munge(munge, amp, samples);
830 dtmf_rx(dtmf_state, amp, samples);
831 //printf("Status 0x%X\n", dtmf_rx_status(dtmf_state));
832 if ((actual = dtmf_rx_get(dtmf_state, buf, 128)) > 0)
833 printf("Received '%s'\n", buf);
834 total += actual;
835 }
836 printf("%d digits received\n", total);
837 }
838 /*- End of function --------------------------------------------------------*/
839
840 int main(int argc, char *argv[])
841 {
842 int duration;
843 time_t now;
844 int channel_codec;
845 int opt;
846
847 use_dialtone_filter = FALSE;
848 channel_codec = MUNGE_CODEC_NONE;
849 decode_test_file = NULL;
850 while ((opt = getopt(argc, argv, "c:d:f")) != -1)
851 {
852 switch (opt)
853 {
854 case 'c':
855 channel_codec = atoi(optarg);
856 break;
857 case 'd':
858 decode_test_file = optarg;
859 break;
860 case 'f':
861 use_dialtone_filter = TRUE;
862 break;
863 default:
864 //usage();
865 exit(2);
866 break;
867 }
868 }
869 munge = codec_munge_init(channel_codec, 0);
870
871 if (decode_test_file)
872 {
873 decode_test(decode_test_file);
874 }
875 else
876 {
877 time(&now);
878 mitel_cm7291_side_1_tests();
879 mitel_cm7291_side_2_and_bellcore_tests();
880 dial_tone_tolerance_tests();
881 callback_function_tests();
882 printf(" Passed\n");
883 duration = time(NULL) - now;
884 printf("Tests passed in %ds\n", duration);
885 }
886
887 return 0;
888 }
889 /*- End of function --------------------------------------------------------*/
890 /*- End of file ------------------------------------------------------------*/

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