Mercurial > hg > audiostuff
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 ------------------------------------------------------------*/ |