Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/tests/v22bis_tests.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * v22bis_tests.c | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2004 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: v22bis_tests.c,v 1.37 2006/11/19 14:07:27 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \page v22bis_tests_page V.22bis modem tests | |
29 \section v22bis_tests_page_sec_1 What does it do? | |
30 These tests connect two V.22bis modems back to back, through a telephone line | |
31 model. BER testing is then used to evaluate performance under various line | |
32 conditions. | |
33 | |
34 If the appropriate GUI environment exists, the tests are built such that a visual | |
35 display of modem status is maintained. | |
36 | |
37 \section v22bis_tests_page_sec_2 How is it used? | |
38 */ | |
39 | |
40 #ifdef HAVE_CONFIG_H | |
41 #include "config.h" | |
42 #endif | |
43 | |
44 #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H) | |
45 #define ENABLE_GUI | |
46 #endif | |
47 | |
48 #include <inttypes.h> | |
49 #include <stdlib.h> | |
50 #include <stdio.h> | |
51 #include <fcntl.h> | |
52 #include <string.h> | |
53 #if defined(HAVE_TGMATH_H) | |
54 #include <tgmath.h> | |
55 #endif | |
56 #if defined(HAVE_MATH_H) | |
57 #include <math.h> | |
58 #endif | |
59 #include <assert.h> | |
60 #include <audiofile.h> | |
61 #include <tiffio.h> | |
62 | |
63 #include "spandsp.h" | |
64 #include "test_utils.h" | |
65 #include "line_model.h" | |
66 #if defined(ENABLE_GUI) | |
67 #include "modem_monitor.h" | |
68 #endif | |
69 | |
70 #define BLOCK_LEN 160 | |
71 | |
72 #define IN_FILE_NAME "v22bis_samp.wav" | |
73 #define OUT_FILE_NAME "v22bis.wav" | |
74 | |
75 int in_bit = 0; | |
76 int out_bit = 0; | |
77 | |
78 int in_bit_no = 0; | |
79 int out_bit_no = 0; | |
80 | |
81 uint8_t tx_buf[1000]; | |
82 int rx_ptr = 0; | |
83 int tx_ptr = 0; | |
84 | |
85 int rx_bits = 0; | |
86 int rx_bad_bits = 0; | |
87 | |
88 int use_gui = FALSE; | |
89 | |
90 both_ways_line_model_state_t *model; | |
91 | |
92 v22bis_state_t caller; | |
93 v22bis_state_t answerer; | |
94 | |
95 struct qam_report_control_s | |
96 { | |
97 v22bis_state_t *s; | |
98 #if defined(ENABLE_GUI) | |
99 qam_monitor_t *qam_monitor; | |
100 #endif | |
101 float smooth_power; | |
102 int symbol_no; | |
103 }; | |
104 | |
105 struct qam_report_control_s qam_caller; | |
106 struct qam_report_control_s qam_answerer; | |
107 | |
108 static void v22bis_putbit(void *user_data, int bit) | |
109 { | |
110 v22bis_state_t *s; | |
111 int i; | |
112 int len; | |
113 complexf_t *coeffs; | |
114 | |
115 s = (v22bis_state_t *) user_data; | |
116 if (bit < 0) | |
117 { | |
118 /* Special conditions */ | |
119 switch (bit) | |
120 { | |
121 case PUTBIT_TRAINING_FAILED: | |
122 printf("Training failed\n"); | |
123 break; | |
124 case PUTBIT_TRAINING_SUCCEEDED: | |
125 printf("Training succeeded\n"); | |
126 len = v22bis_rx_equalizer_state(s, &coeffs); | |
127 printf("Equalizer:\n"); | |
128 for (i = 0; i < len; i++) | |
129 printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); | |
130 break; | |
131 case PUTBIT_CARRIER_UP: | |
132 printf("Carrier up\n"); | |
133 break; | |
134 case PUTBIT_CARRIER_DOWN: | |
135 printf("Carrier down\n"); | |
136 break; | |
137 default: | |
138 printf("Eh!\n"); | |
139 break; | |
140 } | |
141 return; | |
142 } | |
143 | |
144 if (bit != tx_buf[rx_ptr]) | |
145 { | |
146 printf("Rx bit %d - %d\n", rx_bits, bit); | |
147 rx_bad_bits++; | |
148 } | |
149 rx_ptr++; | |
150 if (rx_ptr > 1000) | |
151 rx_ptr = 0; | |
152 rx_bits++; | |
153 if ((rx_bits % 100000) == 0) | |
154 { | |
155 printf("%d bits received, %d bad bits\r", rx_bits, rx_bad_bits); | |
156 fflush(stdout); | |
157 } | |
158 } | |
159 /*- End of function --------------------------------------------------------*/ | |
160 | |
161 static int v22bis_getbit(void *user_data) | |
162 { | |
163 int bit; | |
164 static int tx_bits = 0; | |
165 | |
166 bit = rand() & 1; | |
167 tx_buf[tx_ptr++] = bit; | |
168 if (tx_ptr > 1000) | |
169 tx_ptr = 0; | |
170 //printf("Tx bit %d\n", bit); | |
171 if (++tx_bits > 100000) | |
172 { | |
173 tx_bits = 0; | |
174 bit = 2; | |
175 } | |
176 return bit; | |
177 } | |
178 /*- End of function --------------------------------------------------------*/ | |
179 | |
180 static void qam_report(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol) | |
181 { | |
182 int i; | |
183 int len; | |
184 complexf_t *coeffs; | |
185 float fpower; | |
186 struct qam_report_control_s *s; | |
187 | |
188 s = (struct qam_report_control_s *) user_data; | |
189 if (constel) | |
190 { | |
191 #if defined(ENABLE_GUI) | |
192 if (use_gui) | |
193 { | |
194 qam_monitor_update_constel(s->qam_monitor, constel); | |
195 qam_monitor_update_carrier_tracking(s->qam_monitor, v22bis_rx_carrier_frequency(s->s)); | |
196 qam_monitor_update_symbol_tracking(s->qam_monitor, v22bis_rx_symbol_timing_correction(s->s)); | |
197 } | |
198 #endif | |
199 fpower = (constel->re - target->re)*(constel->re - target->re) | |
200 + (constel->im - target->im)*(constel->im - target->im); | |
201 s->smooth_power = 0.95*s->smooth_power + 0.05*fpower; | |
202 printf("%8d [%8.4f, %8.4f] [%8.4f, %8.4f] %8.4f %8.4f\n", s->symbol_no, constel->re, constel->im, target->re, target->im, fpower, s->smooth_power); | |
203 s->symbol_no++; | |
204 } | |
205 else | |
206 { | |
207 printf("Gardner step %d\n", symbol); | |
208 len = v22bis_rx_equalizer_state(s->s, &coeffs); | |
209 printf("Equalizer A:\n"); | |
210 for (i = 0; i < len; i++) | |
211 printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i])); | |
212 #if defined(ENABLE_GUI) | |
213 if (use_gui) | |
214 qam_monitor_update_equalizer(s->qam_monitor, coeffs, len); | |
215 #endif | |
216 } | |
217 } | |
218 /*- End of function --------------------------------------------------------*/ | |
219 | |
220 int main(int argc, char *argv[]) | |
221 { | |
222 int16_t caller_amp[BLOCK_LEN]; | |
223 int16_t answerer_amp[BLOCK_LEN]; | |
224 int16_t caller_model_amp[BLOCK_LEN]; | |
225 int16_t answerer_model_amp[BLOCK_LEN]; | |
226 int16_t out_amp[2*BLOCK_LEN]; | |
227 AFfilehandle outhandle; | |
228 AFfilesetup filesetup; | |
229 int outframes; | |
230 int samples; | |
231 int i; | |
232 int test_bps; | |
233 int line_model_no; | |
234 int bits_per_test; | |
235 int noise_level; | |
236 int signal_level; | |
237 int log_audio; | |
238 int channel_codec; | |
239 | |
240 channel_codec = MUNGE_CODEC_NONE; | |
241 test_bps = 2400; | |
242 line_model_no = 0; | |
243 noise_level = -70; | |
244 signal_level = -13; | |
245 bits_per_test = 50000; | |
246 log_audio = FALSE; | |
247 for (i = 1; i < argc; i++) | |
248 { | |
249 if (strcmp(argv[i], "-b") == 0) | |
250 { | |
251 bits_per_test = atoi(argv[++i]); | |
252 continue; | |
253 } | |
254 if (strcmp(argv[i], "-c") == 0) | |
255 { | |
256 channel_codec = atoi(argv[++i]); | |
257 continue; | |
258 } | |
259 if (strcmp(argv[i], "-g") == 0) | |
260 { | |
261 use_gui = TRUE; | |
262 continue; | |
263 } | |
264 if (strcmp(argv[i], "-m") == 0) | |
265 { | |
266 log_audio = TRUE; | |
267 continue; | |
268 } | |
269 if (strcmp(argv[i], "-m") == 0) | |
270 { | |
271 line_model_no = atoi(argv[++i]); | |
272 continue; | |
273 } | |
274 if (strcmp(argv[i], "-n") == 0) | |
275 { | |
276 noise_level = atoi(argv[++i]); | |
277 continue; | |
278 } | |
279 if (strcmp(argv[i], "-s") == 0) | |
280 { | |
281 signal_level = atoi(argv[++i]); | |
282 continue; | |
283 } | |
284 if (strcmp(argv[i], "2400") == 0) | |
285 test_bps = 2400; | |
286 else if (strcmp(argv[i], "1200") == 0) | |
287 test_bps = 1200; | |
288 else | |
289 { | |
290 fprintf(stderr, "Invalid bit rate\n"); | |
291 exit(2); | |
292 } | |
293 } | |
294 filesetup = AF_NULL_FILESETUP; | |
295 outhandle = AF_NULL_FILEHANDLE; | |
296 if (log_audio) | |
297 { | |
298 if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) | |
299 { | |
300 fprintf(stderr, " Failed to create file setup\n"); | |
301 exit(2); | |
302 } | |
303 afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); | |
304 afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); | |
305 afInitFileFormat(filesetup, AF_FILE_WAVE); | |
306 afInitChannels(filesetup, AF_DEFAULT_TRACK, 2); | |
307 | |
308 if ((outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE) | |
309 { | |
310 fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); | |
311 exit(2); | |
312 } | |
313 } | |
314 v22bis_init(&caller, test_bps, 2, TRUE, v22bis_getbit, v22bis_putbit, &caller); | |
315 v22bis_tx_power(&caller, signal_level); | |
316 /* Move the carrier off a bit */ | |
317 caller.tx_carrier_phase_rate = dds_phase_ratef(1207.0); | |
318 v22bis_init(&answerer, test_bps, 2, FALSE, v22bis_getbit, v22bis_putbit, &answerer); | |
319 v22bis_tx_power(&answerer, signal_level); | |
320 answerer.tx_carrier_phase_rate = dds_phase_ratef(2407.0); | |
321 v22bis_rx_set_qam_report_handler(&caller, qam_report, (void *) &qam_caller); | |
322 v22bis_rx_set_qam_report_handler(&answerer, qam_report, (void *) &qam_answerer); | |
323 span_log_set_level(&caller.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); | |
324 span_log_set_tag(&caller.logging, "caller"); | |
325 span_log_set_level(&answerer.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); | |
326 span_log_set_tag(&answerer.logging, "answerer"); | |
327 | |
328 qam_caller.s = &caller; | |
329 qam_caller.smooth_power = 0.0; | |
330 qam_caller.symbol_no = 0; | |
331 | |
332 qam_answerer.s = &answerer; | |
333 qam_answerer.smooth_power = 0.0; | |
334 qam_answerer.symbol_no = 0; | |
335 | |
336 #if defined(ENABLE_GUI) | |
337 if (use_gui) | |
338 { | |
339 qam_caller.qam_monitor = qam_monitor_init(6.0, "Calling modem"); | |
340 qam_answerer.qam_monitor = qam_monitor_init(6.0, "Answering modem"); | |
341 } | |
342 #endif | |
343 | |
344 if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, (float) noise_level, channel_codec)) == NULL) | |
345 { | |
346 fprintf(stderr, " Failed to create line model\n"); | |
347 exit(2); | |
348 } | |
349 for (;;) | |
350 { | |
351 samples = v22bis_tx(&caller, caller_amp, BLOCK_LEN); | |
352 #if defined(ENABLE_GUI) | |
353 if (use_gui) | |
354 qam_monitor_update_audio_level(qam_caller.qam_monitor, caller_amp, samples); | |
355 #endif | |
356 if (samples == 0) | |
357 { | |
358 printf("Restarting on zero output\n"); | |
359 v22bis_restart(&caller, test_bps); | |
360 rx_ptr = 0; | |
361 tx_ptr = 0; | |
362 } | |
363 | |
364 samples = v22bis_tx(&answerer, answerer_amp, BLOCK_LEN); | |
365 #if defined(ENABLE_GUI) | |
366 if (use_gui) | |
367 qam_monitor_update_audio_level(qam_answerer.qam_monitor, answerer_amp, samples); | |
368 #endif | |
369 if (samples == 0) | |
370 { | |
371 printf("Restarting on zero output\n"); | |
372 v22bis_restart(&answerer, test_bps); | |
373 rx_ptr = 0; | |
374 tx_ptr = 0; | |
375 } | |
376 | |
377 both_ways_line_model(model, | |
378 caller_model_amp, | |
379 caller_amp, | |
380 answerer_model_amp, | |
381 answerer_amp, | |
382 samples); | |
383 | |
384 v22bis_rx(&answerer, caller_model_amp, samples); | |
385 for (i = 0; i < samples; i++) | |
386 out_amp[2*i] = caller_model_amp[i]; | |
387 for ( ; i < BLOCK_LEN; i++) | |
388 out_amp[2*i] = 0; | |
389 | |
390 v22bis_rx(&caller, answerer_model_amp, samples); | |
391 for (i = 0; i < samples; i++) | |
392 out_amp[2*i + 1] = answerer_model_amp[i]; | |
393 for ( ; i < BLOCK_LEN; i++) | |
394 out_amp[2*i + 1] = 0; | |
395 | |
396 if (log_audio) | |
397 { | |
398 outframes = afWriteFrames(outhandle, | |
399 AF_DEFAULT_TRACK, | |
400 out_amp, | |
401 BLOCK_LEN); | |
402 if (outframes != BLOCK_LEN) | |
403 { | |
404 fprintf(stderr, " Error writing wave file\n"); | |
405 exit(2); | |
406 } | |
407 } | |
408 } | |
409 if (log_audio) | |
410 { | |
411 if (afCloseFile(outhandle) != 0) | |
412 { | |
413 fprintf(stderr, " Cannot close wave file '%s'\n", OUT_FILE_NAME); | |
414 exit(2); | |
415 } | |
416 afFreeFileSetup(filesetup); | |
417 } | |
418 return 0; | |
419 } | |
420 /*- End of function --------------------------------------------------------*/ | |
421 /*- End of file ------------------------------------------------------------*/ |