5
|
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.22 2006/11/19 14:07:27 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 #ifdef HAVE_CONFIG_H
|
|
37 #include "config.h"
|
|
38 #endif
|
|
39
|
|
40 #include <inttypes.h>
|
|
41 #include <stdlib.h>
|
|
42 #include <stdio.h>
|
|
43 #include <string.h>
|
|
44 #if defined(HAVE_TGMATH_H)
|
|
45 #include <tgmath.h>
|
|
46 #endif
|
|
47 #if defined(HAVE_MATH_H)
|
|
48 #include <math.h>
|
|
49 #endif
|
|
50 #include <assert.h>
|
|
51 #include <audiofile.h>
|
|
52 #include <tiffio.h>
|
|
53
|
|
54 #include "spandsp.h"
|
|
55
|
|
56 #define SAMPLES_PER_CHUNK 160
|
|
57
|
|
58 int decode_test = FALSE;
|
|
59
|
|
60 int rx_bits = 0;
|
|
61
|
|
62 t30_state_t t30_dummy;
|
|
63 t4_state_t t4_state;
|
|
64 int t4_up = FALSE;
|
|
65
|
|
66 static void print_frame(const char *io, const uint8_t *fr, int frlen)
|
|
67 {
|
|
68 int i;
|
|
69 int type;
|
|
70 const char *country;
|
|
71 const char *vendor;
|
|
72 const char *model;
|
|
73
|
|
74 fprintf(stderr, "%s %s:", io, t30_frametype(fr[2]));
|
|
75 for (i = 2; i < frlen; i++)
|
|
76 fprintf(stderr, " %02x", fr[i]);
|
|
77 fprintf(stderr, "\n");
|
|
78 type = fr[2] & 0xFE;
|
|
79 if (type == T30_DIS || type == T30_DTC || type == T30_DCS)
|
|
80 t30_decode_dis_dtc_dcs(&t30_dummy, fr, frlen);
|
|
81 if (type == T30_NSF)
|
|
82 {
|
|
83 if (t35_decode(&fr[3], frlen - 3, &country, &vendor, &model))
|
|
84 {
|
|
85 if (country)
|
|
86 printf("The remote was made in '%s'\n", country);
|
|
87 if (vendor)
|
|
88 printf("The remote was made by '%s'\n", vendor);
|
|
89 if (model)
|
|
90 printf("The remote is a '%s'\n", model);
|
|
91 }
|
|
92 }
|
|
93 }
|
|
94 /*- End of function --------------------------------------------------------*/
|
|
95
|
|
96 static void hdlc_accept(void *user_data, int ok, const uint8_t *msg, int len)
|
|
97 {
|
|
98 if (len < 0)
|
|
99 {
|
|
100 /* Special conditions */
|
|
101 switch (len)
|
|
102 {
|
|
103 case PUTBIT_CARRIER_UP:
|
|
104 fprintf(stderr, "Slow carrier up\n");
|
|
105 break;
|
|
106 case PUTBIT_CARRIER_DOWN:
|
|
107 fprintf(stderr, "Slow carrier down\n");
|
|
108 break;
|
|
109 case PUTBIT_FRAMING_OK:
|
|
110 case PUTBIT_ABORT:
|
|
111 /* Just ignore these */
|
|
112 break;
|
|
113 default:
|
|
114 fprintf(stderr, "Unexpected HDLC special length - %d!\n", len);
|
|
115 break;
|
|
116 }
|
|
117 return;
|
|
118 }
|
|
119
|
|
120 if (msg[0] != 0xFF || !(msg[1] == 0x03 || msg[1] == 0x13))
|
|
121 {
|
|
122 fprintf(stderr, "Bad frame header - %02x %02x", msg[0], msg[1]);
|
|
123 return;
|
|
124 }
|
|
125 print_frame("HDLC: ", msg, len);
|
|
126 }
|
|
127 /*- End of function --------------------------------------------------------*/
|
|
128
|
|
129 static void t4_begin(void)
|
|
130 {
|
|
131 t4_rx_set_rx_encoding(&t4_state, T4_COMPRESSION_ITU_T4_2D);
|
|
132 t4_rx_set_x_resolution(&t4_state, T4_X_RESOLUTION_R8);
|
|
133 t4_rx_set_y_resolution(&t4_state, T4_Y_RESOLUTION_STANDARD);
|
|
134 t4_rx_set_image_width(&t4_state, 1728);
|
|
135
|
|
136 t4_rx_start_page(&t4_state);
|
|
137 t4_up = TRUE;
|
|
138 }
|
|
139 /*- End of function --------------------------------------------------------*/
|
|
140
|
|
141 static void t4_end(void)
|
|
142 {
|
|
143 t4_stats_t stats;
|
|
144
|
|
145 if (!t4_up)
|
|
146 return;
|
|
147 t4_rx_end_page(&t4_state);
|
|
148 t4_get_transfer_statistics(&t4_state, &stats);
|
|
149 printf("Pages = %d\n", stats.pages_transferred);
|
|
150 printf("Image size = %dx%d\n", stats.width, stats.length);
|
|
151 printf("Image resolution = %dx%d\n", stats.x_resolution, stats.y_resolution);
|
|
152 printf("Bad rows = %d\n", stats.bad_rows);
|
|
153 printf("Longest bad row run = %d\n", stats.longest_bad_row_run);
|
|
154 t4_up = FALSE;
|
|
155 }
|
|
156 /*- End of function --------------------------------------------------------*/
|
|
157
|
|
158 #if defined(ENABLE_V17)
|
|
159 static void v17_put_bit(void *user_data, int bit)
|
|
160 {
|
|
161 int end_of_page;
|
|
162
|
|
163 if (bit < 0)
|
|
164 {
|
|
165 /* Special conditions */
|
|
166 switch (bit)
|
|
167 {
|
|
168 case PUTBIT_TRAINING_FAILED:
|
|
169 //printf("V.17 Training failed\n");
|
|
170 break;
|
|
171 case PUTBIT_TRAINING_SUCCEEDED:
|
|
172 printf("V.17 Training succeeded\n");
|
|
173 t4_begin();
|
|
174 break;
|
|
175 case PUTBIT_CARRIER_UP:
|
|
176 //printf("V.17 Carrier up\n");
|
|
177 break;
|
|
178 case PUTBIT_CARRIER_DOWN:
|
|
179 //printf("V.17 Carrier down\n");
|
|
180 t4_end();
|
|
181 break;
|
|
182 default:
|
|
183 printf("V.17 Eh!\n");
|
|
184 break;
|
|
185 }
|
|
186 return;
|
|
187 }
|
|
188
|
|
189 end_of_page = t4_rx_putbit(&t4_state, bit);
|
|
190 if (end_of_page)
|
|
191 {
|
|
192 t4_end();
|
|
193 printf("End of page detected\n");
|
|
194 }
|
|
195 //printf("V.17 Rx bit %d - %d\n", rx_bits++, bit);
|
|
196 }
|
|
197 /*- End of function --------------------------------------------------------*/
|
|
198 #endif
|
|
199
|
|
200 static void v29_put_bit(void *user_data, int bit)
|
|
201 {
|
|
202 int end_of_page;
|
|
203
|
|
204 if (bit < 0)
|
|
205 {
|
|
206 /* Special conditions */
|
|
207 switch (bit)
|
|
208 {
|
|
209 case PUTBIT_TRAINING_FAILED:
|
|
210 //printf("V.29 Training failed\n");
|
|
211 break;
|
|
212 case PUTBIT_TRAINING_SUCCEEDED:
|
|
213 printf("V.29 Training succeeded\n");
|
|
214 t4_begin();
|
|
215 break;
|
|
216 case PUTBIT_CARRIER_UP:
|
|
217 //printf("V.29 Carrier up\n");
|
|
218 break;
|
|
219 case PUTBIT_CARRIER_DOWN:
|
|
220 //printf("V.29 Carrier down\n");
|
|
221 t4_end();
|
|
222 break;
|
|
223 default:
|
|
224 printf("V.29 Eh!\n");
|
|
225 break;
|
|
226 }
|
|
227 return;
|
|
228 }
|
|
229
|
|
230 end_of_page = t4_rx_put_bit(&t4_state, bit);
|
|
231 if (end_of_page)
|
|
232 {
|
|
233 t4_end();
|
|
234 printf("End of page detected\n");
|
|
235 }
|
|
236 //printf("V.29 Rx bit %d - %d\n", rx_bits++, bit);
|
|
237 }
|
|
238 /*- End of function --------------------------------------------------------*/
|
|
239
|
|
240 static void v27ter_put_bit(void *user_data, int bit)
|
|
241 {
|
|
242 if (bit < 0)
|
|
243 {
|
|
244 /* Special conditions */
|
|
245 switch (bit)
|
|
246 {
|
|
247 case PUTBIT_TRAINING_FAILED:
|
|
248 //printf("V.27ter Training failed\n");
|
|
249 break;
|
|
250 case PUTBIT_TRAINING_SUCCEEDED:
|
|
251 printf("V.27ter Training succeeded\n");
|
|
252 t4_begin();
|
|
253 break;
|
|
254 case PUTBIT_CARRIER_UP:
|
|
255 //printf("V.27ter Carrier up\n");
|
|
256 break;
|
|
257 case PUTBIT_CARRIER_DOWN:
|
|
258 //printf("V.27ter Carrier down\n");
|
|
259 break;
|
|
260 default:
|
|
261 printf("V.27ter Eh!\n");
|
|
262 break;
|
|
263 }
|
|
264 return;
|
|
265 }
|
|
266
|
|
267 printf("V.27ter Rx bit %d - %d\n", rx_bits++, bit);
|
|
268 }
|
|
269 /*- End of function --------------------------------------------------------*/
|
|
270
|
|
271 int main(int argc, char *argv[])
|
|
272 {
|
|
273 hdlc_rx_state_t hdlcrx;
|
|
274 fsk_rx_state_t fsk;
|
|
275 #if defined(ENABLE_V17)
|
|
276 v17_rx_state_t v17;
|
|
277 #endif
|
|
278 v29_rx_state_t v29;
|
|
279 v27ter_rx_state_t v27ter;
|
|
280 int16_t amp[SAMPLES_PER_CHUNK];
|
|
281 AFfilehandle inhandle;
|
|
282 int len;
|
|
283 const char *filename;
|
|
284
|
|
285 filename = "fax_samp.wav";
|
|
286
|
|
287 if (argc > 1)
|
|
288 filename = argv[1];
|
|
289
|
|
290 inhandle = afOpenFile(filename, "r", NULL);
|
|
291 if (inhandle == AF_NULL_FILEHANDLE)
|
|
292 {
|
|
293 fprintf(stderr, " Cannot open wave file '%s'\n", filename);
|
|
294 exit(2);
|
|
295 }
|
|
296 memset(&t30_dummy, 0, sizeof(t30_dummy));
|
|
297 span_log_init(&t30_dummy.logging, SPAN_LOG_FLOW, NULL);
|
|
298 span_log_set_protocol(&t30_dummy.logging, "T.30");
|
|
299
|
|
300 hdlc_rx_init(&hdlcrx, FALSE, FALSE, 1, hdlc_accept, NULL);
|
|
301 fsk_rx_init(&fsk, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &hdlcrx);
|
|
302 #if defined(ENABLE_V17)
|
|
303 v17_rx_init(&v17, 14400, v17_put_bit, NULL);
|
|
304 #endif
|
|
305 v29_rx_init(&v29, 9600, v29_put_bit, NULL);
|
|
306 v27ter_rx_init(&v27ter, 4800, v27ter_put_bit, NULL);
|
|
307 fsk_rx_signal_cutoff(&fsk, -45.0);
|
|
308 #if defined(ENABLE_V17)
|
|
309 v17_rx_signal_cutoff(&v17, -45.0);
|
|
310 #endif
|
|
311 v29_rx_signal_cutoff(&v29, -45.0);
|
|
312 v27ter_rx_signal_cutoff(&v27ter, -40.0);
|
|
313
|
|
314 //span_log_init(&v29.logging, SPAN_LOG_FLOW, NULL);
|
|
315 //span_log_set_protocol(&v29.logging, "V.29");
|
|
316 //span_log_set_level(&v29.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
|
|
317
|
|
318 if (t4_rx_init(&t4_state, "fax_decode.tif", T4_COMPRESSION_ITU_T4_2D))
|
|
319 {
|
|
320 printf("Failed to init\n");
|
|
321 exit(0);
|
|
322 }
|
|
323
|
|
324 for (;;)
|
|
325 {
|
|
326 len = afReadFrames(inhandle, AF_DEFAULT_TRACK, amp, SAMPLES_PER_CHUNK);
|
|
327 if (len < SAMPLES_PER_CHUNK)
|
|
328 break;
|
|
329 fsk_rx(&fsk, amp, len);
|
|
330 #if defined(ENABLE_V17)
|
|
331 v17_rx(&v17, amp, len);
|
|
332 #endif
|
|
333 v29_rx(&v29, amp, len);
|
|
334 v27ter_rx(&v27ter, amp, len);
|
|
335 }
|
|
336 t4_rx_end(&t4_state);
|
|
337
|
|
338 if (afCloseFile(inhandle) != 0)
|
|
339 {
|
|
340 fprintf(stderr, " Cannot close wave file '%s'\n", filename);
|
|
341 exit(2);
|
|
342 }
|
|
343 return 0;
|
|
344 }
|
|
345 /*- End of function --------------------------------------------------------*/
|
|
346 /*- End of file ------------------------------------------------------------*/
|