Mercurial > hg > audiostuff
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, &[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 ------------------------------------------------------------*/ |