comparison spandsp-0.0.6pre17/tests/super_tone_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 * 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.33 2009/06/02 14:55:36 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 #if defined(HAVE_CONFIG_H)
35 #include "config.h"
36 #endif
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <ctype.h>
44 #include <time.h>
45 #include <sndfile.h>
46
47 #if defined(HAVE_LIBXML_XMLMEMORY_H)
48 #include <libxml/xmlmemory.h>
49 #endif
50 #if defined(HAVE_LIBXML_PARSER_H)
51 #include <libxml/parser.h>
52 #endif
53 #if defined(HAVE_LIBXML_XINCLUDE_H)
54 #include <libxml/xinclude.h>
55 #endif
56
57 //#if defined(WITH_SPANDSP_INTERNALS)
58 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
59 //#endif
60
61 #include "spandsp.h"
62 #include "spandsp-sim.h"
63
64 #define IN_FILE_NAME "super_tone.wav"
65
66 #define MITEL_DIR "../test-data/mitel/"
67 #define BELLCORE_DIR "../test-data/bellcore/"
68
69 const char *bellcore_files[] =
70 {
71 MITEL_DIR "mitel-cm7291-talkoff.wav",
72 BELLCORE_DIR "tr-tsy-00763-1.wav",
73 BELLCORE_DIR "tr-tsy-00763-2.wav",
74 BELLCORE_DIR "tr-tsy-00763-3.wav",
75 BELLCORE_DIR "tr-tsy-00763-4.wav",
76 BELLCORE_DIR "tr-tsy-00763-5.wav",
77 BELLCORE_DIR "tr-tsy-00763-6.wav",
78 ""
79 };
80
81 const char *tone_names[20] = {NULL};
82
83 SNDFILE *inhandle;
84
85 super_tone_rx_segment_t tone_segments[20][10];
86
87 super_tone_tx_step_t *dialtone_tree = NULL;
88 super_tone_tx_step_t *ringback_tree = NULL;
89 super_tone_tx_step_t *busytone_tree = NULL;
90 super_tone_tx_step_t *nutone_tree = NULL;
91 super_tone_tx_step_t *congestiontone_tree = NULL;
92 super_tone_tx_step_t *waitingtone_tree = NULL;
93
94 #if defined(HAVE_LIBXML2)
95 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)
96 {
97 xmlChar *x;
98 float f1;
99 float f2;
100 float f_tol;
101 float l1;
102 float l2;
103 float length;
104 float length_tol;
105 float recognition_length;
106 float recognition_length_tol;
107 int cycles;
108 super_tone_tx_step_t *treep;
109 int min_duration;
110 int max_duration;
111
112 cur = cur->xmlChildrenNode;
113 while (cur)
114 {
115 if (xmlStrcmp(cur->name, (const xmlChar *) "step") == 0)
116 {
117 printf("Step - ");
118 /* Set some defaults */
119 f1 = 0.0;
120 f2 = 0.0;
121 f_tol = 1.0;
122 l1 = -11.0;
123 l2 = -11.0;
124 length = 0.0;
125 length_tol = 10.0;
126 recognition_length = 0.0;
127 recognition_length_tol = 10.0;
128 cycles = 1;
129 if ((x = xmlGetProp(cur, (const xmlChar *) "freq")))
130 {
131 sscanf((char *) x, "%f [%f%%]", &f1, &f_tol);
132 sscanf((char *) x, "%f+%f [%f%%]", &f1, &f2, &f_tol);
133 printf(" Frequency=%.2f+%.2f [%.2f%%]", f1, f2, f_tol);
134 }
135 if ((x = xmlGetProp(cur, (const xmlChar *) "level")))
136 {
137 if (sscanf((char *) x, "%f+%f", &l1, &l2) < 2)
138 l2 = l1;
139 printf(" Level=%.2f+%.2f", l1, l2);
140 }
141 if ((x = xmlGetProp(cur, (const xmlChar *) "length")))
142 {
143 sscanf((char *) x, "%f [%f%%]", &length, &length_tol);
144 printf(" Length=%.2f [%.2f%%]", length, length_tol);
145 }
146 if ((x = xmlGetProp(cur, (const xmlChar *) "recognition-length")))
147 {
148 sscanf((char *) x, "%f [%f%%]", &recognition_length, &recognition_length_tol);
149 printf(" Recognition length=%.2f [%.2f%%]", recognition_length, recognition_length_tol);
150 }
151 if ((x = xmlGetProp(cur, (const xmlChar *) "cycles")))
152 {
153 if (strcasecmp((char *) x, "endless") == 0)
154 cycles = 0;
155 else
156 cycles = atoi((char *) x);
157 printf(" Cycles='%d' ", cycles);
158 }
159 if ((x = xmlGetProp(cur, (const xmlChar *) "recorded-announcement")))
160 printf(" Recorded announcement='%s'", x);
161 printf("\n");
162 if (f1 || f2 || length)
163 {
164 /* TODO: This cannot handle cycling patterns */
165 if (length == 0.0)
166 {
167 if (recognition_length)
168 min_duration = recognition_length*1000.0 + 0.5;
169 else
170 min_duration = 700;
171 max_duration = 0;
172 }
173 else
174 {
175 if (recognition_length)
176 min_duration = recognition_length*1000.0 + 0.5;
177 else
178 min_duration = (length*1000.0 + 0.5)*(1.0 - length_tol/100.0) - 30;
179 max_duration = (length*1000.0 + 0.5)*(1.0 + length_tol/100.0) + 30;
180 }
181 printf(">>>Detector element %10d %10d %10d %10d\n", (int) (f1 + 0.5), (int) (f2 + 0.5), min_duration, max_duration);
182 super_tone_rx_add_element(desc, tone_id, f1 + 0.5, f2 + 0.5, min_duration, max_duration);
183 }
184 treep = super_tone_tx_make_step(NULL,
185 f1,
186 l1,
187 f2,
188 l2,
189 length*1000.0 + 0.5,
190 cycles);
191 *tree = treep;
192 tree = &(treep->next);
193 parse_tone(desc, tone_id, &(treep->nest), doc, ns, cur);
194 }
195 /*endif*/
196 cur = cur->next;
197 }
198 /*endwhile*/
199 return 0;
200 }
201 /*- End of function --------------------------------------------------------*/
202
203 static void parse_tone_set(super_tone_rx_descriptor_t *desc, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur)
204 {
205 int tone_id;
206
207 printf("Parsing tone set\n");
208 cur = cur->xmlChildrenNode;
209 while (cur)
210 {
211 if (strcmp((char *) cur->name, "dial-tone") == 0)
212 {
213 printf("Hit %s\n", cur->name);
214 tone_id = super_tone_rx_add_tone(desc);
215 dialtone_tree = NULL;
216 parse_tone(desc, tone_id, &dialtone_tree, doc, ns, cur);
217 tone_names[tone_id] = "Dial tone";
218 }
219 else if (strcmp((char *) cur->name, "ringback-tone") == 0)
220 {
221 printf("Hit %s\n", cur->name);
222 tone_id = super_tone_rx_add_tone(desc);
223 ringback_tree = NULL;
224 parse_tone(desc, tone_id, &ringback_tree, doc, ns, cur);
225 tone_names[tone_id] = "Ringback tone";
226 }
227 else if (strcmp((char *) cur->name, "busy-tone") == 0)
228 {
229 printf("Hit %s\n", cur->name);
230 tone_id = super_tone_rx_add_tone(desc);
231 busytone_tree = NULL;
232 parse_tone(desc, tone_id, &busytone_tree, doc, ns, cur);
233 tone_names[tone_id] = "Busy tone";
234 }
235 else if (strcmp((char *) cur->name, "number-unobtainable-tone") == 0)
236 {
237 printf("Hit %s\n", cur->name);
238 tone_id = super_tone_rx_add_tone(desc);
239 nutone_tree = NULL;
240 parse_tone(desc, tone_id, &nutone_tree, doc, ns, cur);
241 tone_names[tone_id] = "NU tone";
242 }
243 else if (strcmp((char *) cur->name, "congestion-tone") == 0)
244 {
245 printf("Hit %s\n", cur->name);
246 tone_id = super_tone_rx_add_tone(desc);
247 congestiontone_tree = NULL;
248 parse_tone(desc, tone_id, &congestiontone_tree, doc, ns, cur);
249 tone_names[tone_id] = "Congestion tone";
250 }
251 else if (strcmp((char *) cur->name, "waiting-tone") == 0)
252 {
253 printf("Hit %s\n", cur->name);
254 tone_id = super_tone_rx_add_tone(desc);
255 waitingtone_tree = NULL;
256 parse_tone(desc, tone_id, &waitingtone_tree, doc, ns, cur);
257 tone_names[tone_id] = "Waiting tone";
258 }
259 /*endif*/
260 cur = cur->next;
261 }
262 /*endwhile*/
263 }
264 /*- End of function --------------------------------------------------------*/
265
266 static void get_tone_set(super_tone_rx_descriptor_t *desc, const char *tone_file, const char *set_id)
267 {
268 xmlDocPtr doc;
269 xmlNsPtr ns;
270 xmlNodePtr cur;
271 #if 1
272 xmlValidCtxt valid;
273 #endif
274 xmlChar *x;
275
276 ns = NULL;
277 xmlKeepBlanksDefault(0);
278 xmlCleanupParser();
279 if ((doc = xmlParseFile(tone_file)) == NULL)
280 {
281 fprintf(stderr, "No document\n");
282 exit(2);
283 }
284 /*endif*/
285 xmlXIncludeProcess(doc);
286 #if 1
287 if (!xmlValidateDocument(&valid, doc))
288 {
289 fprintf(stderr, "Invalid document\n");
290 exit(2);
291 }
292 /*endif*/
293 #endif
294 /* Check the document is of the right kind */
295 if ((cur = xmlDocGetRootElement(doc)) == NULL)
296 {
297 fprintf(stderr, "Empty document\n");
298 xmlFreeDoc(doc);
299 exit(2);
300 }
301 /*endif*/
302 if (xmlStrcmp(cur->name, (const xmlChar *) "global-tones"))
303 {
304 fprintf(stderr, "Document of the wrong type, root node != global-tones");
305 xmlFreeDoc(doc);
306 exit(2);
307 }
308 /*endif*/
309 cur = cur->xmlChildrenNode;
310 while (cur && xmlIsBlankNode (cur))
311 cur = cur->next;
312 /*endwhile*/
313 if (cur == NULL)
314 exit(2);
315 /*endif*/
316 while (cur)
317 {
318 if (xmlStrcmp(cur->name, (const xmlChar *) "tone-set") == 0)
319 {
320 if ((x = xmlGetProp(cur, (const xmlChar *) "uncode")))
321 {
322 if (strcmp((char *) x, set_id) == 0)
323 parse_tone_set(desc, doc, ns, cur);
324 }
325 /*endif*/
326 }
327 /*endif*/
328 cur = cur->next;
329 }
330 /*endwhile*/
331 xmlFreeDoc(doc);
332 }
333 /*- End of function --------------------------------------------------------*/
334 #endif
335
336 static void super_tone_rx_fill_descriptor(super_tone_rx_descriptor_t *desc)
337 {
338 int tone_id;
339
340 tone_id = super_tone_rx_add_tone(desc);
341 super_tone_rx_add_element(desc, tone_id, 400, 0, 700, 0);
342 tone_names[tone_id] = "XXX";
343
344 tone_id = super_tone_rx_add_tone(desc);
345 super_tone_rx_add_element(desc, tone_id, 1100, 0, 400, 600);
346 super_tone_rx_add_element(desc, tone_id, 0, 0, 2800, 3200);
347 tone_names[tone_id] = "FAX tone";
348 }
349 /*- End of function --------------------------------------------------------*/
350
351 static void wakeup(void *data, int code, int level, int delay)
352 {
353 if (code >= 0)
354 printf("Current tone is %d '%s' '%s'\n", code, (tone_names[code]) ? tone_names[code] : "???", (char *) data);
355 else
356 printf("Tone off '%s'\n", (char *) data);
357 }
358 /*- End of function --------------------------------------------------------*/
359
360 static void tone_segment(void *data, int f1, int f2, int duration)
361 {
362 if (f1 < 0)
363 printf("Result %5d silence\n", duration);
364 else if (f2 < 0)
365 printf("Result %5d %4d\n", duration, f1);
366 else
367 printf("Result %5d %4d + %4d\n", duration, f1, f2);
368 }
369 /*- End of function --------------------------------------------------------*/
370
371 int main(int argc, char *argv[])
372 {
373 int x;
374 int16_t amp[8000];
375 int sample;
376 int frames;
377 awgn_state_t noise_source;
378 super_tone_rx_state_t *super;
379 super_tone_rx_descriptor_t desc;
380
381 if ((inhandle = sf_open_telephony_read(IN_FILE_NAME, 1)) == NULL)
382 {
383 fprintf(stderr, " Cannot open audio file '%s'\n", IN_FILE_NAME);
384 exit(2);
385 }
386 super_tone_rx_make_descriptor(&desc);
387 #if defined(HAVE_LIBXML2)
388 get_tone_set(&desc, "../spandsp/global-tones.xml", (argc > 1) ? argv[1] : "hk");
389 #endif
390 super_tone_rx_fill_descriptor(&desc);
391 if ((super = super_tone_rx_init(NULL, &desc, wakeup, (void *) "test")) == NULL)
392 {
393 printf(" Failed to create detector.\n");
394 exit(2);
395 }
396 super_tone_rx_segment_callback(super, tone_segment);
397 awgn_init_dbm0(&noise_source, 1234567, -30.0f);
398 printf("Processing file\n");
399 while ((frames = sf_readf_short(inhandle, amp, 8000)))
400 {
401 /* Add some noise to the signal for a more meaningful test. */
402 //for (sample = 0; sample < frames; sample++)
403 // amp[sample] += saturate(amp[sample] + awgn (&noise_source));
404 for (sample = 0; sample < frames; )
405 {
406 x = super_tone_rx(super, amp + sample, frames - sample);
407 sample += x;
408 }
409 }
410 if (sf_close(inhandle))
411 {
412 fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME);
413 exit(2);
414 }
415 #if 0
416 /* Test for voice immunity */
417 for (j = 0; bellcore_files[j][0]; j++)
418 {
419 if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL)
420 {
421 printf(" Cannot open audio file '%s'\n", bellcore_files[j]);
422 exit(2);
423 }
424 while ((frames = sf_readf_short(inhandle, amp, 8000)))
425 {
426 for (sample = 0; sample < frames; )
427 {
428 x = super_tone_rx(super, amp + sample, frames - sample);
429 sample += x;
430 }
431 }
432 if (sf_close(inhandle) != 0)
433 {
434 printf(" Cannot close speech file '%s'\n", bellcore_files[j]);
435 exit(2);
436 }
437 }
438 #endif
439 super_tone_rx_free(super);
440 printf("Done\n");
441 return 0;
442 }
443 /*- End of function --------------------------------------------------------*/
444 /*- End of file ------------------------------------------------------------*/

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