comparison spandsp-0.0.6pre17/tests/g711_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 * g711_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: g711_tests.c,v 1.17 2009/05/30 15:23:13 steveu Exp $
26 */
27
28 /*! \page g711_tests_page A-law and u-law conversion tests
29 \section g711_tests_page_sec_1 What does it do?
30
31 \section g711_tests_page_sec_2 How is it used?
32 */
33
34 #if defined(HAVE_CONFIG_H)
35 #include "config.h"
36 #endif
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <sndfile.h>
44
45 //#if defined(WITH_SPANDSP_INTERNALS)
46 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
47 //#endif
48
49 #include "spandsp.h"
50 #include "spandsp-sim.h"
51
52 #define BLOCK_LEN 160
53
54 #define IN_FILE_NAME "../test-data/local/short_nb_voice.wav"
55 #define ENCODED_FILE_NAME "g711.g711"
56 #define OUT_FILE_NAME "post_g711.wav"
57
58 int16_t amp[65536];
59 uint8_t ulaw_data[65536];
60 uint8_t alaw_data[65536];
61
62 const uint8_t alaw_1khz_sine[] = {0x34, 0x21, 0x21, 0x34, 0xB4, 0xA1, 0xA1, 0xB4};
63 const uint8_t ulaw_1khz_sine[] = {0x1E, 0x0B, 0x0B, 0x1E, 0x9E, 0x8B, 0x8B, 0x9E};
64
65 static void compliance_tests(int log_audio)
66 {
67 SNDFILE *outhandle;
68 power_meter_t power_meter;
69 int outframes;
70 int i;
71 int block;
72 int pre;
73 int post;
74 int post_post;
75 int alaw_failures;
76 int ulaw_failures;
77 float worst_alaw;
78 float worst_ulaw;
79 float tmp;
80 int len;
81 g711_state_t *enc_state;
82 g711_state_t *transcode;
83 g711_state_t *dec_state;
84
85 outhandle = NULL;
86 if (log_audio)
87 {
88 if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL)
89 {
90 fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
91 exit(2);
92 }
93 }
94
95 printf("Conversion accuracy tests.\n");
96 alaw_failures = 0;
97 ulaw_failures = 0;
98 worst_alaw = 0.0;
99 worst_ulaw = 0.0;
100 for (block = 0; block < 1; block++)
101 {
102 for (i = 0; i < 65536; i++)
103 {
104 pre = i - 32768;
105 post = alaw_to_linear(linear_to_alaw(pre));
106 if (abs(pre) > 140)
107 {
108 tmp = (float) abs(post - pre)/(float) abs(pre);
109 if (tmp > 0.10)
110 {
111 printf("A-law: Excessive error at %d (%d)\n", pre, post);
112 alaw_failures++;
113 }
114 if (tmp > worst_alaw)
115 worst_alaw = tmp;
116 }
117 else
118 {
119 /* Small values need different handling for sensible measurement */
120 if (abs(post - pre) > 15)
121 {
122 printf("A-law: Excessive error at %d (%d)\n", pre, post);
123 alaw_failures++;
124 }
125 }
126 amp[i] = post;
127 }
128 if (log_audio)
129 {
130 outframes = sf_writef_short(outhandle, amp, 65536);
131 if (outframes != 65536)
132 {
133 fprintf(stderr, " Error writing audio file\n");
134 exit(2);
135 }
136 }
137 for (i = 0; i < 65536; i++)
138 {
139 pre = i - 32768;
140 post = ulaw_to_linear(linear_to_ulaw(pre));
141 if (abs(pre) > 40)
142 {
143 tmp = (float) abs(post - pre)/(float) abs(pre);
144 if (tmp > 0.10)
145 {
146 printf("u-law: Excessive error at %d (%d)\n", pre, post);
147 ulaw_failures++;
148 }
149 if (tmp > worst_ulaw)
150 worst_ulaw = tmp;
151 }
152 else
153 {
154 /* Small values need different handling for sensible measurement */
155 if (abs(post - pre) > 4)
156 {
157 printf("u-law: Excessive error at %d (%d)\n", pre, post);
158 ulaw_failures++;
159 }
160 }
161 amp[i] = post;
162 }
163 if (log_audio)
164 {
165 outframes = sf_writef_short(outhandle, amp, 65536);
166 if (outframes != 65536)
167 {
168 fprintf(stderr, " Error writing audio file\n");
169 exit(2);
170 }
171 }
172 }
173 printf("Worst A-law error (ignoring small values) %f%%\n", worst_alaw*100.0);
174 printf("Worst u-law error (ignoring small values) %f%%\n", worst_ulaw*100.0);
175 if (alaw_failures || ulaw_failures)
176 {
177 printf("%d A-law values with excessive error\n", alaw_failures);
178 printf("%d u-law values with excessive error\n", ulaw_failures);
179 printf("Tests failed\n");
180 exit(2);
181 }
182
183 printf("Cyclic conversion repeatability tests.\n");
184 /* Find what happens to every possible linear value after a round trip. */
185 for (i = 0; i < 65536; i++)
186 {
187 pre = i - 32768;
188 /* Make a round trip */
189 post = alaw_to_linear(linear_to_alaw(pre));
190 /* A second round trip should cause no further change */
191 post_post = alaw_to_linear(linear_to_alaw(post));
192 if (post_post != post)
193 {
194 printf("A-law second round trip mismatch - at %d, %d != %d\n", pre, post, post_post);
195 printf("Tests failed\n");
196 exit(2);
197 }
198 /* Make a round trip */
199 post = ulaw_to_linear(linear_to_ulaw(pre));
200 /* A second round trip should cause no further change */
201 post_post = ulaw_to_linear(linear_to_ulaw(post));
202 if (post_post != post)
203 {
204 printf("u-law round trip mismatch - at %d, %d != %d\n", pre, post, post_post);
205 printf("Tests failed\n");
206 exit(2);
207 }
208 }
209
210 printf("Reference power level tests.\n");
211 power_meter_init(&power_meter, 7);
212
213 for (i = 0; i < 8000; i++)
214 {
215 amp[i] = ulaw_to_linear(ulaw_1khz_sine[i & 7]);
216 power_meter_update(&power_meter, amp[i]);
217 }
218 printf("Reference u-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter));
219 if (log_audio)
220 {
221 outframes = sf_writef_short(outhandle, amp, 8000);
222 if (outframes != 8000)
223 {
224 fprintf(stderr, " Error writing audio file\n");
225 exit(2);
226 }
227 }
228 if (0.1f < fabs(power_meter_current_dbm0(&power_meter)))
229 {
230 printf("Test failed.\n");
231 exit(2);
232 }
233
234 for (i = 0; i < 8000; i++)
235 {
236 amp[i] = alaw_to_linear(alaw_1khz_sine[i & 7]);
237 power_meter_update(&power_meter, amp[i]);
238 }
239 printf("Reference A-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter));
240 if (log_audio)
241 {
242 outframes = sf_writef_short(outhandle, amp, 8000);
243 if (outframes != 8000)
244 {
245 fprintf(stderr, " Error writing audio file\n");
246 exit(2);
247 }
248 }
249 if (0.1f < fabs(power_meter_current_dbm0(&power_meter)))
250 {
251 printf("Test failed.\n");
252 exit(2);
253 }
254
255 /* Check the transcoding functions. */
256 printf("Testing transcoding A-law -> u-law -> A-law\n");
257 for (i = 0; i < 256; i++)
258 {
259 if (alaw_to_ulaw(ulaw_to_alaw(i)) != i)
260 {
261 if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1)
262 {
263 printf("u-law -> A-law -> u-law gave %d -> %d\n", i, alaw_to_ulaw(ulaw_to_alaw(i)));
264 printf("Test failed\n");
265 exit(2);
266 }
267 }
268 }
269
270 printf("Testing transcoding u-law -> A-law -> u-law\n");
271 for (i = 0; i < 256; i++)
272 {
273 if (ulaw_to_alaw(alaw_to_ulaw(i)) != i)
274 {
275 if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1)
276 {
277 printf("A-law -> u-law -> A-law gave %d -> %d\n", i, ulaw_to_alaw(alaw_to_ulaw(i)));
278 printf("Test failed\n");
279 exit(2);
280 }
281 }
282 }
283
284 enc_state = g711_init(NULL, G711_ALAW);
285 transcode = g711_init(NULL, G711_ALAW);
286 dec_state = g711_init(NULL, G711_ULAW);
287
288 len = 65536;
289 for (i = 0; i < len; i++)
290 amp[i] = i - 32768;
291 len = g711_encode(enc_state, alaw_data, amp, len);
292 len = g711_transcode(transcode, ulaw_data, alaw_data, len);
293 len = g711_decode(dec_state, amp, ulaw_data, len);
294 if (len != 65536)
295 {
296 printf("Block coding gave the wrong length - %d instead of %d\n", len, 65536);
297 printf("Test failed\n");
298 exit(2);
299 }
300 for (i = 0; i < len; i++)
301 {
302 pre = i - 32768;
303 post = amp[i];
304 if (abs(pre) > 140)
305 {
306 tmp = (float) abs(post - pre)/(float) abs(pre);
307 if (tmp > 0.10)
308 {
309 printf("Block: Excessive error at %d (%d)\n", pre, post);
310 exit(2);
311 }
312 }
313 else
314 {
315 /* Small values need different handling for sensible measurement */
316 if (abs(post - pre) > 15)
317 {
318 printf("Block: Excessive error at %d (%d)\n", pre, post);
319 exit(2);
320 }
321 }
322 }
323 g711_release(enc_state);
324 g711_release(transcode);
325 g711_release(dec_state);
326
327 if (log_audio)
328 {
329 if (sf_close(outhandle))
330 {
331 fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
332 exit(2);
333 }
334 }
335
336 printf("Tests passed.\n");
337 }
338 /*- End of function --------------------------------------------------------*/
339
340 int main(int argc, char *argv[])
341 {
342 SNDFILE *inhandle;
343 SNDFILE *outhandle;
344 int outframes;
345 int opt;
346 int samples;
347 int len2;
348 int len3;
349 int basic_tests;
350 int law;
351 int encode;
352 int decode;
353 int file;
354 const char *in_file;
355 const char *out_file;
356 g711_state_t *enc_state;
357 g711_state_t *dec_state;
358 int16_t indata[BLOCK_LEN];
359 int16_t outdata[BLOCK_LEN];
360 uint8_t g711data[BLOCK_LEN];
361
362 basic_tests = TRUE;
363 law = G711_ALAW;
364 encode = FALSE;
365 decode = FALSE;
366 in_file = NULL;
367 out_file = NULL;
368 while ((opt = getopt(argc, argv, "ad:e:l:u")) != -1)
369 {
370 switch (opt)
371 {
372 case 'a':
373 law = G711_ALAW;
374 basic_tests = FALSE;
375 break;
376 case 'd':
377 in_file = optarg;
378 basic_tests = FALSE;
379 decode = TRUE;
380 break;
381 case 'e':
382 in_file = optarg;
383 basic_tests = FALSE;
384 encode = TRUE;
385 break;
386 case 'l':
387 out_file = optarg;
388 break;
389 case 'u':
390 law = G711_ULAW;
391 basic_tests = FALSE;
392 break;
393 default:
394 //usage();
395 exit(2);
396 }
397 }
398
399 if (basic_tests)
400 {
401 compliance_tests(TRUE);
402 }
403 else
404 {
405 if (!decode && !encode)
406 {
407 decode =
408 encode = TRUE;
409 }
410 if (in_file == NULL)
411 {
412 in_file = (encode) ? IN_FILE_NAME : ENCODED_FILE_NAME;
413 }
414 if (out_file == NULL)
415 {
416 out_file = (decode) ? OUT_FILE_NAME : ENCODED_FILE_NAME;
417 }
418 inhandle = NULL;
419 outhandle = NULL;
420 file = -1;
421 enc_state = NULL;
422 dec_state = NULL;
423 if (encode)
424 {
425 if ((inhandle = sf_open_telephony_read(in_file, 1)) == NULL)
426 {
427 fprintf(stderr, " Cannot open audio file '%s'\n", in_file);
428 exit(2);
429 }
430 enc_state = g711_init(NULL, law);
431 }
432 else
433 {
434 if ((file = open(in_file, O_RDONLY)) < 0)
435 {
436 fprintf(stderr, " Failed to open '%s'\n", in_file);
437 exit(2);
438 }
439 }
440 if (decode)
441 {
442 if ((outhandle = sf_open_telephony_write(out_file, 1)) == NULL)
443 {
444 fprintf(stderr, " Cannot create audio file '%s'\n", out_file);
445 exit(2);
446 }
447 dec_state = g711_init(NULL, law);
448 }
449 else
450 {
451 if ((file = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
452 {
453 fprintf(stderr, " Failed to open '%s'\n", out_file);
454 exit(2);
455 }
456 }
457 for (;;)
458 {
459 if (encode)
460 {
461 samples = sf_readf_short(inhandle, indata, BLOCK_LEN);
462 if (samples <= 0)
463 break;
464 len2 = g711_encode(enc_state, g711data, indata, samples);
465 }
466 else
467 {
468 len2 = read(file, g711data, BLOCK_LEN);
469 if (len2 <= 0)
470 break;
471 }
472 if (decode)
473 {
474 len3 = g711_decode(dec_state, outdata, g711data, len2);
475 outframes = sf_writef_short(outhandle, outdata, len3);
476 if (outframes != len3)
477 {
478 fprintf(stderr, " Error writing audio file\n");
479 exit(2);
480 }
481 }
482 else
483 {
484 len3 = write(file, g711data, len2);
485 if (len3 <= 0)
486 break;
487 }
488 }
489 if (encode)
490 {
491 if (sf_close(inhandle))
492 {
493 fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME);
494 exit(2);
495 }
496 }
497 else
498 {
499 close(file);
500 }
501 if (decode)
502 {
503 if (sf_close(outhandle))
504 {
505 fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
506 exit(2);
507 }
508 }
509 else
510 {
511 close(file);
512 }
513 printf("'%s' translated to '%s' using %s.\n", in_file, out_file, (law == G711_ALAW) ? "A-law" : "u-law");
514 }
515 return 0;
516 }
517 /*- End of function --------------------------------------------------------*/
518 /*- End of file ------------------------------------------------------------*/

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