comparison spandsp-0.0.6pre17/tests/fax_decode.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 * fax_decode.c - a simple FAX audio decoder
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2005 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: fax_decode.c,v 1.58 2009/11/02 13:25:20 steveu Exp $
26 */
27
28 /*! \page fax_decode_page FAX decoder
29 \section fax_decode_page_sec_1 What does it do?
30 ???.
31
32 \section fax_decode_tests_page_sec_2 How does it work?
33 ???.
34 */
35
36 #if defined(HAVE_CONFIG_H)
37 #include "config.h"
38 #endif
39
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <sndfile.h>
45
46 //#if defined(WITH_SPANDSP_INTERNALS)
47 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
48 //#endif
49
50 #include "spandsp.h"
51
52 #define SAMPLES_PER_CHUNK 160
53
54 #define DISBIT1 0x01
55 #define DISBIT2 0x02
56 #define DISBIT3 0x04
57 #define DISBIT4 0x08
58 #define DISBIT5 0x10
59 #define DISBIT6 0x20
60 #define DISBIT7 0x40
61 #define DISBIT8 0x80
62
63 enum
64 {
65 FAX_NONE,
66 FAX_V27TER_RX,
67 FAX_V29_RX,
68 FAX_V17_RX
69 };
70
71 static const struct
72 {
73 int bit_rate;
74 int modem_type;
75 int which;
76 uint8_t dcs_code;
77 } fallback_sequence[] =
78 {
79 {14400, T30_MODEM_V17, T30_SUPPORT_V17, DISBIT6},
80 {12000, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT4)},
81 { 9600, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT3)},
82 { 9600, T30_MODEM_V29, T30_SUPPORT_V29, DISBIT3},
83 { 7200, T30_MODEM_V17, T30_SUPPORT_V17, (DISBIT6 | DISBIT4 | DISBIT3)},
84 { 7200, T30_MODEM_V29, T30_SUPPORT_V29, (DISBIT4 | DISBIT3)},
85 { 4800, T30_MODEM_V27TER, T30_SUPPORT_V27TER, DISBIT4},
86 { 2400, T30_MODEM_V27TER, T30_SUPPORT_V27TER, 0},
87 { 0, 0, 0, 0}
88 };
89
90 int decode_test = FALSE;
91 int rx_bits = 0;
92
93 t30_state_t t30_dummy;
94 t4_state_t t4_state;
95 int t4_up = FALSE;
96
97 hdlc_rx_state_t hdlcrx;
98
99 int fast_trained = FAX_NONE;
100
101 uint8_t ecm_data[256][260];
102 int16_t ecm_len[256];
103
104 int line_encoding = T4_COMPRESSION_ITU_T4_1D;
105 int x_resolution = T4_X_RESOLUTION_R8;
106 int y_resolution = T4_Y_RESOLUTION_STANDARD;
107 int image_width = 1728;
108 int octets_per_ecm_frame = 256;
109 int error_correcting_mode = FALSE;
110 int current_fallback = 0;
111
112 static void print_frame(const char *io, const uint8_t *fr, int frlen)
113 {
114 int i;
115 int type;
116 const char *country;
117 const char *vendor;
118 const char *model;
119
120 fprintf(stderr, "%s %s:", io, t30_frametype(fr[2]));
121 for (i = 2; i < frlen; i++)
122 fprintf(stderr, " %02x", fr[i]);
123 fprintf(stderr, "\n");
124 type = fr[2] & 0xFE;
125 if (type == T30_DIS || type == T30_DTC || type == T30_DCS)
126 t30_decode_dis_dtc_dcs(&t30_dummy, fr, frlen);
127 if (type == T30_NSF || type == T30_NSS || type == T30_NSC)
128 {
129 if (t35_decode(&fr[3], frlen - 3, &country, &vendor, &model))
130 {
131 if (country)
132 fprintf(stderr, "The remote was made in '%s'\n", country);
133 if (vendor)
134 fprintf(stderr, "The remote was made by '%s'\n", vendor);
135 if (model)
136 fprintf(stderr, "The remote is a '%s'\n", model);
137 }
138 }
139 }
140 /*- End of function --------------------------------------------------------*/
141
142 static int find_fallback_entry(int dcs_code)
143 {
144 int i;
145
146 /* The table is short, and not searched often, so a brain-dead linear scan seems OK */
147 for (i = 0; fallback_sequence[i].bit_rate; i++)
148 {
149 if (fallback_sequence[i].dcs_code == dcs_code)
150 break;
151 }
152 if (fallback_sequence[i].bit_rate == 0)
153 return -1;
154 return i;
155 }
156 /*- End of function --------------------------------------------------------*/
157
158 static int check_rx_dcs(const uint8_t *msg, int len)
159 {
160 static const int widths[3][4] =
161 {
162 { 864, 1024, 1216, -1}, /* R4 resolution - no longer used in recent versions of T.30 */
163 {1728, 2048, 2432, -1}, /* R8 resolution */
164 {3456, 4096, 4864, -1} /* R16 resolution */
165 };
166 uint8_t dcs_frame[T30_MAX_DIS_DTC_DCS_LEN];
167
168 /* Check DCS frame from remote */
169 if (len < 6)
170 {
171 printf("Short DCS frame\n");
172 return -1;
173 }
174
175 /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows
176 us to simply pick out the bits, without worrying about whether they were set from the remote side. */
177 if (len > T30_MAX_DIS_DTC_DCS_LEN)
178 {
179 memcpy(dcs_frame, msg, T30_MAX_DIS_DTC_DCS_LEN);
180 }
181 else
182 {
183 memcpy(dcs_frame, msg, len);
184 if (len < T30_MAX_DIS_DTC_DCS_LEN)
185 memset(dcs_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len);
186 }
187
188 octets_per_ecm_frame = (dcs_frame[6] & DISBIT4) ? 256 : 64;
189 if ((dcs_frame[8] & DISBIT1))
190 y_resolution = T4_Y_RESOLUTION_SUPERFINE;
191 else if (dcs_frame[4] & DISBIT7)
192 y_resolution = T4_Y_RESOLUTION_FINE;
193 else
194 y_resolution = T4_Y_RESOLUTION_STANDARD;
195 image_width = widths[(dcs_frame[8] & DISBIT3) ? 2 : 1][dcs_frame[5] & (DISBIT2 | DISBIT1)];
196
197 /* Check which compression we will use. */
198 if ((dcs_frame[6] & DISBIT7))
199 line_encoding = T4_COMPRESSION_ITU_T6;
200 else if ((dcs_frame[4] & DISBIT8))
201 line_encoding = T4_COMPRESSION_ITU_T4_2D;
202 else
203 line_encoding = T4_COMPRESSION_ITU_T4_1D;
204 fprintf(stderr, "Selected compression %d\n", line_encoding);
205
206 if ((current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0)
207 printf("Remote asked for a modem standard we do not support\n");
208 error_correcting_mode = ((dcs_frame[6] & DISBIT3) != 0);
209
210 //v17_rx_restart(&v17, fallback_sequence[fallback_entry].bit_rate, FALSE);
211 return 0;
212 }
213 /*- End of function --------------------------------------------------------*/
214
215 static void hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
216 {
217 int type;
218 int frame_no;
219 int i;
220
221 if (len < 0)
222 {
223 /* Special conditions */
224 fprintf(stderr, "HDLC status is %s (%d)\n", signal_status_to_str(len), len);
225 return;
226 }
227
228 if (ok)
229 {
230 if (msg[0] != 0xFF || !(msg[1] == 0x03 || msg[1] == 0x13))
231 {
232 fprintf(stderr, "Bad frame header - %02x %02x\n", msg[0], msg[1]);
233 return;
234 }
235 print_frame("HDLC: ", msg, len);
236 type = msg[2] & 0xFE;
237 switch (type)
238 {
239 case T4_FCD:
240 if (len <= 4 + 256)
241 {
242 frame_no = msg[3];
243 /* Just store the actual image data, and record its length */
244 memcpy(&ecm_data[frame_no][0], &msg[4], len - 4);
245 ecm_len[frame_no] = (int16_t) (len - 4);
246 }
247 break;
248 case T30_DCS:
249 check_rx_dcs(msg, len);
250 break;
251 }
252 }
253 else
254 {
255 fprintf(stderr, "Bad HDLC frame ");
256 for (i = 0; i < len; i++)
257 fprintf(stderr, " %02x", msg[i]);
258 fprintf(stderr, "\n");
259 }
260 }
261 /*- End of function --------------------------------------------------------*/
262
263 static void t4_begin(void)
264 {
265 int i;
266
267 //printf("Begin T.4 - %d %d %d %d\n", line_encoding, x_resolution, y_resolution, image_width);
268 t4_rx_set_rx_encoding(&t4_state, line_encoding);
269 t4_rx_set_x_resolution(&t4_state, x_resolution);
270 t4_rx_set_y_resolution(&t4_state, y_resolution);
271 t4_rx_set_image_width(&t4_state, image_width);
272
273 t4_rx_start_page(&t4_state);
274 t4_up = TRUE;
275
276 for (i = 0; i < 256; i++)
277 ecm_len[i] = -1;
278 }
279 /*- End of function --------------------------------------------------------*/
280
281 static void t4_end(void)
282 {
283 t4_stats_t stats;
284 int i;
285 int j;
286 int k;
287
288 if (!t4_up)
289 return;
290 if (error_correcting_mode)
291 {
292 for (i = 0; i < 256; i++)
293 {
294 for (j = 0; j < ecm_len[i]; j++)
295 {
296 for (k = 0; k < 8; k++)
297 t4_rx_put_bit(&t4_state, (ecm_data[i][j] >> k) & 1);
298 }
299 fprintf(stderr, "%d", (ecm_len[i] < 0) ? 0 : 1);
300 }
301 fprintf(stderr, "\n");
302 }
303 t4_rx_end_page(&t4_state);
304 t4_get_transfer_statistics(&t4_state, &stats);
305 fprintf(stderr, "Pages = %d\n", stats.pages_transferred);
306 fprintf(stderr, "Image size = %dx%d\n", stats.width, stats.length);
307 fprintf(stderr, "Image resolution = %dx%d\n", stats.x_resolution, stats.y_resolution);
308 fprintf(stderr, "Bad rows = %d\n", stats.bad_rows);
309 fprintf(stderr, "Longest bad row run = %d\n", stats.longest_bad_row_run);
310 t4_up = FALSE;
311 }
312 /*- End of function --------------------------------------------------------*/
313
314 static void v21_put_bit(void *user_data, int bit)
315 {
316 if (bit < 0)
317 {
318 /* Special conditions */
319 fprintf(stderr, "V.21 rx status is %s (%d)\n", signal_status_to_str(bit), bit);
320 switch (bit)
321 {
322 case SIG_STATUS_CARRIER_DOWN:
323 //t4_end();
324 break;
325 }
326 return;
327 }
328 if (fast_trained == FAX_NONE)
329 hdlc_rx_put_bit(&hdlcrx, bit);
330 //printf("V.21 Rx bit %d - %d\n", rx_bits++, bit);
331 }
332 /*- End of function --------------------------------------------------------*/
333
334 static void v17_put_bit(void *user_data, int bit)
335 {
336 if (bit < 0)
337 {
338 /* Special conditions */
339 fprintf(stderr, "V.17 rx status is %s (%d)\n", signal_status_to_str(bit), bit);
340 switch (bit)
341 {
342 case SIG_STATUS_TRAINING_SUCCEEDED:
343 fast_trained = FAX_V17_RX;
344 t4_begin();
345 break;
346 case SIG_STATUS_CARRIER_DOWN:
347 t4_end();
348 if (fast_trained == FAX_V17_RX)
349 fast_trained = FAX_NONE;
350 break;
351 }
352 return;
353 }
354 if (error_correcting_mode)
355 {
356 hdlc_rx_put_bit(&hdlcrx, bit);
357 }
358 else
359 {
360 if (t4_rx_put_bit(&t4_state, bit))
361 {
362 t4_end();
363 fprintf(stderr, "End of page detected\n");
364 }
365 }
366 //printf("V.17 Rx bit %d - %d\n", rx_bits++, bit);
367 }
368 /*- End of function --------------------------------------------------------*/
369
370 static void v29_put_bit(void *user_data, int bit)
371 {
372 if (bit < 0)
373 {
374 /* Special conditions */
375 fprintf(stderr, "V.29 rx status is %s (%d)\n", signal_status_to_str(bit), bit);
376 switch (bit)
377 {
378 case SIG_STATUS_TRAINING_SUCCEEDED:
379 fast_trained = FAX_V29_RX;
380 t4_begin();
381 break;
382 case SIG_STATUS_CARRIER_DOWN:
383 t4_end();
384 if (fast_trained == FAX_V29_RX)
385 fast_trained = FAX_NONE;
386 break;
387 }
388 return;
389 }
390 if (error_correcting_mode)
391 {
392 hdlc_rx_put_bit(&hdlcrx, bit);
393 }
394 else
395 {
396 if (t4_rx_put_bit(&t4_state, bit))
397 {
398 t4_end();
399 fprintf(stderr, "End of page detected\n");
400 }
401 }
402 //printf("V.29 Rx bit %d - %d\n", rx_bits++, bit);
403 }
404 /*- End of function --------------------------------------------------------*/
405
406 static void v27ter_put_bit(void *user_data, int bit)
407 {
408 if (bit < 0)
409 {
410 /* Special conditions */
411 fprintf(stderr, "V.27ter rx status is %s (%d)\n", signal_status_to_str(bit), bit);
412 switch (bit)
413 {
414 case SIG_STATUS_TRAINING_SUCCEEDED:
415 fast_trained = FAX_V27TER_RX;
416 t4_begin();
417 break;
418 case SIG_STATUS_CARRIER_DOWN:
419 t4_end();
420 if (fast_trained == FAX_V27TER_RX)
421 fast_trained = FAX_NONE;
422 break;
423 }
424 return;
425 }
426 if (error_correcting_mode)
427 {
428 hdlc_rx_put_bit(&hdlcrx, bit);
429 }
430 else
431 {
432 if (t4_rx_put_bit(&t4_state, bit))
433 {
434 t4_end();
435 fprintf(stderr, "End of page detected\n");
436 }
437 }
438 //printf("V.27ter Rx bit %d - %d\n", rx_bits++, bit);
439 }
440 /*- End of function --------------------------------------------------------*/
441
442 int main(int argc, char *argv[])
443 {
444 fsk_rx_state_t *fsk;
445 v17_rx_state_t *v17;
446 v29_rx_state_t *v29;
447 v27ter_rx_state_t *v27ter;
448 int16_t amp[SAMPLES_PER_CHUNK];
449 SNDFILE *inhandle;
450 SF_INFO info;
451 int len;
452 const char *filename;
453 logging_state_t *logging;
454
455 filename = "fax_samp.wav";
456
457 if (argc > 1)
458 filename = argv[1];
459
460 memset(&info, 0, sizeof(info));
461 if ((inhandle = sf_open(filename, SFM_READ, &info)) == NULL)
462 {
463 fprintf(stderr, " Cannot open audio file '%s' for reading\n", filename);
464 exit(2);
465 }
466 if (info.samplerate != SAMPLE_RATE)
467 {
468 printf(" Unexpected sample rate in audio file '%s'\n", filename);
469 exit(2);
470 }
471 if (info.channels != 1)
472 {
473 printf(" Unexpected number of channels in audio file '%s'\n", filename);
474 exit(2);
475 }
476
477 memset(&t30_dummy, 0, sizeof(t30_dummy));
478 span_log_init(&t30_dummy.logging, SPAN_LOG_FLOW, NULL);
479 span_log_set_protocol(&t30_dummy.logging, "T.30");
480
481 hdlc_rx_init(&hdlcrx, FALSE, TRUE, 5, hdlc_accept, NULL);
482 fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, NULL);
483 v17 = v17_rx_init(NULL, 14400, v17_put_bit, NULL);
484 v29 = v29_rx_init(NULL, 9600, v29_put_bit, NULL);
485 //v29 = v29_rx_init(NULL, 7200, v29_put_bit, NULL);
486 v27ter = v27ter_rx_init(NULL, 4800, v27ter_put_bit, NULL);
487 fsk_rx_signal_cutoff(fsk, -45.5);
488 v17_rx_signal_cutoff(v17, -45.5);
489 v29_rx_signal_cutoff(v29, -45.5);
490 v27ter_rx_signal_cutoff(v27ter, -40.0);
491
492 #if 1
493 logging = v17_rx_get_logging_state(v17);
494 span_log_init(logging, SPAN_LOG_FLOW, NULL);
495 span_log_set_protocol(logging, "V.17");
496 span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
497
498 logging = v29_rx_get_logging_state(v29);
499 span_log_init(logging, SPAN_LOG_FLOW, NULL);
500 span_log_set_protocol(logging, "V.29");
501 span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
502
503 logging = v27ter_rx_get_logging_state(v27ter);
504 span_log_init(logging, SPAN_LOG_FLOW, NULL);
505 span_log_set_protocol(logging, "V.27ter");
506 span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
507 #endif
508
509 if (t4_rx_init(&t4_state, "fax_decode.tif", T4_COMPRESSION_ITU_T4_2D) == NULL)
510 {
511 fprintf(stderr, "Failed to init\n");
512 exit(0);
513 }
514
515 for (;;)
516 {
517 len = sf_readf_short(inhandle, amp, SAMPLES_PER_CHUNK);
518 if (len < SAMPLES_PER_CHUNK)
519 break;
520 fsk_rx(fsk, amp, len);
521 v17_rx(v17, amp, len);
522 v29_rx(v29, amp, len);
523 //v27ter_rx(v27ter, amp, len);
524 }
525 t4_rx_release(&t4_state);
526
527 if (sf_close(inhandle) != 0)
528 {
529 fprintf(stderr, " Cannot close audio file '%s'\n", filename);
530 exit(2);
531 }
532 return 0;
533 }
534 /*- End of function --------------------------------------------------------*/
535 /*- End of file ------------------------------------------------------------*/

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