5
|
1 /*
|
|
2 * SpanDSP - a series of DSP components for telephony
|
|
3 *
|
|
4 * modem_connect_tones_tests.c
|
|
5 *
|
|
6 * Written by Steve Underwood <steveu@coppice.org>
|
|
7 *
|
|
8 * Copyright (C) 2006 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: modem_connect_tones_tests.c,v 1.5 2006/11/19 14:07:27 steveu Exp $
|
|
26 */
|
|
27
|
|
28 /*! \page modem_connect_tones_tests_page Modem connect tones tests
|
|
29 \section modem_connect_tones_rx_tests_page_sec_1 What does it do?
|
|
30 These tests...
|
|
31 */
|
|
32
|
|
33 #ifdef HAVE_CONFIG_H
|
|
34 #include "config.h"
|
|
35 #endif
|
|
36
|
|
37 #include <stdlib.h>
|
|
38 #include <inttypes.h>
|
|
39 #include <stdio.h>
|
|
40 #if defined(HAVE_TGMATH_H)
|
|
41 #include <tgmath.h>
|
|
42 #endif
|
|
43 #if defined(HAVE_MATH_H)
|
|
44 #include <math.h>
|
|
45 #endif
|
|
46 #include <fcntl.h>
|
|
47 #include <string.h>
|
|
48 #include <audiofile.h>
|
|
49 #include <tiffio.h>
|
|
50
|
|
51 #include "spandsp.h"
|
|
52
|
|
53 #define OUTPUT_FILE_NAME "modem_connect_tones.wav"
|
|
54
|
|
55 #define BELLCORE_DIR "../itutests/bellcore/"
|
|
56
|
|
57 #define FALSE 0
|
|
58 #define TRUE (!FALSE)
|
|
59
|
|
60 const char *bellcore_files[] =
|
|
61 {
|
|
62 BELLCORE_DIR "tr-tsy-00763-1.wav",
|
|
63 BELLCORE_DIR "tr-tsy-00763-2.wav",
|
|
64 BELLCORE_DIR "tr-tsy-00763-3.wav",
|
|
65 BELLCORE_DIR "tr-tsy-00763-4.wav",
|
|
66 BELLCORE_DIR "tr-tsy-00763-5.wav",
|
|
67 BELLCORE_DIR "tr-tsy-00763-6.wav",
|
|
68 ""
|
|
69 };
|
|
70
|
|
71 int main(int argc, char *argv[])
|
|
72 {
|
|
73 int i;
|
|
74 int j;
|
|
75 int pitch;
|
|
76 int level;
|
|
77 int16_t amp[8000];
|
|
78 modem_connect_tones_rx_state_t cng_rx;
|
|
79 modem_connect_tones_rx_state_t ced_rx;
|
|
80 modem_connect_tones_rx_state_t ec_dis_rx;
|
|
81 modem_connect_tones_tx_state_t ec_dis_tx;
|
|
82 awgn_state_t chan_noise_source;
|
|
83 int hits;
|
|
84 AFfilehandle inhandle;
|
|
85 AFfilehandle outhandle;
|
|
86 AFfilesetup filesetup;
|
|
87 int outframes;
|
|
88 int frames;
|
|
89 int samples;
|
|
90 int hit;
|
|
91 int false_hit;
|
|
92 int false_miss;
|
|
93 float x;
|
|
94 tone_gen_descriptor_t tone_desc;
|
|
95 tone_gen_state_t tone_tx;
|
|
96
|
|
97 if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP)
|
|
98 {
|
|
99 fprintf(stderr, " Failed to create file setup\n");
|
|
100 exit(2);
|
|
101 }
|
|
102 afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
|
|
103 afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
|
|
104 afInitFileFormat(filesetup, AF_FILE_WAVE);
|
|
105 afInitChannels(filesetup, AF_DEFAULT_TRACK, 1);
|
|
106
|
|
107 if ((outhandle = afOpenFile(OUTPUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE)
|
|
108 {
|
|
109 fprintf(stderr, " Cannot create wave file '%s'\n", OUTPUT_FILE_NAME);
|
|
110 exit(2);
|
|
111 }
|
|
112
|
|
113 printf("Test 1a: CNG generation to a file\n");
|
|
114 modem_connect_tones_tx_init(&ec_dis_tx, MODEM_CONNECT_TONES_FAX_CNG);
|
|
115 for (i = 0; i < 1000; i++)
|
|
116 {
|
|
117 samples = modem_connect_tones_tx(&ec_dis_tx, amp, 160);
|
|
118 outframes = afWriteFrames(outhandle,
|
|
119 AF_DEFAULT_TRACK,
|
|
120 amp,
|
|
121 samples);
|
|
122 if (outframes != samples)
|
|
123 {
|
|
124 fprintf(stderr, " Error writing wave file\n");
|
|
125 exit(2);
|
|
126 }
|
|
127 }
|
|
128
|
|
129 printf("Test 1b: CED generation to a file\n");
|
|
130 modem_connect_tones_tx_init(&ec_dis_tx, MODEM_CONNECT_TONES_FAX_CED);
|
|
131 for (i = 0; i < 1000; i++)
|
|
132 {
|
|
133 samples = modem_connect_tones_tx(&ec_dis_tx, amp, 160);
|
|
134 outframes = afWriteFrames(outhandle,
|
|
135 AF_DEFAULT_TRACK,
|
|
136 amp,
|
|
137 samples);
|
|
138 if (outframes != samples)
|
|
139 {
|
|
140 fprintf(stderr, " Error writing wave file\n");
|
|
141 exit(2);
|
|
142 }
|
|
143 }
|
|
144
|
|
145 printf("Test 1c: Modulated EC-disable generation to a file\n");
|
|
146 /* Some with modulation */
|
|
147 modem_connect_tones_tx_init(&ec_dis_tx, MODEM_CONNECT_TONES_EC_DISABLE_MOD);
|
|
148 for (i = 0; i < 1000; i++)
|
|
149 {
|
|
150 samples = modem_connect_tones_tx(&ec_dis_tx, amp, 160);
|
|
151 outframes = afWriteFrames(outhandle,
|
|
152 AF_DEFAULT_TRACK,
|
|
153 amp,
|
|
154 samples);
|
|
155 if (outframes != samples)
|
|
156 {
|
|
157 fprintf(stderr, " Error writing wave file\n");
|
|
158 exit(2);
|
|
159 }
|
|
160 }
|
|
161
|
|
162 printf("Test 1d: EC-disable generation to a file\n");
|
|
163 /* Some without modulation */
|
|
164 modem_connect_tones_tx_init(&ec_dis_tx, MODEM_CONNECT_TONES_EC_DISABLE);
|
|
165 for (i = 0; i < 1000; i++)
|
|
166 {
|
|
167 samples = modem_connect_tones_tx(&ec_dis_tx, amp, 160);
|
|
168 outframes = afWriteFrames(outhandle,
|
|
169 AF_DEFAULT_TRACK,
|
|
170 amp,
|
|
171 samples);
|
|
172 if (outframes != samples)
|
|
173 {
|
|
174 fprintf(stderr, " Error writing wave file\n");
|
|
175 exit(2);
|
|
176 }
|
|
177 }
|
|
178 if (afCloseFile(outhandle) != 0)
|
|
179 {
|
|
180 printf(" Cannot close wave file '%s'\n", OUTPUT_FILE_NAME);
|
|
181 exit(2);
|
|
182 }
|
|
183
|
|
184 printf("Test 2a: CNG detection with frequency\n");
|
|
185 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f);
|
|
186 false_hit = FALSE;
|
|
187 false_miss = FALSE;
|
|
188 for (pitch = 600; pitch < 1600; pitch++)
|
|
189 {
|
|
190 make_tone_gen_descriptor(&tone_desc,
|
|
191 pitch,
|
|
192 -11,
|
|
193 0,
|
|
194 0,
|
|
195 425,
|
|
196 3000,
|
|
197 0,
|
|
198 0,
|
|
199 TRUE);
|
|
200 tone_gen_init(&tone_tx, &tone_desc);
|
|
201
|
|
202 modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL);
|
|
203 for (i = 0; i < 500; i++)
|
|
204 {
|
|
205 samples = tone_gen(&tone_tx, amp, 160);
|
|
206 for (j = 0; j < samples; j++)
|
|
207 amp[j] += awgn(&chan_noise_source);
|
|
208 /*endfor*/
|
|
209 modem_connect_tones_rx(&cng_rx, amp, samples);
|
|
210 }
|
|
211 hit = modem_connect_tones_rx_get(&cng_rx);
|
|
212 if (pitch < (1100 - 70) || pitch > (1100 + 70))
|
|
213 {
|
|
214 if (hit)
|
|
215 false_hit = TRUE;
|
|
216 }
|
|
217 else if (pitch > (1100 - 50) && pitch < (1100 + 50))
|
|
218 {
|
|
219 if (!hit)
|
|
220 false_miss = TRUE;
|
|
221 }
|
|
222 if (hit)
|
|
223 printf("Detected at %5dHz %12d %12d %d\n", pitch, cng_rx.channel_level, cng_rx.notch_level, hit);
|
|
224 }
|
|
225 if (false_hit || false_miss)
|
|
226 {
|
|
227 printf("Test failed.\n");
|
|
228 exit(2);
|
|
229 }
|
|
230
|
|
231 printf("Test 2b: CED detection with frequency\n");
|
|
232 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f);
|
|
233 false_hit = FALSE;
|
|
234 false_miss = FALSE;
|
|
235 for (pitch = 1600; pitch < 2600; pitch++)
|
|
236 {
|
|
237 make_tone_gen_descriptor(&tone_desc,
|
|
238 pitch,
|
|
239 -11,
|
|
240 0,
|
|
241 0,
|
|
242 2600,
|
|
243 0,
|
|
244 0,
|
|
245 0,
|
|
246 FALSE);
|
|
247 tone_gen_init(&tone_tx, &tone_desc);
|
|
248
|
|
249 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED, NULL, NULL);
|
|
250 for (i = 0; i < 500; i++)
|
|
251 {
|
|
252 samples = tone_gen(&tone_tx, amp, 160);
|
|
253 for (j = 0; j < samples; j++)
|
|
254 amp[j] += awgn(&chan_noise_source);
|
|
255 /*endfor*/
|
|
256 modem_connect_tones_rx(&ced_rx, amp, samples);
|
|
257 }
|
|
258 hit = modem_connect_tones_rx_get(&ced_rx);
|
|
259 if (pitch < (2100 - 70) || pitch > (2100 + 70))
|
|
260 {
|
|
261 if (hit)
|
|
262 false_hit = TRUE;
|
|
263 }
|
|
264 else if (pitch > (2100 - 50) && pitch < (2100 + 50))
|
|
265 {
|
|
266 if (!hit)
|
|
267 false_miss = TRUE;
|
|
268 }
|
|
269 if (hit)
|
|
270 printf("Detected at %5dHz %12d %12d %d\n", pitch, ced_rx.channel_level, ced_rx.notch_level, hit);
|
|
271 }
|
|
272 if (false_hit || false_miss)
|
|
273 {
|
|
274 printf("Test failed.\n");
|
|
275 exit(2);
|
|
276 }
|
|
277
|
|
278 printf("Test 2c: EC disable detection with frequency\n");
|
|
279 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f);
|
|
280 false_hit = FALSE;
|
|
281 false_miss = FALSE;
|
|
282 for (pitch = 2000; pitch < 2200; pitch++)
|
|
283 {
|
|
284 /* Use the transmitter to test the receiver */
|
|
285 modem_connect_tones_tx_init(&ec_dis_tx, MODEM_CONNECT_TONES_EC_DISABLE);
|
|
286 /* Fudge things for the test */
|
|
287 ec_dis_tx.tone_phase_rate = dds_phase_rate(pitch);
|
|
288 ec_dis_tx.level = dds_scaling_dbm0(-25);
|
|
289 modem_connect_tones_rx_init(&ec_dis_rx, MODEM_CONNECT_TONES_EC_DISABLE, NULL, NULL);
|
|
290 for (i = 0; i < 500; i++)
|
|
291 {
|
|
292 samples = modem_connect_tones_tx(&ec_dis_tx, amp, 160);
|
|
293 for (j = 0; j < samples; j++)
|
|
294 amp[j] += awgn(&chan_noise_source);
|
|
295 /*endfor*/
|
|
296 modem_connect_tones_rx(&ec_dis_rx, amp, samples);
|
|
297 }
|
|
298 hit = modem_connect_tones_rx_get(&ec_dis_rx);
|
|
299 if (pitch < (2100 - 70) || pitch > (2100 + 70))
|
|
300 {
|
|
301 if (hit)
|
|
302 false_hit = TRUE;
|
|
303 }
|
|
304 else if (pitch > (2100 - 50) && pitch < (2100 + 50))
|
|
305 {
|
|
306 if (!hit)
|
|
307 false_miss = TRUE;
|
|
308 }
|
|
309 if (hit)
|
|
310 printf("Detected at %5dHz %12d %12d %d\n", pitch, ec_dis_rx.channel_level, ec_dis_rx.notch_level, hit);
|
|
311 }
|
|
312 if (false_hit || false_miss)
|
|
313 {
|
|
314 printf("Test failed.\n");
|
|
315 exit(2);
|
|
316 }
|
|
317
|
|
318 printf("Test 3a: CNG detection with level\n");
|
|
319 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f);
|
|
320 false_hit = FALSE;
|
|
321 false_miss = FALSE;
|
|
322 for (pitch = 1062; pitch <= 1138; pitch += 2*38)
|
|
323 {
|
|
324 for (level = 0; level >= -43; level--)
|
|
325 {
|
|
326 make_tone_gen_descriptor(&tone_desc,
|
|
327 pitch,
|
|
328 level,
|
|
329 0,
|
|
330 0,
|
|
331 500,
|
|
332 3000,
|
|
333 0,
|
|
334 0,
|
|
335 TRUE);
|
|
336 tone_gen_init(&tone_tx, &tone_desc);
|
|
337
|
|
338 modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL);
|
|
339 for (i = 0; i < 500; i++)
|
|
340 {
|
|
341 samples = tone_gen(&tone_tx, amp, 160);
|
|
342 for (j = 0; j < samples; j++)
|
|
343 amp[j] += awgn(&chan_noise_source);
|
|
344 /*endfor*/
|
|
345 modem_connect_tones_rx(&cng_rx, amp, samples);
|
|
346 }
|
|
347 hit = modem_connect_tones_rx_get(&cng_rx);
|
|
348 if (level < -43)
|
|
349 {
|
|
350 if (hit)
|
|
351 false_hit = TRUE;
|
|
352 }
|
|
353 else if (level > -43)
|
|
354 {
|
|
355 if (!hit)
|
|
356 false_miss = TRUE;
|
|
357 }
|
|
358 if (hit)
|
|
359 printf("Detected at %5dHz %ddB %12d %12d %d\n", pitch, level, cng_rx.channel_level, cng_rx.notch_level, hit);
|
|
360 }
|
|
361 }
|
|
362 if (false_hit || false_miss)
|
|
363 {
|
|
364 printf("Test failed.\n");
|
|
365 exit(2);
|
|
366 }
|
|
367
|
|
368 printf("Test 3b: CED detection with level\n");
|
|
369 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f);
|
|
370 false_hit = FALSE;
|
|
371 false_miss = FALSE;
|
|
372 for (pitch = 2062; pitch <= 2138; pitch += 2*38)
|
|
373 {
|
|
374 for (level = 0; level >= -43; level--)
|
|
375 {
|
|
376 make_tone_gen_descriptor(&tone_desc,
|
|
377 pitch,
|
|
378 level,
|
|
379 0,
|
|
380 0,
|
|
381 2600,
|
|
382 0,
|
|
383 0,
|
|
384 0,
|
|
385 FALSE);
|
|
386 tone_gen_init(&tone_tx, &tone_desc);
|
|
387
|
|
388 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED, NULL, NULL);
|
|
389 for (i = 0; i < 500; i++)
|
|
390 {
|
|
391 samples = tone_gen(&tone_tx, amp, 160);
|
|
392 for (j = 0; j < samples; j++)
|
|
393 amp[j] += awgn(&chan_noise_source);
|
|
394 /*endfor*/
|
|
395 modem_connect_tones_rx(&ced_rx, amp, samples);
|
|
396 }
|
|
397 hit = modem_connect_tones_rx_get(&ced_rx);
|
|
398 if (level < -43)
|
|
399 {
|
|
400 if (hit)
|
|
401 false_hit = TRUE;
|
|
402 }
|
|
403 else if (level > -43)
|
|
404 {
|
|
405 if (!hit)
|
|
406 false_miss = TRUE;
|
|
407 }
|
|
408 if (hit)
|
|
409 printf("Detected at %5dHz %ddB %12d %12d %d\n", pitch, level, ced_rx.channel_level, ced_rx.notch_level, hit);
|
|
410 }
|
|
411 }
|
|
412 if (false_hit || false_miss)
|
|
413 {
|
|
414 printf("Test failed.\n");
|
|
415 exit(2);
|
|
416 }
|
|
417
|
|
418 /* Talk-off test */
|
|
419 /* Here we use the BellCore talk off test tapes, intended for DTMF detector
|
|
420 testing. Presumably they should also have value here, but I am not sure.
|
|
421 If those voice snippets were chosen to be tough on DTMF detectors, they
|
|
422 might go easy on detectors looking for different pitches. However, the
|
|
423 Mitel DTMF test tape is known (the hard way) to exercise 2280Hz tone
|
|
424 detectors quite well. */
|
|
425 printf("Test 2: Talk-off test\n");
|
|
426 modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL);
|
|
427 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED, NULL, NULL);
|
|
428 modem_connect_tones_rx_init(&ec_dis_rx, MODEM_CONNECT_TONES_EC_DISABLE, NULL, NULL);
|
|
429 hits = 0;
|
|
430 for (j = 0; bellcore_files[j][0]; j++)
|
|
431 {
|
|
432 if ((inhandle = afOpenFile(bellcore_files[j], "r", 0)) == AF_NULL_FILEHANDLE)
|
|
433 {
|
|
434 printf (" Cannot open speech file '%s'\n", bellcore_files[j]);
|
|
435 exit (2);
|
|
436 }
|
|
437 if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0)
|
|
438 {
|
|
439 printf (" Unexpected frame size in speech file '%s'\n", bellcore_files[j]);
|
|
440 exit (2);
|
|
441 }
|
|
442 if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE)
|
|
443 {
|
|
444 printf(" Unexpected sample rate in speech file '%s'\n", bellcore_files[j]);
|
|
445 exit(2);
|
|
446 }
|
|
447 if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0)
|
|
448 {
|
|
449 printf(" Unexpected number of channels in speech file '%s'\n", bellcore_files[j]);
|
|
450 exit(2);
|
|
451 }
|
|
452
|
|
453 hits = 0;
|
|
454 while ((frames = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, 8000)))
|
|
455 {
|
|
456 modem_connect_tones_rx(&cng_rx, amp, frames);
|
|
457 modem_connect_tones_rx(&ced_rx, amp, frames);
|
|
458 modem_connect_tones_rx(&ec_dis_rx, amp, frames);
|
|
459 if (modem_connect_tones_rx_get(&cng_rx))
|
|
460 {
|
|
461 /* This is not a true measure of hits, as there might be more
|
|
462 than one in a block of data. However, since the only good
|
|
463 result is no hits, this approximation is OK. */
|
|
464 hits++;
|
|
465 modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL);
|
|
466 }
|
|
467 if (modem_connect_tones_rx_get(&ced_rx))
|
|
468 {
|
|
469 hits++;
|
|
470 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED, NULL, NULL);
|
|
471 }
|
|
472 if (modem_connect_tones_rx_get(&ec_dis_rx))
|
|
473 {
|
|
474 hits++;
|
|
475 modem_connect_tones_rx_init(&ec_dis_rx, MODEM_CONNECT_TONES_EC_DISABLE, NULL, NULL);
|
|
476 }
|
|
477 }
|
|
478 if (afCloseFile(inhandle) != 0)
|
|
479 {
|
|
480 printf(" Cannot close speech file '%s'\n", bellcore_files[j]);
|
|
481 exit(2);
|
|
482 }
|
|
483 printf(" File %d gave %d false hits.\n", j + 1, hits);
|
|
484 }
|
|
485 if (hits)
|
|
486 {
|
|
487 printf("Test failed.\n");
|
|
488 exit(2);
|
|
489 }
|
|
490
|
|
491 printf("Tests passed.\n");
|
|
492 return 0;
|
|
493 }
|
|
494 /*- End of function --------------------------------------------------------*/
|
|
495 /*- End of file ------------------------------------------------------------*/
|