Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/tests/modem_connect_tones_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 * 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.32 2009/11/02 15:04:15 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 /* Enable the following definition to enable direct probing into the FAX structures */ | |
34 //#define WITH_SPANDSP_INTERNALS | |
35 | |
36 #if defined(HAVE_CONFIG_H) | |
37 #include "config.h" | |
38 #endif | |
39 | |
40 #include <stdlib.h> | |
41 #include <stdio.h> | |
42 #include <fcntl.h> | |
43 #include <unistd.h> | |
44 #include <string.h> | |
45 #include <sndfile.h> | |
46 | |
47 //#if defined(WITH_SPANDSP_INTERNALS) | |
48 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES | |
49 //#endif | |
50 | |
51 #include "spandsp.h" | |
52 #include "spandsp-sim.h" | |
53 | |
54 #define SAMPLES_PER_CHUNK 160 | |
55 | |
56 #define OUTPUT_FILE_NAME "modem_connect_tones.wav" | |
57 | |
58 #define MITEL_DIR "../test-data/mitel/" | |
59 #define BELLCORE_DIR "../test-data/bellcore/" | |
60 | |
61 #define FALSE 0 | |
62 #define TRUE (!FALSE) | |
63 | |
64 #define LEVEL_MAX -5 | |
65 #define LEVEL_MIN -48 | |
66 #define LEVEL_MIN_ACCEPT -43 | |
67 #define LEVEL_MIN_REJECT -44 | |
68 | |
69 /* The 1100Hz tone is supposed to be within 38Hz, according to T.30. Allow another 8Hz for FDM, even though | |
70 you rarely see that used today. */ | |
71 #define CED_FREQ_TOLERANCE (38 + 8) | |
72 #define CED_FREQ_BLACKOUT (80) | |
73 /* The 2100Hz tone is supposed to be within 15Hz, according to T.30. Allow another 8Hz for FDM, even though | |
74 you rarely see that used today. */ | |
75 #define CNG_FREQ_TOLERANCE (15 + 8) | |
76 #define CNG_FREQ_BLACKOUT (80) | |
77 #define AM_FREQ_TOLERANCE (1) | |
78 | |
79 const char *bellcore_files[] = | |
80 { | |
81 MITEL_DIR "mitel-cm7291-talkoff.wav", | |
82 BELLCORE_DIR "tr-tsy-00763-1.wav", | |
83 BELLCORE_DIR "tr-tsy-00763-2.wav", | |
84 BELLCORE_DIR "tr-tsy-00763-3.wav", | |
85 BELLCORE_DIR "tr-tsy-00763-4.wav", | |
86 BELLCORE_DIR "tr-tsy-00763-5.wav", | |
87 BELLCORE_DIR "tr-tsy-00763-6.wav", | |
88 "" | |
89 }; | |
90 | |
91 enum | |
92 { | |
93 PERFORM_TEST_1A = (1 << 1), | |
94 PERFORM_TEST_1B = (1 << 2), | |
95 PERFORM_TEST_1C = (1 << 3), | |
96 PERFORM_TEST_1D = (1 << 4), | |
97 PERFORM_TEST_1E = (1 << 5), | |
98 PERFORM_TEST_2A = (1 << 6), | |
99 PERFORM_TEST_2B = (1 << 7), | |
100 PERFORM_TEST_2C = (1 << 8), | |
101 PERFORM_TEST_2D = (1 << 9), | |
102 PERFORM_TEST_2E = (1 << 10), | |
103 PERFORM_TEST_3A = (1 << 11), | |
104 PERFORM_TEST_3B = (1 << 12), | |
105 PERFORM_TEST_3C = (1 << 13), | |
106 PERFORM_TEST_3D = (1 << 14), | |
107 PERFORM_TEST_3E = (1 << 15), | |
108 PERFORM_TEST_4 = (1 << 16), | |
109 PERFORM_TEST_5A = (1 << 17), | |
110 PERFORM_TEST_5B = (1 << 18), | |
111 PERFORM_TEST_6A = (1 << 19), | |
112 PERFORM_TEST_6B = (1 << 20), | |
113 PERFORM_TEST_7A = (1 << 21), | |
114 PERFORM_TEST_7B = (1 << 22), | |
115 PERFORM_TEST_8 = (1 << 23) | |
116 }; | |
117 | |
118 int preamble_count = 0; | |
119 int preamble_on_at = -1; | |
120 int preamble_off_at = -1; | |
121 int hits = 0; | |
122 int when = 0; | |
123 | |
124 static int preamble_get_bit(void *user_data) | |
125 { | |
126 static int bit_no = 0; | |
127 int bit; | |
128 | |
129 /* Generate a section of HDLC flag octet preamble. Then generate some random | |
130 bits, which should not look like preamble. */ | |
131 if (++preamble_count < 255) | |
132 { | |
133 bit = (bit_no < 2) ? 0 : 1; | |
134 if (++bit_no >= 8) | |
135 bit_no = 0; | |
136 #if 0 | |
137 /* Inject some bad bits */ | |
138 if (rand()%15 == 0) | |
139 return bit ^ 1; | |
140 #endif | |
141 } | |
142 else | |
143 { | |
144 bit = rand() & 1; | |
145 } | |
146 return bit; | |
147 } | |
148 /*- End of function --------------------------------------------------------*/ | |
149 | |
150 static void cng_detected(void *user_data, int tone, int level, int delay) | |
151 { | |
152 printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); | |
153 if (tone == MODEM_CONNECT_TONES_FAX_CNG) | |
154 hits++; | |
155 } | |
156 /*- End of function --------------------------------------------------------*/ | |
157 | |
158 static void preamble_detected(void *user_data, int tone, int level, int delay) | |
159 { | |
160 printf("%s (%d) declared at bit %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, preamble_count, level); | |
161 if (tone == MODEM_CONNECT_TONES_FAX_PREAMBLE) | |
162 preamble_on_at = preamble_count; | |
163 else | |
164 preamble_off_at = preamble_count; | |
165 /*endif*/ | |
166 } | |
167 /*- End of function --------------------------------------------------------*/ | |
168 | |
169 static void ced_detected(void *user_data, int tone, int level, int delay) | |
170 { | |
171 printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); | |
172 if (tone == MODEM_CONNECT_TONES_FAX_PREAMBLE | |
173 || | |
174 tone == MODEM_CONNECT_TONES_ANS) | |
175 { | |
176 hits++; | |
177 } | |
178 } | |
179 /*- End of function --------------------------------------------------------*/ | |
180 | |
181 static void ans_pr_detected(void *user_data, int tone, int level, int delay) | |
182 { | |
183 printf("%s (%d) declared at %fs, delay %d (%ddBm0)\n", modem_connect_tone_to_str(tone), tone, (float) when/SAMPLE_RATE, delay, level); | |
184 if (tone == MODEM_CONNECT_TONES_ANS_PR) | |
185 hits++; | |
186 } | |
187 /*- End of function --------------------------------------------------------*/ | |
188 | |
189 int main(int argc, char *argv[]) | |
190 { | |
191 int i; | |
192 int j; | |
193 int pitch; | |
194 int depth; | |
195 int level; | |
196 int interval; | |
197 int cycle; | |
198 int16_t amp[8000]; | |
199 modem_connect_tones_rx_state_t cng_rx; | |
200 modem_connect_tones_rx_state_t ced_rx; | |
201 modem_connect_tones_rx_state_t ans_pr_rx; | |
202 modem_connect_tones_tx_state_t modem_tone_tx; | |
203 awgn_state_t chan_noise_source; | |
204 SNDFILE *inhandle; | |
205 SNDFILE *outhandle; | |
206 int outframes; | |
207 int frames; | |
208 int samples; | |
209 int hit; | |
210 int false_hit; | |
211 int false_miss; | |
212 power_meter_t power_state; | |
213 int power; | |
214 int max_power; | |
215 int level2; | |
216 int max_level2; | |
217 int tone_type; | |
218 int test_list; | |
219 int opt; | |
220 char *decode_test_file; | |
221 fsk_tx_state_t preamble_tx; | |
222 | |
223 test_list = 0; | |
224 decode_test_file = NULL; | |
225 while ((opt = getopt(argc, argv, "d:")) != -1) | |
226 { | |
227 switch (opt) | |
228 { | |
229 case 'd': | |
230 decode_test_file = optarg; | |
231 break; | |
232 default: | |
233 //usage(); | |
234 exit(2); | |
235 break; | |
236 } | |
237 } | |
238 argc -= optind; | |
239 argv += optind; | |
240 for (i = 0; i < argc; i++) | |
241 { | |
242 if (strcasecmp(argv[i], "1a") == 0) | |
243 test_list |= PERFORM_TEST_1A; | |
244 else if (strcasecmp(argv[i], "1b") == 0) | |
245 test_list |= PERFORM_TEST_1B; | |
246 else if (strcasecmp(argv[i], "1c") == 0) | |
247 test_list |= PERFORM_TEST_1C; | |
248 else if (strcasecmp(argv[i], "1d") == 0) | |
249 test_list |= PERFORM_TEST_1D; | |
250 else if (strcasecmp(argv[i], "1e") == 0) | |
251 test_list |= PERFORM_TEST_1E; | |
252 else if (strcasecmp(argv[i], "2a") == 0) | |
253 test_list |= PERFORM_TEST_2A; | |
254 else if (strcasecmp(argv[i], "2b") == 0) | |
255 test_list |= PERFORM_TEST_2B; | |
256 else if (strcasecmp(argv[i], "2c") == 0) | |
257 test_list |= PERFORM_TEST_2C; | |
258 else if (strcasecmp(argv[i], "2d") == 0) | |
259 test_list |= PERFORM_TEST_2D; | |
260 else if (strcasecmp(argv[i], "2e") == 0) | |
261 test_list |= PERFORM_TEST_2E; | |
262 else if (strcasecmp(argv[i], "3a") == 0) | |
263 test_list |= PERFORM_TEST_3A; | |
264 else if (strcasecmp(argv[i], "3b") == 0) | |
265 test_list |= PERFORM_TEST_3B; | |
266 else if (strcasecmp(argv[i], "3c") == 0) | |
267 test_list |= PERFORM_TEST_3C; | |
268 else if (strcasecmp(argv[i], "3d") == 0) | |
269 test_list |= PERFORM_TEST_3D; | |
270 else if (strcasecmp(argv[i], "3e") == 0) | |
271 test_list |= PERFORM_TEST_3E; | |
272 else if (strcasecmp(argv[i], "4") == 0) | |
273 test_list |= PERFORM_TEST_4; | |
274 else if (strcasecmp(argv[i], "5a") == 0) | |
275 test_list |= PERFORM_TEST_5A; | |
276 else if (strcasecmp(argv[i], "5b") == 0) | |
277 test_list |= PERFORM_TEST_5B; | |
278 else if (strcasecmp(argv[i], "6a") == 0) | |
279 test_list |= PERFORM_TEST_6A; | |
280 else if (strcasecmp(argv[i], "6b") == 0) | |
281 test_list |= PERFORM_TEST_6B; | |
282 else if (strcasecmp(argv[i], "7a") == 0) | |
283 test_list |= PERFORM_TEST_7A; | |
284 else if (strcasecmp(argv[i], "7b") == 0) | |
285 test_list |= PERFORM_TEST_7B; | |
286 else if (strcasecmp(argv[i], "8") == 0) | |
287 test_list |= PERFORM_TEST_8; | |
288 else | |
289 { | |
290 fprintf(stderr, "Unknown test '%s' specified\n", argv[i]); | |
291 exit(2); | |
292 } | |
293 } | |
294 if (decode_test_file == NULL && test_list == 0) | |
295 test_list = 0xFFFFFFFF; | |
296 | |
297 if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) | |
298 { | |
299 fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME); | |
300 exit(2); | |
301 } | |
302 | |
303 if ((test_list & PERFORM_TEST_1A)) | |
304 { | |
305 printf("Test 1a: CNG generation to a file\n"); | |
306 modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_FAX_CNG); | |
307 for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
308 { | |
309 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
310 outframes = sf_writef_short(outhandle, amp, samples); | |
311 if (outframes != samples) | |
312 { | |
313 fprintf(stderr, " Error writing audio file\n"); | |
314 exit(2); | |
315 } | |
316 /*endif*/ | |
317 } | |
318 /*endfor*/ | |
319 } | |
320 /*endif*/ | |
321 | |
322 if ((test_list & PERFORM_TEST_1B)) | |
323 { | |
324 printf("Test 1b: CED/ANS generation to a file\n"); | |
325 modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_FAX_CED); | |
326 for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
327 { | |
328 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
329 outframes = sf_writef_short(outhandle, amp, samples); | |
330 if (outframes != samples) | |
331 { | |
332 fprintf(stderr, " Error writing audio file\n"); | |
333 exit(2); | |
334 } | |
335 /*endif*/ | |
336 } | |
337 /*endfor*/ | |
338 } | |
339 /*endif*/ | |
340 | |
341 if ((test_list & PERFORM_TEST_1C)) | |
342 { | |
343 printf("Test 1c: ANSam (Modulated ANS) generation to a file\n"); | |
344 /* Some with modulation */ | |
345 modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANSAM); | |
346 for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
347 { | |
348 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
349 outframes = sf_writef_short(outhandle, amp, samples); | |
350 if (outframes != samples) | |
351 { | |
352 fprintf(stderr, " Error writing audio file\n"); | |
353 exit(2); | |
354 } | |
355 /*endif*/ | |
356 } | |
357 /*endfor*/ | |
358 } | |
359 /*endif*/ | |
360 | |
361 if ((test_list & PERFORM_TEST_1D)) | |
362 { | |
363 printf("Test 1d: ANS/ (EC-disable) generation to a file\n"); | |
364 /* Some without modulation, but with phase reversals */ | |
365 modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS_PR); | |
366 for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
367 { | |
368 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
369 outframes = sf_writef_short(outhandle, amp, samples); | |
370 if (outframes != samples) | |
371 { | |
372 fprintf(stderr, " Error writing audio file\n"); | |
373 exit(2); | |
374 } | |
375 /*endif*/ | |
376 } | |
377 /*endfor*/ | |
378 } | |
379 /*endif*/ | |
380 | |
381 if ((test_list & PERFORM_TEST_1E)) | |
382 { | |
383 printf("Test 1e: ANSam/ (Modulated EC-disable) generation to a file\n"); | |
384 /* Some with modulation and phase reversals */ | |
385 modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANSAM_PR); | |
386 for (i = 0; i < 20*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
387 { | |
388 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
389 outframes = sf_writef_short(outhandle, amp, samples); | |
390 if (outframes != samples) | |
391 { | |
392 fprintf(stderr, " Error writing audio file\n"); | |
393 exit(2); | |
394 } | |
395 /*endif*/ | |
396 } | |
397 /*endfor*/ | |
398 } | |
399 /*endif*/ | |
400 | |
401 if (sf_close(outhandle) != 0) | |
402 { | |
403 printf(" Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); | |
404 exit(2); | |
405 } | |
406 /*endif*/ | |
407 | |
408 if ((test_list & PERFORM_TEST_2A)) | |
409 { | |
410 printf("Test 2a: CNG detection with frequency\n"); | |
411 tone_type = MODEM_CONNECT_TONES_FAX_CNG; | |
412 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
413 false_hit = FALSE; | |
414 false_miss = FALSE; | |
415 for (pitch = 600; pitch <= 1600; pitch++) | |
416 { | |
417 /* Use the transmitter to test the receiver */ | |
418 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
419 /* Fudge things for the test */ | |
420 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
421 modem_connect_tones_rx_init(&cng_rx, tone_type, NULL, NULL); | |
422 power_meter_init(&power_state, 5); | |
423 power = 0; | |
424 max_power = 0; | |
425 level2 = 0; | |
426 max_level2 = 0; | |
427 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
428 { | |
429 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
430 for (j = 0; j < samples; j++) | |
431 { | |
432 amp[j] += awgn(&chan_noise_source); | |
433 power = power_meter_update(&power_state, amp[j]); | |
434 if (power > max_power) | |
435 max_power = power; | |
436 /*endif*/ | |
437 level2 += ((abs(amp[j]) - level2) >> 5); | |
438 if (level2 > max_level2) | |
439 max_level2 = level2; | |
440 } | |
441 /*endfor*/ | |
442 modem_connect_tones_rx(&cng_rx, amp, samples); | |
443 } | |
444 /*endfor*/ | |
445 hit = modem_connect_tones_rx_get(&cng_rx); | |
446 if (pitch < (1100 - CED_FREQ_BLACKOUT) || pitch > (1100 + CED_FREQ_BLACKOUT)) | |
447 { | |
448 if (hit != MODEM_CONNECT_TONES_NONE) | |
449 false_hit = TRUE; | |
450 /*endif*/ | |
451 } | |
452 else if (pitch > (1100 - CED_FREQ_TOLERANCE) && pitch < (1100 + CED_FREQ_TOLERANCE)) | |
453 { | |
454 if (hit != tone_type) | |
455 false_miss = TRUE; | |
456 /*endif*/ | |
457 } | |
458 /*endif*/ | |
459 if (hit != MODEM_CONNECT_TONES_NONE) | |
460 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, cng_rx.channel_level, cng_rx.notch_level, hit); | |
461 /*endif*/ | |
462 } | |
463 /*endfor*/ | |
464 if (false_hit || false_miss) | |
465 { | |
466 printf("Test failed.\n"); | |
467 exit(2); | |
468 } | |
469 /*endif*/ | |
470 printf("Test passed.\n"); | |
471 } | |
472 /*endif*/ | |
473 | |
474 if ((test_list & PERFORM_TEST_2B)) | |
475 { | |
476 printf("Test 2b: CED/ANS detection with frequency\n"); | |
477 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
478 false_hit = FALSE; | |
479 false_miss = FALSE; | |
480 for (pitch = 1600; pitch < 2600; pitch++) | |
481 { | |
482 /* Use the transmitter to test the receiver */ | |
483 modem_connect_tones_tx_init(&modem_tone_tx, MODEM_CONNECT_TONES_ANS); | |
484 /* Fudge things for the test */ | |
485 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
486 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); | |
487 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
488 { | |
489 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
490 for (j = 0; j < samples; j++) | |
491 amp[j] += awgn(&chan_noise_source); | |
492 /*endfor*/ | |
493 modem_connect_tones_rx(&ced_rx, amp, samples); | |
494 } | |
495 /*endfor*/ | |
496 hit = modem_connect_tones_rx_get(&ced_rx); | |
497 if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) | |
498 { | |
499 if (hit != MODEM_CONNECT_TONES_NONE) | |
500 false_hit = TRUE; | |
501 /*endif*/ | |
502 } | |
503 else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) | |
504 { | |
505 if (hit != MODEM_CONNECT_TONES_FAX_CED) | |
506 false_miss = TRUE; | |
507 /*endif*/ | |
508 } | |
509 /*endif*/ | |
510 if (hit != MODEM_CONNECT_TONES_NONE) | |
511 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ced_rx.channel_level, ced_rx.notch_level, hit); | |
512 /*endif*/ | |
513 } | |
514 if (false_hit || false_miss) | |
515 { | |
516 printf("Test failed.\n"); | |
517 exit(2); | |
518 } | |
519 /*endif*/ | |
520 printf("Test passed.\n"); | |
521 } | |
522 /*endif*/ | |
523 | |
524 if ((test_list & PERFORM_TEST_2C)) | |
525 { | |
526 printf("Test 2c: ANSam detection with frequency\n"); | |
527 tone_type = MODEM_CONNECT_TONES_ANSAM; | |
528 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
529 false_hit = FALSE; | |
530 false_miss = FALSE; | |
531 for (pitch = 2000; pitch <= 2200; pitch++) | |
532 { | |
533 /* Use the transmitter to test the receiver */ | |
534 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
535 /* Fudge things for the test */ | |
536 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
537 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
538 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
539 { | |
540 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
541 for (j = 0; j < samples; j++) | |
542 amp[j] += awgn(&chan_noise_source); | |
543 /*endfor*/ | |
544 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
545 } | |
546 /*endfor*/ | |
547 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
548 if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) | |
549 { | |
550 if (hit != MODEM_CONNECT_TONES_NONE) | |
551 false_hit = TRUE; | |
552 /*endif*/ | |
553 } | |
554 else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) | |
555 { | |
556 if (hit != tone_type) | |
557 false_miss = TRUE; | |
558 /*endif*/ | |
559 } | |
560 /*endif*/ | |
561 if (hit != MODEM_CONNECT_TONES_NONE) | |
562 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
563 /*endif*/ | |
564 } | |
565 /*endfor*/ | |
566 if (false_hit || false_miss) | |
567 { | |
568 printf("Test failed.\n"); | |
569 exit(2); | |
570 } | |
571 /*endif*/ | |
572 printf("Test passed.\n"); | |
573 } | |
574 /*endif*/ | |
575 | |
576 if ((test_list & PERFORM_TEST_2D)) | |
577 { | |
578 printf("Test 2d: ANS/ (EC-disable) detection with frequency\n"); | |
579 tone_type = MODEM_CONNECT_TONES_ANS_PR; | |
580 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
581 false_hit = FALSE; | |
582 false_miss = FALSE; | |
583 for (pitch = 2000; pitch <= 2200; pitch++) | |
584 { | |
585 /* Use the transmitter to test the receiver */ | |
586 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
587 /* Fudge things for the test */ | |
588 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
589 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
590 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
591 { | |
592 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
593 for (j = 0; j < samples; j++) | |
594 amp[j] += awgn(&chan_noise_source); | |
595 /*endfor*/ | |
596 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
597 } | |
598 /*endfor*/ | |
599 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
600 if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) | |
601 { | |
602 if (hit != MODEM_CONNECT_TONES_NONE) | |
603 false_hit = TRUE; | |
604 /*endif*/ | |
605 } | |
606 else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) | |
607 { | |
608 if (hit != tone_type) | |
609 false_miss = TRUE; | |
610 /*endif*/ | |
611 } | |
612 /*endif*/ | |
613 if (hit != MODEM_CONNECT_TONES_NONE) | |
614 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
615 /*endif*/ | |
616 } | |
617 /*endfor*/ | |
618 if (false_hit || false_miss) | |
619 { | |
620 printf("Test failed.\n"); | |
621 exit(2); | |
622 } | |
623 /*endif*/ | |
624 printf("Test passed.\n"); | |
625 } | |
626 /*endif*/ | |
627 | |
628 if ((test_list & PERFORM_TEST_2E)) | |
629 { | |
630 printf("Test 2e: ANSam/ (Modulated EC-disable) detection with frequency\n"); | |
631 tone_type = MODEM_CONNECT_TONES_ANSAM_PR; | |
632 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
633 false_hit = FALSE; | |
634 false_miss = FALSE; | |
635 for (pitch = 2000; pitch <= 2200; pitch++) | |
636 { | |
637 /* Use the transmitter to test the receiver */ | |
638 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
639 /* Fudge things for the test */ | |
640 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
641 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
642 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
643 { | |
644 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
645 for (j = 0; j < samples; j++) | |
646 amp[j] += awgn(&chan_noise_source); | |
647 /*endfor*/ | |
648 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
649 } | |
650 /*endfor*/ | |
651 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
652 if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) | |
653 { | |
654 if (hit != MODEM_CONNECT_TONES_NONE) | |
655 false_hit = TRUE; | |
656 /*endif*/ | |
657 } | |
658 else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) | |
659 { | |
660 if (hit != tone_type) | |
661 false_miss = TRUE; | |
662 /*endif*/ | |
663 } | |
664 /*endif*/ | |
665 if (hit != MODEM_CONNECT_TONES_NONE) | |
666 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
667 /*endif*/ | |
668 } | |
669 /*endfor*/ | |
670 if (false_hit || false_miss) | |
671 { | |
672 printf("Test failed.\n"); | |
673 exit(2); | |
674 } | |
675 /*endif*/ | |
676 printf("Test passed.\n"); | |
677 } | |
678 /*endif*/ | |
679 | |
680 if ((test_list & PERFORM_TEST_3A)) | |
681 { | |
682 printf("Test 3a: CNG detection with level\n"); | |
683 tone_type = MODEM_CONNECT_TONES_FAX_CNG; | |
684 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); | |
685 false_hit = FALSE; | |
686 false_miss = FALSE; | |
687 for (pitch = 1100 - CED_FREQ_TOLERANCE; pitch <= 1100 + CED_FREQ_TOLERANCE; pitch += 2*CED_FREQ_TOLERANCE) | |
688 { | |
689 for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) | |
690 { | |
691 /* Use the transmitter to test the receiver */ | |
692 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
693 /* Fudge things for the test */ | |
694 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
695 modem_tone_tx.level = dds_scaling_dbm0(level); | |
696 modem_connect_tones_rx_init(&cng_rx, tone_type, NULL, NULL); | |
697 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
698 { | |
699 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
700 for (j = 0; j < samples; j++) | |
701 amp[j] += awgn(&chan_noise_source); | |
702 /*endfor*/ | |
703 modem_connect_tones_rx(&cng_rx, amp, samples); | |
704 } | |
705 /*endfor*/ | |
706 hit = modem_connect_tones_rx_get(&cng_rx); | |
707 if (level < LEVEL_MIN_REJECT) | |
708 { | |
709 if (hit != MODEM_CONNECT_TONES_NONE) | |
710 false_hit = TRUE; | |
711 /*endif*/ | |
712 } | |
713 else if (level > LEVEL_MIN_ACCEPT) | |
714 { | |
715 if (hit != tone_type) | |
716 false_miss = TRUE; | |
717 /*endif*/ | |
718 } | |
719 /*endif*/ | |
720 if (hit != MODEM_CONNECT_TONES_NONE) | |
721 printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, cng_rx.channel_level, cng_rx.notch_level, hit); | |
722 /*endif*/ | |
723 } | |
724 /*endfor*/ | |
725 } | |
726 /*endfor*/ | |
727 if (false_hit || false_miss) | |
728 { | |
729 printf("Test failed.\n"); | |
730 exit(2); | |
731 } | |
732 /*endif*/ | |
733 printf("Test passed.\n"); | |
734 } | |
735 /*endif*/ | |
736 | |
737 if ((test_list & PERFORM_TEST_3B)) | |
738 { | |
739 printf("Test 3b: CED/ANS detection with level\n"); | |
740 tone_type = MODEM_CONNECT_TONES_ANS; | |
741 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); | |
742 false_hit = FALSE; | |
743 false_miss = FALSE; | |
744 for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) | |
745 { | |
746 for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) | |
747 { | |
748 /* Use the transmitter to test the receiver */ | |
749 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
750 /* Fudge things for the test */ | |
751 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
752 modem_tone_tx.level = dds_scaling_dbm0(level); | |
753 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); | |
754 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
755 { | |
756 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
757 for (j = 0; j < samples; j++) | |
758 amp[j] += awgn(&chan_noise_source); | |
759 /*endfor*/ | |
760 modem_connect_tones_rx(&ced_rx, amp, samples); | |
761 } | |
762 /*endfor*/ | |
763 hit = modem_connect_tones_rx_get(&ced_rx); | |
764 if (level < LEVEL_MIN_REJECT) | |
765 { | |
766 if (hit != MODEM_CONNECT_TONES_NONE) | |
767 false_hit = TRUE; | |
768 /*endif*/ | |
769 } | |
770 else if (level > LEVEL_MIN_ACCEPT) | |
771 { | |
772 if (hit != tone_type) | |
773 false_miss = TRUE; | |
774 /*endif*/ | |
775 } | |
776 /*endif*/ | |
777 if (hit != MODEM_CONNECT_TONES_NONE) | |
778 printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ced_rx.channel_level, ced_rx.notch_level, hit); | |
779 /*endif*/ | |
780 } | |
781 /*endfor*/ | |
782 } | |
783 /*endfor*/ | |
784 if (false_hit || false_miss) | |
785 { | |
786 printf("Test failed.\n"); | |
787 exit(2); | |
788 } | |
789 /*endif*/ | |
790 printf("Test passed.\n"); | |
791 } | |
792 /*endif*/ | |
793 | |
794 if ((test_list & PERFORM_TEST_3C)) | |
795 { | |
796 printf("Test 3c: ANSam detection with level\n"); | |
797 tone_type = MODEM_CONNECT_TONES_ANSAM; | |
798 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); | |
799 false_hit = FALSE; | |
800 false_miss = FALSE; | |
801 for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) | |
802 { | |
803 //for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) | |
804 for (level = -26; level >= -26; level--) | |
805 { | |
806 /* Use the transmitter to test the receiver */ | |
807 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
808 /* Fudge things for the test */ | |
809 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
810 modem_tone_tx.level = dds_scaling_dbm0(level); | |
811 modem_tone_tx.mod_level = modem_tone_tx.level*20/100; | |
812 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
813 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
814 { | |
815 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
816 for (j = 0; j < samples; j++) | |
817 amp[j] += awgn(&chan_noise_source); | |
818 /*endfor*/ | |
819 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
820 } | |
821 /*endfor*/ | |
822 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
823 if (level < LEVEL_MIN_REJECT) | |
824 { | |
825 if (hit != MODEM_CONNECT_TONES_NONE) | |
826 false_hit = TRUE; | |
827 /*endif*/ | |
828 } | |
829 else if (level > LEVEL_MIN_ACCEPT) | |
830 { | |
831 if (hit != tone_type) | |
832 false_miss = TRUE; | |
833 /*endif*/ | |
834 } | |
835 /*endif*/ | |
836 //if (hit != MODEM_CONNECT_TONES_NONE) | |
837 printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
838 /*endif*/ | |
839 } | |
840 /*endfor*/ | |
841 } | |
842 /*endfor*/ | |
843 if (false_hit || false_miss) | |
844 { | |
845 printf("Test failed.\n"); | |
846 exit(2); | |
847 } | |
848 /*endif*/ | |
849 printf("Test passed.\n"); | |
850 } | |
851 /*endif*/ | |
852 | |
853 if ((test_list & PERFORM_TEST_3D)) | |
854 { | |
855 printf("Test 3d: ANS/ (EC-disable) detection with level\n"); | |
856 tone_type = MODEM_CONNECT_TONES_ANS_PR; | |
857 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); | |
858 false_hit = FALSE; | |
859 false_miss = FALSE; | |
860 for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) | |
861 { | |
862 for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) | |
863 { | |
864 /* Use the transmitter to test the receiver */ | |
865 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
866 /* Fudge things for the test */ | |
867 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
868 modem_tone_tx.level = dds_scaling_dbm0(level); | |
869 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
870 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
871 { | |
872 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
873 for (j = 0; j < samples; j++) | |
874 amp[j] += awgn(&chan_noise_source); | |
875 /*endfor*/ | |
876 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
877 } | |
878 /*endfor*/ | |
879 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
880 if (level < LEVEL_MIN_REJECT) | |
881 { | |
882 if (hit != MODEM_CONNECT_TONES_NONE) | |
883 false_hit = TRUE; | |
884 /*endif*/ | |
885 } | |
886 else if (level > LEVEL_MIN_ACCEPT) | |
887 { | |
888 if (hit != tone_type) | |
889 false_miss = TRUE; | |
890 /*endif*/ | |
891 } | |
892 /*endif*/ | |
893 if (hit != MODEM_CONNECT_TONES_NONE) | |
894 printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
895 /*endif*/ | |
896 } | |
897 /*endfor*/ | |
898 } | |
899 /*endfor*/ | |
900 if (false_hit || false_miss) | |
901 { | |
902 printf("Test failed.\n"); | |
903 exit(2); | |
904 } | |
905 /*endif*/ | |
906 printf("Test passed.\n"); | |
907 } | |
908 /*endif*/ | |
909 | |
910 if ((test_list & PERFORM_TEST_3E)) | |
911 { | |
912 printf("Test 3e: ANSam/ (Modulated EC-disable) detection with level\n"); | |
913 tone_type = MODEM_CONNECT_TONES_ANSAM_PR; | |
914 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); | |
915 false_hit = FALSE; | |
916 false_miss = FALSE; | |
917 for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) | |
918 { | |
919 for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) | |
920 { | |
921 /* Use the transmitter to test the receiver */ | |
922 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
923 /* Fudge things for the test */ | |
924 modem_tone_tx.tone_phase_rate = dds_phase_rate(pitch); | |
925 modem_tone_tx.level = dds_scaling_dbm0(level); | |
926 modem_tone_tx.mod_level = modem_tone_tx.level*20/100; | |
927 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
928 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
929 { | |
930 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
931 for (j = 0; j < samples; j++) | |
932 amp[j] += awgn(&chan_noise_source); | |
933 /*endfor*/ | |
934 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
935 } | |
936 /*endfor*/ | |
937 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
938 if (level < LEVEL_MIN_REJECT) | |
939 { | |
940 if (hit != MODEM_CONNECT_TONES_NONE) | |
941 false_hit = TRUE; | |
942 /*endif*/ | |
943 } | |
944 else if (level > LEVEL_MIN_ACCEPT) | |
945 { | |
946 if (hit != tone_type) | |
947 false_miss = TRUE; | |
948 /*endif*/ | |
949 } | |
950 /*endif*/ | |
951 if (hit != MODEM_CONNECT_TONES_NONE) | |
952 printf("Detected at %5dHz %4ddB %12" PRId32 " %12" PRId32 " %d\n", pitch, level, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
953 /*endif*/ | |
954 } | |
955 /*endfor*/ | |
956 } | |
957 /*endfor*/ | |
958 if (false_hit || false_miss) | |
959 { | |
960 printf("Test failed.\n"); | |
961 exit(2); | |
962 } | |
963 /*endif*/ | |
964 printf("Test passed.\n"); | |
965 } | |
966 /*endif*/ | |
967 | |
968 if ((test_list & PERFORM_TEST_4)) | |
969 { | |
970 printf("Test 4: CED detection, when stimulated with V.21 preamble\n"); | |
971 false_hit = FALSE; | |
972 false_miss = FALSE; | |
973 | |
974 /* Send 255 bits of preamble (0.85s, the minimum specified preamble for T.30), and then | |
975 some random bits. Check the preamble detector comes on, and goes off at reasonable times. */ | |
976 fsk_tx_init(&preamble_tx, &preset_fsk_specs[FSK_V21CH2], preamble_get_bit, NULL); | |
977 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, preamble_detected, NULL); | |
978 for (i = 0; i < 2*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
979 { | |
980 samples = fsk_tx(&preamble_tx, amp, SAMPLES_PER_CHUNK); | |
981 modem_connect_tones_rx(&ced_rx, amp, samples); | |
982 } | |
983 /*endfor*/ | |
984 for (i = 0; i < SAMPLE_RATE/10; i += SAMPLES_PER_CHUNK) | |
985 { | |
986 memset(amp, 0, sizeof(int16_t)*SAMPLES_PER_CHUNK); | |
987 modem_connect_tones_rx(&ced_rx, amp, SAMPLES_PER_CHUNK); | |
988 } | |
989 /*endfor*/ | |
990 if (preamble_on_at < 40 || preamble_on_at > 50 | |
991 || | |
992 preamble_off_at < 580 || preamble_off_at > 620) | |
993 { | |
994 printf("Test failed.\n"); | |
995 exit(2); | |
996 } | |
997 /*endif*/ | |
998 printf("Test passed.\n"); | |
999 } | |
1000 /*endif*/ | |
1001 | |
1002 if ((test_list & PERFORM_TEST_5A)) | |
1003 { | |
1004 printf("Test 5A: ANS and ANS/ detection with reversal interval\n"); | |
1005 tone_type = MODEM_CONNECT_TONES_ANS_PR; | |
1006 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); | |
1007 false_hit = FALSE; | |
1008 false_miss = FALSE; | |
1009 for (interval = 400; interval < 800; interval++) | |
1010 { | |
1011 printf("Reversal interval = %d\n", interval); | |
1012 /* Use the transmitter to test the receiver */ | |
1013 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
1014 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, ans_pr_detected, NULL); | |
1015 hits = 0; | |
1016 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
1017 { | |
1018 when = i; | |
1019 samples = SAMPLES_PER_CHUNK; | |
1020 for (j = 0; j < samples; j++) | |
1021 { | |
1022 if (--modem_tone_tx.hop_timer <= 0) | |
1023 { | |
1024 modem_tone_tx.hop_timer = ms_to_samples(interval); | |
1025 modem_tone_tx.tone_phase += 0x80000000; | |
1026 } | |
1027 /*endif*/ | |
1028 amp[j] = dds_mod(&modem_tone_tx.tone_phase, modem_tone_tx.tone_phase_rate, modem_tone_tx.level, 0); | |
1029 } | |
1030 for (j = 0; j < samples; j++) | |
1031 amp[j] += awgn(&chan_noise_source); | |
1032 /*endfor*/ | |
1033 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
1034 } | |
1035 /*endfor*/ | |
1036 if (interval < (450 - 25) || interval > (450 + 25)) | |
1037 { | |
1038 if (hits != 0) | |
1039 false_hit = TRUE; | |
1040 /*endif*/ | |
1041 } | |
1042 else if (interval > (450 - 25) && interval < (450 + 25)) | |
1043 { | |
1044 if (hits == 0) | |
1045 false_miss = TRUE; | |
1046 /*endif*/ | |
1047 } | |
1048 /*endif*/ | |
1049 if (hits) | |
1050 printf("Detected at %5dHz %4ddB %dms %12" PRId32 " %12" PRId32 " %d\n", 2100, -11, interval, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hits); | |
1051 /*endif*/ | |
1052 } | |
1053 /*endfor*/ | |
1054 if (false_hit || false_miss) | |
1055 { | |
1056 printf("Test failed.\n"); | |
1057 exit(2); | |
1058 } | |
1059 /*endif*/ | |
1060 printf("Test passed.\n"); | |
1061 } | |
1062 /*endif*/ | |
1063 | |
1064 if ((test_list & PERFORM_TEST_5B)) | |
1065 { | |
1066 printf("Test 5B: ANS and ANS/ detection with mixed reversal intervals\n"); | |
1067 awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); | |
1068 tone_type = MODEM_CONNECT_TONES_ANS_PR; | |
1069 false_hit = FALSE; | |
1070 false_miss = FALSE; | |
1071 interval = 450; | |
1072 printf("Reversal interval = %d\n", interval); | |
1073 /* Use the transmitter to test the receiver */ | |
1074 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
1075 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, ans_pr_detected, NULL); | |
1076 cycle = 0; | |
1077 hits = 0; | |
1078 for (i = 0; i < 60*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
1079 { | |
1080 when = i; | |
1081 samples = SAMPLES_PER_CHUNK; | |
1082 for (j = 0; j < samples; j++) | |
1083 { | |
1084 if (--modem_tone_tx.hop_timer <= 0) | |
1085 { | |
1086 if (++cycle == 10) | |
1087 interval = 1000; | |
1088 if (cycle == 20) | |
1089 interval = 450; | |
1090 modem_tone_tx.hop_timer = ms_to_samples(interval); | |
1091 modem_tone_tx.tone_phase += 0x80000000; | |
1092 } | |
1093 amp[j] = dds_mod(&modem_tone_tx.tone_phase, modem_tone_tx.tone_phase_rate, modem_tone_tx.level, 0); | |
1094 } | |
1095 /*endfor*/ | |
1096 for (j = 0; j < samples; j++) | |
1097 amp[j] += awgn(&chan_noise_source); | |
1098 /*endfor*/ | |
1099 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
1100 /* TODO: Add test result detection logic. */ | |
1101 } | |
1102 /*endfor*/ | |
1103 if (false_hit || false_miss) | |
1104 { | |
1105 printf("Test failed.\n"); | |
1106 exit(2); | |
1107 } | |
1108 /*endif*/ | |
1109 printf("Test passed.\n"); | |
1110 } | |
1111 /*endif*/ | |
1112 | |
1113 if ((test_list & PERFORM_TEST_6A)) | |
1114 { | |
1115 printf("Test 6a: ANSam detection with AM pitch\n"); | |
1116 tone_type = MODEM_CONNECT_TONES_ANSAM; | |
1117 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
1118 false_hit = FALSE; | |
1119 false_miss = FALSE; | |
1120 for (pitch = 5; pitch < 25; pitch++) | |
1121 { | |
1122 /* Use the transmitter to test the receiver */ | |
1123 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
1124 /* Fudge things for the test */ | |
1125 modem_tone_tx.mod_phase_rate = dds_phase_rate(pitch); | |
1126 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
1127 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
1128 { | |
1129 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
1130 for (j = 0; j < samples; j++) | |
1131 amp[j] += awgn(&chan_noise_source); | |
1132 /*endfor*/ | |
1133 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
1134 } | |
1135 /*endfor*/ | |
1136 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
1137 if (pitch < (15 - 10) || pitch > (15 + 10)) | |
1138 { | |
1139 if (hit == tone_type) | |
1140 false_hit = TRUE; | |
1141 /*endif*/ | |
1142 } | |
1143 else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) | |
1144 { | |
1145 if (hit != tone_type) | |
1146 false_miss = TRUE; | |
1147 /*endif*/ | |
1148 } | |
1149 /*endif*/ | |
1150 if (hit != MODEM_CONNECT_TONES_NONE) | |
1151 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
1152 /*endif*/ | |
1153 } | |
1154 /*endfor*/ | |
1155 if (false_hit || false_miss) | |
1156 { | |
1157 printf("Test failed.\n"); | |
1158 exit(2); | |
1159 } | |
1160 /*endif*/ | |
1161 printf("Test passed.\n"); | |
1162 } | |
1163 /*endif*/ | |
1164 | |
1165 if ((test_list & PERFORM_TEST_6B)) | |
1166 { | |
1167 printf("Test 6b: ANSam/ (Modulated EC-disable) detection with AM pitch\n"); | |
1168 tone_type = MODEM_CONNECT_TONES_ANSAM_PR; | |
1169 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
1170 false_hit = FALSE; | |
1171 false_miss = FALSE; | |
1172 for (pitch = 5; pitch < 25; pitch++) | |
1173 { | |
1174 /* Use the transmitter to test the receiver */ | |
1175 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
1176 /* Fudge things for the test */ | |
1177 modem_tone_tx.mod_phase_rate = dds_phase_rate(pitch); | |
1178 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
1179 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
1180 { | |
1181 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
1182 for (j = 0; j < samples; j++) | |
1183 amp[j] += awgn(&chan_noise_source); | |
1184 /*endfor*/ | |
1185 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
1186 } | |
1187 /*endfor*/ | |
1188 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
1189 if (pitch < (15 - 10) || pitch > (15 + 10)) | |
1190 { | |
1191 if (hit == tone_type) | |
1192 false_hit = TRUE; | |
1193 /*endif*/ | |
1194 } | |
1195 else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) | |
1196 { | |
1197 if (hit != tone_type) | |
1198 false_miss = TRUE; | |
1199 /*endif*/ | |
1200 } | |
1201 /*endif*/ | |
1202 if (hit != MODEM_CONNECT_TONES_NONE) | |
1203 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
1204 /*endif*/ | |
1205 } | |
1206 /*endfor*/ | |
1207 if (false_hit || false_miss) | |
1208 { | |
1209 printf("Test failed.\n"); | |
1210 exit(2); | |
1211 } | |
1212 /*endif*/ | |
1213 printf("Test passed.\n"); | |
1214 } | |
1215 /*endif*/ | |
1216 | |
1217 if ((test_list & PERFORM_TEST_7A)) | |
1218 { | |
1219 printf("Test 7a: ANSam detection with AM depth\n"); | |
1220 tone_type = MODEM_CONNECT_TONES_ANSAM; | |
1221 pitch = 2100; | |
1222 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
1223 false_hit = FALSE; | |
1224 false_miss = FALSE; | |
1225 for (depth = 0; depth < 40; depth++) | |
1226 { | |
1227 /* Use the transmitter to test the receiver */ | |
1228 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
1229 /* Fudge things for the test */ | |
1230 modem_tone_tx.mod_level = modem_tone_tx.level*depth/100; | |
1231 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
1232 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
1233 { | |
1234 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
1235 for (j = 0; j < samples; j++) | |
1236 amp[j] += awgn(&chan_noise_source); | |
1237 /*endfor*/ | |
1238 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
1239 } | |
1240 /*endfor*/ | |
1241 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
1242 if (depth < 10) | |
1243 { | |
1244 if (hit == tone_type) | |
1245 false_hit = TRUE; | |
1246 /*endif*/ | |
1247 } | |
1248 else if (depth > 15) | |
1249 { | |
1250 if (hit != tone_type) | |
1251 false_miss = TRUE; | |
1252 /*endif*/ | |
1253 } | |
1254 /*endif*/ | |
1255 if (hit != MODEM_CONNECT_TONES_NONE) | |
1256 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
1257 /*endif*/ | |
1258 } | |
1259 /*endfor*/ | |
1260 if (false_hit || false_miss) | |
1261 { | |
1262 printf("Test failed.\n"); | |
1263 exit(2); | |
1264 } | |
1265 /*endif*/ | |
1266 printf("Test passed.\n"); | |
1267 } | |
1268 /*endif*/ | |
1269 | |
1270 if ((test_list & PERFORM_TEST_7B)) | |
1271 { | |
1272 printf("Test 7b: ANSam/ (Modulated EC-disable) detection with AM depth\n"); | |
1273 tone_type = MODEM_CONNECT_TONES_ANSAM_PR; | |
1274 pitch = 2100; | |
1275 awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); | |
1276 false_hit = FALSE; | |
1277 false_miss = FALSE; | |
1278 for (depth = 0; depth < 40; depth++) | |
1279 { | |
1280 /* Use the transmitter to test the receiver */ | |
1281 modem_connect_tones_tx_init(&modem_tone_tx, tone_type); | |
1282 /* Fudge things for the test */ | |
1283 modem_tone_tx.mod_level = modem_tone_tx.level*depth/100; | |
1284 modem_connect_tones_rx_init(&ans_pr_rx, tone_type, NULL, NULL); | |
1285 for (i = 0; i < 10*SAMPLE_RATE; i += SAMPLES_PER_CHUNK) | |
1286 { | |
1287 samples = modem_connect_tones_tx(&modem_tone_tx, amp, SAMPLES_PER_CHUNK); | |
1288 for (j = 0; j < samples; j++) | |
1289 amp[j] += awgn(&chan_noise_source); | |
1290 /*endfor*/ | |
1291 modem_connect_tones_rx(&ans_pr_rx, amp, samples); | |
1292 } | |
1293 /*endfor*/ | |
1294 hit = modem_connect_tones_rx_get(&ans_pr_rx); | |
1295 if (depth < 10) | |
1296 { | |
1297 if (hit == tone_type) | |
1298 false_hit = TRUE; | |
1299 /*endif*/ | |
1300 } | |
1301 else if (depth > 15) | |
1302 { | |
1303 if (hit != tone_type) | |
1304 false_miss = TRUE; | |
1305 /*endif*/ | |
1306 } | |
1307 /*endif*/ | |
1308 if (hit != MODEM_CONNECT_TONES_NONE) | |
1309 printf("Detected at %5dHz %12" PRId32 " %12" PRId32 " %d\n", pitch, ans_pr_rx.channel_level, ans_pr_rx.notch_level, hit); | |
1310 /*endif*/ | |
1311 } | |
1312 /*endfor*/ | |
1313 if (false_hit || false_miss) | |
1314 { | |
1315 printf("Test failed.\n"); | |
1316 exit(2); | |
1317 } | |
1318 /*endif*/ | |
1319 printf("Test passed.\n"); | |
1320 } | |
1321 /*endif*/ | |
1322 | |
1323 if ((test_list & PERFORM_TEST_8)) | |
1324 { | |
1325 /* Talk-off test */ | |
1326 /* Here we use the BellCore and Mitel talk off test tapes, intended for DTMF | |
1327 detector testing. Presumably they should also have value here, but I am not | |
1328 sure. If those voice snippets were chosen to be tough on DTMF detectors, they | |
1329 might go easy on detectors looking for different pitches. However, the | |
1330 Mitel DTMF test tape is known (the hard way) to exercise 2280Hz tone | |
1331 detectors quite well. */ | |
1332 printf("Test 8: Talk-off test\n"); | |
1333 modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL); | |
1334 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); | |
1335 modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); | |
1336 for (j = 0; bellcore_files[j][0]; j++) | |
1337 { | |
1338 if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL) | |
1339 { | |
1340 fprintf(stderr, " Cannot open speech file '%s'\n", bellcore_files[j]); | |
1341 exit (2); | |
1342 } | |
1343 /*endif*/ | |
1344 | |
1345 when = 0; | |
1346 hits = 0; | |
1347 while ((frames = sf_readf_short(inhandle, amp, 8000))) | |
1348 { | |
1349 when++; | |
1350 modem_connect_tones_rx(&cng_rx, amp, frames); | |
1351 modem_connect_tones_rx(&ced_rx, amp, frames); | |
1352 modem_connect_tones_rx(&ans_pr_rx, amp, frames); | |
1353 if (modem_connect_tones_rx_get(&cng_rx) != MODEM_CONNECT_TONES_NONE) | |
1354 { | |
1355 /* This is not a true measure of hits, as there might be more | |
1356 than one in a block of data. However, since the only good | |
1357 result is no hits, this approximation is OK. */ | |
1358 printf("Hit CNG at %ds\n", when); | |
1359 hits++; | |
1360 modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, NULL, NULL); | |
1361 } | |
1362 /*endif*/ | |
1363 if (modem_connect_tones_rx_get(&ced_rx) != MODEM_CONNECT_TONES_NONE) | |
1364 { | |
1365 printf("Hit CED at %ds\n", when); | |
1366 hits++; | |
1367 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, NULL, NULL); | |
1368 } | |
1369 /*endif*/ | |
1370 if (modem_connect_tones_rx_get(&ans_pr_rx) != MODEM_CONNECT_TONES_NONE) | |
1371 { | |
1372 printf("Hit EC disable at %ds\n", when); | |
1373 hits++; | |
1374 modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); | |
1375 } | |
1376 /*endif*/ | |
1377 } | |
1378 /*endwhile*/ | |
1379 if (sf_close(inhandle) != 0) | |
1380 { | |
1381 fprintf(stderr, " Cannot close speech file '%s'\n", bellcore_files[j]); | |
1382 exit(2); | |
1383 } | |
1384 /*endif*/ | |
1385 printf(" File %d gave %d false hits.\n", j + 1, hits); | |
1386 } | |
1387 /*endfor*/ | |
1388 if (hits > 0) | |
1389 { | |
1390 printf("Test failed.\n"); | |
1391 exit(2); | |
1392 } | |
1393 /*endif*/ | |
1394 printf("Test passed.\n"); | |
1395 } | |
1396 /*endif*/ | |
1397 | |
1398 if (decode_test_file) | |
1399 { | |
1400 printf("Decode file '%s'\n", decode_test_file); | |
1401 modem_connect_tones_rx_init(&cng_rx, MODEM_CONNECT_TONES_FAX_CNG, cng_detected, NULL); | |
1402 modem_connect_tones_rx_init(&ced_rx, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, ced_detected, NULL); | |
1403 modem_connect_tones_rx_init(&ans_pr_rx, MODEM_CONNECT_TONES_ANS_PR, ans_pr_detected, NULL); | |
1404 hits = 0; | |
1405 if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL) | |
1406 { | |
1407 fprintf(stderr, " Cannot open speech file '%s'\n", decode_test_file); | |
1408 exit (2); | |
1409 } | |
1410 /*endif*/ | |
1411 | |
1412 when = 0; | |
1413 hits = 0; | |
1414 while ((frames = sf_readf_short(inhandle, amp, 8000))) | |
1415 { | |
1416 when++; | |
1417 modem_connect_tones_rx(&cng_rx, amp, frames); | |
1418 modem_connect_tones_rx(&ced_rx, amp, frames); | |
1419 modem_connect_tones_rx(&ans_pr_rx, amp, frames); | |
1420 } | |
1421 /*endwhile*/ | |
1422 if (sf_close(inhandle) != 0) | |
1423 { | |
1424 fprintf(stderr, " Cannot close speech file '%s'\n", decode_test_file); | |
1425 exit(2); | |
1426 } | |
1427 /*endif*/ | |
1428 printf(" File gave %d hits.\n", hits); | |
1429 } | |
1430 printf("Tests passed.\n"); | |
1431 return 0; | |
1432 } | |
1433 /*- End of function --------------------------------------------------------*/ | |
1434 /*- End of file ------------------------------------------------------------*/ |