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