comparison spandsp-0.0.3/spandsp-0.0.3/tests/super_tone_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 * super_tone_detect_tests.c
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2003 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2, as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: super_tone_rx_tests.c,v 1.18 2006/11/20 13:58:57 steveu Exp $
26 */
27
28 /*! \file */
29
30 /*! \page super_tone_rx_tests_page Supervisory tone detection tests
31 \section super_tone_rx_tests_page_sec_1 What does it do?
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <strings.h>
41 #include <stdio.h>
42 #include <fcntl.h>
43 #include <ctype.h>
44 #include <time.h>
45 #include <inttypes.h>
46 #include <sys/socket.h>
47 #if defined(HAVE_TGMATH_H)
48 #include <tgmath.h>
49 #endif
50 #if defined(HAVE_MATH_H)
51 #include <math.h>
52 #endif
53
54 #if defined(HAVE_LIBXML_XMLMEMORY_H)
55 #include <libxml/xmlmemory.h>
56 #endif
57 #if defined(HAVE_LIBXML_PARSER_H)
58 #include <libxml/parser.h>
59 #endif
60 #if defined(HAVE_LIBXML_XINCLUDE_H)
61 #include <libxml/xinclude.h>
62 #endif
63
64 #include <audiofile.h>
65 #include <tiffio.h>
66
67 #include "spandsp.h"
68
69 #define IN_FILE_NAME "super_tone.wav"
70 #define BELLCORE_DIR "../itutests/bellcore/"
71
72 const char *bellcore_files[] =
73 {
74 BELLCORE_DIR "tr-tsy-00763-1.wav",
75 BELLCORE_DIR "tr-tsy-00763-2.wav",
76 BELLCORE_DIR "tr-tsy-00763-3.wav",
77 BELLCORE_DIR "tr-tsy-00763-4.wav",
78 BELLCORE_DIR "tr-tsy-00763-5.wav",
79 BELLCORE_DIR "tr-tsy-00763-6.wav",
80 ""
81 };
82
83 const char *tone_names[20] = {NULL};
84
85 AFfilehandle inhandle;
86
87 super_tone_rx_segment_t tone_segments[20][10];
88
89 super_tone_tx_step_t *dialtone_tree = NULL;
90 super_tone_tx_step_t *ringback_tree = NULL;
91 super_tone_tx_step_t *busytone_tree = NULL;
92 super_tone_tx_step_t *nutone_tree = NULL;
93 super_tone_tx_step_t *congestiontone_tree = NULL;
94 super_tone_tx_step_t *waitingtone_tree = NULL;
95
96 #if defined(HAVE_LIBXML2)
97 static int parse_tone(super_tone_rx_descriptor_t *desc, int tone_id, super_tone_tx_step_t **tree, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur)
98 {
99 xmlChar *x;
100 float f1;
101 float f2;
102 float f_tol;
103 float l1;
104 float l2;
105 float length;
106 float length_tol;
107 float recognition_length;
108 float recognition_length_tol;
109 int cycles;
110 super_tone_tx_step_t *treep;
111 int min_duration;
112 int max_duration;
113
114 cur = cur->xmlChildrenNode;
115 while (cur)
116 {
117 if (xmlStrcmp(cur->name, (const xmlChar *) "step") == 0)
118 {
119 printf("Step - ");
120 /* Set some defaults */
121 f1 = 0.0;
122 f2 = 0.0;
123 f_tol = 1.0;
124 l1 = -11.0;
125 l2 = -11.0;
126 length = 0.0;
127 length_tol = 10.0;
128 recognition_length = 0.0;
129 recognition_length_tol = 10.0;
130 cycles = 1;
131 if ((x = xmlGetProp(cur, (const xmlChar *) "freq")))
132 {
133 sscanf((char *) x, "%f [%f%%]", &f1, &f_tol);
134 sscanf((char *) x, "%f+%f [%f%%]", &f1, &f2, &f_tol);
135 printf(" Frequency=%.2f+%.2f [%.2f%%]", f1, f2, f_tol);
136 }
137 if ((x = xmlGetProp(cur, (const xmlChar *) "level")))
138 {
139 if (sscanf((char *) x, "%f+%f", &l1, &l2) < 2)
140 l2 = l1;
141 printf(" Level=%.2f+%.2f", l1, l2);
142 }
143 if ((x = xmlGetProp(cur, (const xmlChar *) "length")))
144 {
145 sscanf((char *) x, "%f [%f%%]", &length, &length_tol);
146 printf(" Length=%.2f [%.2f%%]", length, length_tol);
147 }
148 if ((x = xmlGetProp(cur, (const xmlChar *) "recognition-length")))
149 {
150 sscanf((char *) x, "%f [%f%%]", &recognition_length, &recognition_length_tol);
151 printf(" Recognition length=%.2f [%.2f%%]", recognition_length, recognition_length_tol);
152 }
153 if ((x = xmlGetProp(cur, (const xmlChar *) "cycles")))
154 {
155 if (strcasecmp((char *) x, "endless") == 0)
156 cycles = 0;
157 else
158 cycles = atoi((char *) x);
159 printf(" Cycles='%d' ", cycles);
160 }
161 if ((x = xmlGetProp(cur, (const xmlChar *) "recorded-announcement")))
162 printf(" Recorded announcement='%s'", x);
163 printf("\n");
164 if (f1 || f2 || length)
165 {
166 /* TODO: This cannot handle cycling patterns */
167 if (length == 0.0)
168 {
169 if (recognition_length)
170 min_duration = recognition_length*1000.0 + 0.5;
171 else
172 min_duration = 700;
173 max_duration = 0;
174 }
175 else
176 {
177 if (recognition_length)
178 min_duration = recognition_length*1000.0 + 0.5;
179 else
180 min_duration = (length*1000.0 + 0.5)*(1.0 - length_tol/100.0) - 30;
181 max_duration = (length*1000.0 + 0.5)*(1.0 + length_tol/100.0) + 30;
182 }
183 printf(">>>Detector element %10d %10d %10d %10d\n", (int) (f1 + 0.5), (int) (f2 + 0.5), min_duration, max_duration);
184 super_tone_rx_add_element(desc, tone_id, f1 + 0.5, f2 + 0.5, min_duration, max_duration);
185 }
186 treep = super_tone_tx_make_step(NULL,
187 f1,
188 l1,
189 f2,
190 l2,
191 length*1000.0 + 0.5,
192 cycles);
193 *tree = treep;
194 tree = &(treep->next);
195 parse_tone(desc, tone_id, &(treep->nest), doc, ns, cur);
196 }
197 /*endif*/
198 cur = cur->next;
199 }
200 /*endwhile*/
201 return 0;
202 }
203 /*- End of function --------------------------------------------------------*/
204
205 static void parse_tone_set(super_tone_rx_descriptor_t *desc, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur)
206 {
207 int tone_id;
208
209 printf("Parsing tone set\n");
210 cur = cur->xmlChildrenNode;
211 while (cur)
212 {
213 if (strcmp((char *) cur->name, "dial-tone") == 0)
214 {
215 printf("Hit %s\n", cur->name);
216 tone_id = super_tone_rx_add_tone(desc);
217 dialtone_tree = NULL;
218 parse_tone(desc, tone_id, &dialtone_tree, doc, ns, cur);
219 tone_names[tone_id] = "Dial tone";
220 }
221 else if (strcmp((char *) cur->name, "ringback-tone") == 0)
222 {
223 printf("Hit %s\n", cur->name);
224 tone_id = super_tone_rx_add_tone(desc);
225 ringback_tree = NULL;
226 parse_tone(desc, tone_id, &ringback_tree, doc, ns, cur);
227 tone_names[tone_id] = "Ringback tone";
228 }
229 else if (strcmp((char *) cur->name, "busy-tone") == 0)
230 {
231 printf("Hit %s\n", cur->name);
232 tone_id = super_tone_rx_add_tone(desc);
233 busytone_tree = NULL;
234 parse_tone(desc, tone_id, &busytone_tree, doc, ns, cur);
235 tone_names[tone_id] = "Busy tone";
236 }
237 else if (strcmp((char *) cur->name, "number-unobtainable-tone") == 0)
238 {
239 printf("Hit %s\n", cur->name);
240 tone_id = super_tone_rx_add_tone(desc);
241 nutone_tree = NULL;
242 parse_tone(desc, tone_id, &nutone_tree, doc, ns, cur);
243 tone_names[tone_id] = "NU tone";
244 }
245 else if (strcmp((char *) cur->name, "congestion-tone") == 0)
246 {
247 printf("Hit %s\n", cur->name);
248 tone_id = super_tone_rx_add_tone(desc);
249 congestiontone_tree = NULL;
250 parse_tone(desc, tone_id, &congestiontone_tree, doc, ns, cur);
251 tone_names[tone_id] = "Congestion tone";
252 }
253 else if (strcmp((char *) cur->name, "waiting-tone") == 0)
254 {
255 printf("Hit %s\n", cur->name);
256 tone_id = super_tone_rx_add_tone(desc);
257 waitingtone_tree = NULL;
258 parse_tone(desc, tone_id, &waitingtone_tree, doc, ns, cur);
259 tone_names[tone_id] = "Waiting tone";
260 }
261 /*endif*/
262 cur = cur->next;
263 }
264 /*endwhile*/
265 }
266 /*- End of function --------------------------------------------------------*/
267
268 static void get_tone_set(super_tone_rx_descriptor_t *desc, const char *tone_file, const char *set_id)
269 {
270 xmlDocPtr doc;
271 xmlNsPtr ns;
272 xmlNodePtr cur;
273 #if 0
274 xmlValidCtxt valid;
275 #endif
276 xmlChar *x;
277
278 ns = NULL;
279 xmlKeepBlanksDefault(0);
280 xmlCleanupParser();
281 doc = xmlParseFile(tone_file);
282 if (doc == NULL)
283 {
284 fprintf(stderr, "No document\n");
285 exit(2);
286 }
287 /*endif*/
288 xmlXIncludeProcess(doc);
289 #if 0
290 if (!xmlValidateDocument(&valid, doc))
291 {
292 fprintf(stderr, "Invalid document\n");
293 exit(2);
294 }
295 /*endif*/
296 #endif
297 /* Check the document is of the right kind */
298 if ((cur = xmlDocGetRootElement(doc)) == NULL)
299 {
300 fprintf(stderr, "Empty document\n");
301 xmlFreeDoc(doc);
302 exit(2);
303 }
304 /*endif*/
305 if (xmlStrcmp(cur->name, (const xmlChar *) "global-tones"))
306 {
307 fprintf(stderr, "Document of the wrong type, root node != global-tones");
308 xmlFreeDoc(doc);
309 exit(2);
310 }
311 /*endif*/
312 cur = cur->xmlChildrenNode;
313 while (cur && xmlIsBlankNode (cur))
314 cur = cur->next;
315 /*endwhile*/
316 if (cur == NULL)
317 exit(2);
318 /*endif*/
319 while (cur)
320 {
321 if (xmlStrcmp(cur->name, (const xmlChar *) "tone-set") == 0)
322 {
323 if ((x = xmlGetProp(cur, (const xmlChar *) "uncode")))
324 {
325 if (strcmp((char *) x, set_id) == 0)
326 parse_tone_set(desc, doc, ns, cur);
327 }
328 /*endif*/
329 }
330 /*endif*/
331 cur = cur->next;
332 }
333 /*endwhile*/
334 xmlFreeDoc(doc);
335 }
336 /*- End of function --------------------------------------------------------*/
337 #endif
338
339 static void super_tone_rx_fill_descriptor(super_tone_rx_descriptor_t *desc)
340 {
341 int tone_id;
342
343 tone_id = super_tone_rx_add_tone(desc);
344 super_tone_rx_add_element(desc, tone_id, 400, 0, 700, 0);
345 tone_names[tone_id] = "XXX";
346
347 tone_id = super_tone_rx_add_tone(desc);
348 super_tone_rx_add_element(desc, tone_id, 1100, 0, 400, 600);
349 super_tone_rx_add_element(desc, tone_id, 0, 0, 2800, 3200);
350 tone_names[tone_id] = "FAX tone";
351 }
352 /*- End of function --------------------------------------------------------*/
353
354 static void wakeup(void *data, int code)
355 {
356 if (code >= 0)
357 printf("Current tone is %d '%s' '%s'\n", code, (tone_names[code]) ? tone_names[code] : "???", (char *) data);
358 else
359 printf("Tone off '%s'\n", (char *) data);
360 }
361 /*- End of function --------------------------------------------------------*/
362
363 static void tone_segment(void *data, int f1, int f2, int duration)
364 {
365 if (f1 < 0)
366 printf("Result %5d silence\n", duration);
367 else if (f2 < 0)
368 printf("Result %5d %4d\n", duration, f1);
369 else
370 printf("Result %5d %4d + %4d\n", duration, f1, f2);
371 }
372 /*- End of function --------------------------------------------------------*/
373
374 int main(int argc, char *argv[])
375 {
376 int x;
377 int16_t amp[8000];
378 int sample;
379 int frames;
380 awgn_state_t noise_source;
381 super_tone_rx_state_t *super;
382 super_tone_rx_descriptor_t desc;
383
384 if ((inhandle = afOpenFile(IN_FILE_NAME, "r", 0)) == AF_NULL_FILEHANDLE)
385 {
386 fprintf(stderr, " Cannot open wave file '%s'\n", IN_FILE_NAME);
387 exit(2);
388 }
389 if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0)
390 {
391 printf(" Unexpected frame size in wave file '%s'\n", IN_FILE_NAME);
392 exit(2);
393 }
394 if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE)
395 {
396 printf(" Unexpected sample rate in wave file '%s'\n", IN_FILE_NAME);
397 exit(2);
398 }
399 if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0)
400 {
401 printf(" Unexpected number of channels in wave file '%s'\n", IN_FILE_NAME);
402 exit(2);
403 }
404 super_tone_rx_make_descriptor(&desc);
405 #if defined(HAVE_LIBXML2)
406 get_tone_set(&desc, "../spandsp/global-tones.xml", (argc > 1) ? argv[1] : "hk");
407 #endif
408 super_tone_rx_fill_descriptor(&desc);
409 if ((super = super_tone_rx_init(NULL, &desc, wakeup, (void *) "test")) == NULL)
410 {
411 printf(" Failed to create detector.\n");
412 exit(2);
413 }
414 super_tone_rx_segment_callback(super, tone_segment);
415 awgn_init_dbm0(&noise_source, 1234567, -30.0f);
416 printf("Processing file\n");
417 while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, 8000)))
418 {
419 /* Add some noise to the signal for a more meaningful test. */
420 //for (sample = 0; sample < frames; sample++)
421 // amp[sample] += saturate(amp[sample] + awgn (&noise_source));
422 for (sample = 0; sample < frames; )
423 {
424 x = super_tone_rx(super, amp + sample, frames - sample);
425 sample += x;
426 }
427 }
428 if (afCloseFile(inhandle))
429 {
430 fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME);
431 exit(2);
432 }
433 #if 0
434 /* Test for voice immunity */
435 for (j = 0; bellcore_files[j][0]; j++)
436 {
437 if ((inhandle = afOpenFile(bellcore_files[j], "r", 0)) == AF_NULL_FILEHANDLE)
438 {
439 printf(" Cannot open wave file '%s'\n", bellcore_files[j]);
440 exit(2);
441 }
442 if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0)
443 {
444 printf(" Unexpected frame size in wave file '%s'\n", bellcore_files[j]);
445 exit(2);
446 }
447 if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE)
448 {
449 printf(" Unexpected sample rate in wave file '%s'\n", bellcore_files[j]);
450 exit(2);
451 }
452 if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0)
453 {
454 printf(" Unexpected number of channels in wave file '%s'\n", bellcore_files[j]);
455 exit(2);
456 }
457 while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, 8000)))
458 {
459 for (sample = 0; sample < frames; )
460 {
461 x = super_tone_rx(super, amp + sample, frames - sample);
462 sample += x;
463 }
464 }
465 if (afCloseFile(inhandle) != 0)
466 {
467 printf(" Cannot close speech file '%s'\n", bellcore_files[j]);
468 exit(2);
469 }
470 }
471 #endif
472 super_tone_rx_free(super);
473 printf("Done\n");
474 return 0;
475 }
476 /*- End of function --------------------------------------------------------*/
477 /*- End of file ------------------------------------------------------------*/

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