Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/tests/g722_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 * g722_tests.c - Test G.722 encode and decode. | |
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: g722_tests.c,v 1.17 2006/11/19 14:07:27 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 /*! \page g722_tests_page G.722 tests | |
31 \section g722_tests_page_sec_1 What does it do? | |
32 This modules implements two sets of tests: | |
33 - The tests defined in the G.722 specification, using the test data files supplied | |
34 with the specification. | |
35 - A generally audio quality test, consisting of compressing and decompressing a speeech | |
36 file for audible comparison. | |
37 | |
38 The speech file should be recorded at 16 bits/sample, 16000 samples/second, and named | |
39 "pre_g722.wav". | |
40 | |
41 The ITU tests use the codec in a special mode, in which the QMFs, which split and recombine the | |
42 sub-bands, are disabled. This means they do not test 100% of the codec. This is the reason for | |
43 including the additional listening test. | |
44 | |
45 \section g722_tests_page_sec_2 How is it used? | |
46 To perform the tests in the G.722 specification you need to obtain the test data files from the | |
47 specification. These are copyright material, and so cannot be distributed with spandsp. | |
48 | |
49 The files, containing test vectors, which are supplied with the G.722 specification, should be | |
50 copied to itutests/g722. The ITU tests can then be run by executing g722_tests without | |
51 any parameters. | |
52 | |
53 To perform a general audio quality test, g722_tests should be run with a parameter specifying | |
54 the required bit rate for compression. The valid parameters are "-48", "-56", and "-64". | |
55 The file ../localtests/short_wb_voice.wav will be compressed to the specified bit rate, decompressed, | |
56 and the resulting audio stored in post_g722.wav. | |
57 */ | |
58 | |
59 #ifdef HAVE_CONFIG_H | |
60 #include <config.h> | |
61 #endif | |
62 | |
63 #include <stdlib.h> | |
64 #include <unistd.h> | |
65 #include <stdio.h> | |
66 #include <fcntl.h> | |
67 #include <inttypes.h> | |
68 #include <memory.h> | |
69 #include <stdlib.h> | |
70 #if defined(HAVE_TGMATH_H) | |
71 #include <tgmath.h> | |
72 #endif | |
73 #if defined(HAVE_MATH_H) | |
74 #include <math.h> | |
75 #endif | |
76 #include <audiofile.h> | |
77 #include <ctype.h> | |
78 #include <tiffio.h> | |
79 | |
80 #include "spandsp.h" | |
81 | |
82 #define G722_SAMPLE_RATE 16000 | |
83 | |
84 #define BLOCK_LEN 320 | |
85 | |
86 #define MAX_TEST_VECTOR_LEN 40000 | |
87 | |
88 #define TESTDATA_DIR "../itutests/g722/" | |
89 | |
90 #define EIGHTK_IN_FILE_NAME "../localtests/short_nb_voice.wav" | |
91 #define IN_FILE_NAME "../localtests/short_wb_voice.wav" | |
92 #define OUT_FILE_NAME "post_g722.wav" | |
93 | |
94 #if 0 | |
95 static const char *itu_test_files[] = | |
96 { | |
97 TESTDATA_DIR "T1C1.XMT", /* 69973 bytes */ | |
98 TESTDATA_DIR "T1C2.XMT", /* 3605 bytes */ | |
99 TESTDATA_DIR "T1D3.COD", /* 69973 bytes */ | |
100 | |
101 TESTDATA_DIR "T2R1.COD", /* 69973 bytes */ | |
102 TESTDATA_DIR "T2R2.COD", /* 3605 bytes */ | |
103 | |
104 TESTDATA_DIR "T3L1.RC1", /* 69973 bytes */ | |
105 TESTDATA_DIR "T3L1.RC2", /* 69973 bytes */ | |
106 TESTDATA_DIR "T3L1.RC3", /* 69973 bytes */ | |
107 TESTDATA_DIR "T3H1.RC0", /* 69973 bytes */ | |
108 TESTDATA_DIR "T3L2.RC1", /* 3605 bytes */ | |
109 TESTDATA_DIR "T3L2.RC2", /* 3605 bytes */ | |
110 TESTDATA_DIR "T3L2.RC3", /* 3605 bytes */ | |
111 TESTDATA_DIR "T3H2.RC0", /* 3605 bytes */ | |
112 TESTDATA_DIR "T3L3.RC1", /* 69973 bytes */ | |
113 TESTDATA_DIR "T3L3.RC2", /* 69973 bytes */ | |
114 TESTDATA_DIR "T3L3.RC3", /* 69973 bytes */ | |
115 TESTDATA_DIR "T3H3.RC0" /* 69973 bytes */ | |
116 }; | |
117 #endif | |
118 | |
119 static const char *encode_test_files[] = | |
120 { | |
121 TESTDATA_DIR "T1C1.XMT", TESTDATA_DIR "T2R1.COD", | |
122 TESTDATA_DIR "T1C2.XMT", TESTDATA_DIR "T2R2.COD", | |
123 NULL | |
124 }; | |
125 | |
126 static const char *decode_test_files[] = | |
127 { | |
128 TESTDATA_DIR "T2R1.COD", | |
129 TESTDATA_DIR "T3L1.RC1", | |
130 TESTDATA_DIR "T3L1.RC2", | |
131 TESTDATA_DIR "T3L1.RC3", | |
132 TESTDATA_DIR "T3H1.RC0", | |
133 | |
134 TESTDATA_DIR "T2R2.COD", | |
135 TESTDATA_DIR "T3L2.RC1", | |
136 TESTDATA_DIR "T3L2.RC2", | |
137 TESTDATA_DIR "T3L2.RC3", | |
138 TESTDATA_DIR "T3H2.RC0", | |
139 | |
140 TESTDATA_DIR "T1D3.COD", | |
141 TESTDATA_DIR "T3L3.RC1", | |
142 TESTDATA_DIR "T3L3.RC2", | |
143 TESTDATA_DIR "T3L3.RC3", | |
144 TESTDATA_DIR "T3H3.RC0", | |
145 | |
146 NULL | |
147 }; | |
148 | |
149 int16_t itu_data[MAX_TEST_VECTOR_LEN]; | |
150 uint16_t itu_ref[MAX_TEST_VECTOR_LEN]; | |
151 uint16_t itu_ref_upper[MAX_TEST_VECTOR_LEN]; | |
152 uint8_t compressed[MAX_TEST_VECTOR_LEN]; | |
153 int16_t decompressed[MAX_TEST_VECTOR_LEN]; | |
154 | |
155 static int hex_get(char *s) | |
156 { | |
157 int i; | |
158 int value; | |
159 int x; | |
160 | |
161 for (value = i = 0; i < 4; i++) | |
162 { | |
163 x = *s++ - 0x30; | |
164 if (x > 9) | |
165 x -= 0x07; | |
166 if (x > 15) | |
167 x -= 0x20; | |
168 if (x < 0 || x > 15) | |
169 return -1; | |
170 value <<= 4; | |
171 value |= x; | |
172 } | |
173 return value; | |
174 } | |
175 /*- End of function --------------------------------------------------------*/ | |
176 | |
177 static int get_vector(FILE *file, uint16_t vec[]) | |
178 { | |
179 char buf[132 + 1]; | |
180 char *s; | |
181 int i; | |
182 int value; | |
183 | |
184 while (fgets(buf, 133, file)) | |
185 { | |
186 if (buf[0] == '/' && buf[1] == '*') | |
187 continue; | |
188 s = buf; | |
189 i = 0; | |
190 while ((value = hex_get(s)) >= 0) | |
191 { | |
192 vec[i++] = value; | |
193 s += 4; | |
194 } | |
195 return i; | |
196 } | |
197 return 0; | |
198 } | |
199 /*- End of function --------------------------------------------------------*/ | |
200 | |
201 static int get_test_vector(const char *file, uint16_t buf[], int max_len) | |
202 { | |
203 int octets; | |
204 int i; | |
205 FILE *infile; | |
206 | |
207 if ((infile = fopen(file, "r")) == NULL) | |
208 { | |
209 fprintf(stderr, " Failed to open '%s'\n", file); | |
210 exit(2); | |
211 } | |
212 octets = 0; | |
213 while ((i = get_vector(infile, buf + octets)) > 0) | |
214 octets += i; | |
215 fclose(infile); | |
216 return octets; | |
217 } | |
218 /*- End of function --------------------------------------------------------*/ | |
219 | |
220 int main(int argc, char *argv[]) | |
221 { | |
222 g722_encode_state_t enc_state; | |
223 g722_decode_state_t dec_state; | |
224 int len; | |
225 int len_comp; | |
226 int len_comp_upper; | |
227 int len_data; | |
228 int len2; | |
229 int len3; | |
230 int i; | |
231 int j; | |
232 int k; | |
233 int file; | |
234 AFfilehandle inhandle; | |
235 AFfilehandle outhandle; | |
236 AFfilesetup filesetup; | |
237 int outframes; | |
238 int samples; | |
239 int mode; | |
240 int itutests; | |
241 int bit_rate; | |
242 int eight_k_in; | |
243 int eight_k_out; | |
244 float x; | |
245 int16_t indata[BLOCK_LEN]; | |
246 int16_t outdata[BLOCK_LEN]; | |
247 uint8_t adpcmdata[BLOCK_LEN]; | |
248 | |
249 i = 1; | |
250 bit_rate = 64000; | |
251 eight_k_in = FALSE; | |
252 eight_k_out = FALSE; | |
253 itutests = TRUE; | |
254 while (argc > i) | |
255 { | |
256 if (strcmp(argv[i], "-48") == 0) | |
257 { | |
258 bit_rate = 48000; | |
259 itutests = FALSE; | |
260 i++; | |
261 } | |
262 else if (strcmp(argv[i], "-56") == 0) | |
263 { | |
264 bit_rate = 56000; | |
265 itutests = FALSE; | |
266 i++; | |
267 } | |
268 else if (strcmp(argv[i], "-64") == 0) | |
269 { | |
270 bit_rate = 64000; | |
271 itutests = FALSE; | |
272 i++; | |
273 } | |
274 else if (strcmp(argv[i], "-8k8k") == 0) | |
275 { | |
276 eight_k_in = TRUE; | |
277 eight_k_out = TRUE; | |
278 i++; | |
279 } | |
280 else if (strcmp(argv[i], "-8k16k") == 0) | |
281 { | |
282 eight_k_in = TRUE; | |
283 eight_k_out = FALSE; | |
284 i++; | |
285 } | |
286 else if (strcmp(argv[i], "-16k8k") == 0) | |
287 { | |
288 eight_k_in = FALSE; | |
289 eight_k_out = TRUE; | |
290 i++; | |
291 } | |
292 else if (strcmp(argv[i], "-16k16k") == 0) | |
293 { | |
294 eight_k_in = FALSE; | |
295 eight_k_out = FALSE; | |
296 i++; | |
297 } | |
298 else | |
299 { | |
300 fprintf(stderr, "Unknown parameter %s specified.\n", argv[i]); | |
301 exit(2); | |
302 } | |
303 } | |
304 | |
305 if (itutests) | |
306 { | |
307 /* ITU G.722 encode tests, using configuration 1. The QMF is bypassed */ | |
308 for (file = 0; encode_test_files[file]; file += 2) | |
309 { | |
310 printf("Testing %s -> %s\n", encode_test_files[file], encode_test_files[file + 1]); | |
311 | |
312 /* Get the input data */ | |
313 len_data = get_test_vector(encode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN); | |
314 | |
315 /* Get the reference output data */ | |
316 len_comp = get_test_vector(encode_test_files[file + 1], itu_ref, MAX_TEST_VECTOR_LEN); | |
317 | |
318 /* Process the input data */ | |
319 /* Skip the reset stuff at each end of the data */ | |
320 for (i = 0; i < len_data; i++) | |
321 { | |
322 if ((itu_data[i] & 1) == 0) | |
323 break; | |
324 } | |
325 for (j = i; j < len_data; j++) | |
326 { | |
327 if ((itu_data[j] & 1)) | |
328 break; | |
329 } | |
330 len = j - i; | |
331 g722_encode_init(&enc_state, 64000, FALSE); | |
332 enc_state.itu_test_mode = TRUE; | |
333 len2 = g722_encode(&enc_state, compressed, itu_data + i, len); | |
334 | |
335 /* Check the result against the ITU's reference output data */ | |
336 j = 0; | |
337 for (k = 0; k < len2; k++) | |
338 { | |
339 if ((compressed[k] & 0xFF) != ((itu_ref[k + i] >> 8) & 0xFF)) | |
340 { | |
341 printf(">>> %6d %4x %4x\n", k, compressed[k] & 0xFF, itu_ref[k + i] & 0xFFFF); | |
342 j++; | |
343 } | |
344 } | |
345 printf("%d bad samples, out of %d/%d samples\n", j, len, len_data); | |
346 if (j) | |
347 { | |
348 printf("Test failed\n"); | |
349 exit(2); | |
350 } | |
351 printf("Test passed\n"); | |
352 } | |
353 | |
354 /* ITU G.722 decode tests, using configuration 2. The QMF is bypassed */ | |
355 /* Run each of the tests for each of the modes - 48kbps, 56kbps and 64kbps. */ | |
356 for (mode = 1; mode <= 3; mode++) | |
357 { | |
358 for (file = 0; decode_test_files[file]; file += 5) | |
359 { | |
360 printf("Testing mode %d, %s -> %s + %s\n", | |
361 mode, | |
362 decode_test_files[file], | |
363 decode_test_files[file + mode], | |
364 decode_test_files[file + 4]); | |
365 | |
366 /* Get the input data */ | |
367 len_data = get_test_vector(decode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN); | |
368 | |
369 /* Get the lower reference output data */ | |
370 len_comp = get_test_vector(decode_test_files[file + mode], itu_ref, MAX_TEST_VECTOR_LEN); | |
371 | |
372 /* Get the upper reference output data */ | |
373 len_comp_upper = get_test_vector(decode_test_files[file + 4], itu_ref_upper, MAX_TEST_VECTOR_LEN); | |
374 | |
375 /* Process the input data */ | |
376 /* Skip the reset stuff at each end of the data */ | |
377 for (i = 0; i < len_data; i++) | |
378 { | |
379 if ((itu_data[i] & 1) == 0) | |
380 break; | |
381 } | |
382 for (j = i; j < len_data; j++) | |
383 { | |
384 if ((itu_data[j] & 1)) | |
385 break; | |
386 } | |
387 len = j - i; | |
388 for (k = 0; k < len; k++) | |
389 compressed[k] = itu_data[k + i] >> ((mode == 3) ? 10 : (mode == 2) ? 9 : 8); | |
390 | |
391 g722_decode_init(&dec_state, (mode == 3) ? 48000 : (mode == 2) ? 56000 : 64000, FALSE); | |
392 dec_state.itu_test_mode = TRUE; | |
393 len2 = g722_decode(&dec_state, decompressed, compressed, len); | |
394 | |
395 /* Check the result against the ITU's reference output data */ | |
396 j = 0; | |
397 for (k = 0; k < len2; k += 2) | |
398 { | |
399 if ((decompressed[k] & 0xFFFF) != (itu_ref[(k >> 1) + i] & 0xFFFF) | |
400 || | |
401 (decompressed[k + 1] & 0xFFFF) != (itu_ref_upper[(k >> 1) + i] & 0xFFFF)) | |
402 { | |
403 printf(">>> %6d %4x %4x %4x %4x\n", k >> 1, decompressed[k] & 0xFFFF, decompressed[k + 1] & 0xFFFF, itu_ref[(k >> 1) + i] & 0xFFFF, itu_ref_upper[(k >> 1) + i] & 0xFFFF); | |
404 j++; | |
405 } | |
406 } | |
407 printf("%d bad samples, out of %d/%d samples\n", j, len, len_data); | |
408 if (j) | |
409 { | |
410 printf("Test failed\n"); | |
411 exit(2); | |
412 } | |
413 printf("Test passed\n"); | |
414 } | |
415 } | |
416 | |
417 printf("Tests passed.\n"); | |
418 } | |
419 else | |
420 { | |
421 if (eight_k_in) | |
422 { | |
423 if ((inhandle = afOpenFile(EIGHTK_IN_FILE_NAME, "r", NULL)) == AF_NULL_FILEHANDLE) | |
424 { | |
425 fprintf(stderr, " Cannot open wave file '%s'\n", EIGHTK_IN_FILE_NAME); | |
426 exit(2); | |
427 } | |
428 if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) | |
429 { | |
430 printf(" Unexpected frame size in wave file '%s'\n", EIGHTK_IN_FILE_NAME); | |
431 exit(2); | |
432 } | |
433 if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) | |
434 { | |
435 printf(" Unexpected sample rate %f in wave file '%s'\n", x, EIGHTK_IN_FILE_NAME); | |
436 exit(2); | |
437 } | |
438 if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) | |
439 { | |
440 printf(" Unexpected number of channels in wave file '%s'\n", EIGHTK_IN_FILE_NAME); | |
441 exit(2); | |
442 } | |
443 } | |
444 else | |
445 { | |
446 if ((inhandle = afOpenFile(IN_FILE_NAME, "r", NULL)) == AF_NULL_FILEHANDLE) | |
447 { | |
448 fprintf(stderr, " Cannot open wave file '%s'\n", IN_FILE_NAME); | |
449 exit(2); | |
450 } | |
451 if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) | |
452 { | |
453 printf(" Unexpected frame size in wave file '%s'\n", IN_FILE_NAME); | |
454 exit(2); | |
455 } | |
456 if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) G722_SAMPLE_RATE) | |
457 { | |
458 printf(" Unexpected sample rate %f in wave file '%s'\n", x, IN_FILE_NAME); | |
459 exit(2); | |
460 } | |
461 if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) | |
462 { | |
463 printf(" Unexpected number of channels in wave file '%s'\n", IN_FILE_NAME); | |
464 exit(2); | |
465 } | |
466 } | |
467 | |
468 if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) | |
469 { | |
470 fprintf(stderr, " Failed to create file setup\n"); | |
471 exit(2); | |
472 } | |
473 afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); | |
474 if (eight_k_out) | |
475 afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); | |
476 else | |
477 afInitRate(filesetup, AF_DEFAULT_TRACK, (float) G722_SAMPLE_RATE); | |
478 afInitFileFormat(filesetup, AF_FILE_WAVE); | |
479 afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); | |
480 if ((outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE) | |
481 { | |
482 fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); | |
483 exit(2); | |
484 } | |
485 if (eight_k_in) | |
486 g722_encode_init(&enc_state, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000); | |
487 else | |
488 g722_encode_init(&enc_state, bit_rate, G722_PACKED); | |
489 if (eight_k_out) | |
490 g722_decode_init(&dec_state, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000); | |
491 else | |
492 g722_decode_init(&dec_state, bit_rate, G722_PACKED); | |
493 for (;;) | |
494 { | |
495 samples = afReadFrames(inhandle, | |
496 AF_DEFAULT_TRACK, | |
497 indata, | |
498 BLOCK_LEN); | |
499 if (samples <= 0) | |
500 break; | |
501 len2 = g722_encode(&enc_state, adpcmdata, indata, samples); | |
502 len3 = g722_decode(&dec_state, outdata, adpcmdata, len2); | |
503 outframes = afWriteFrames(outhandle, | |
504 AF_DEFAULT_TRACK, | |
505 outdata, | |
506 len3); | |
507 if (outframes != len3) | |
508 { | |
509 fprintf(stderr, " Error writing wave file\n"); | |
510 exit(2); | |
511 } | |
512 } | |
513 if (afCloseFile(inhandle)) | |
514 { | |
515 fprintf(stderr, " Cannot close wave file '%s'\n", IN_FILE_NAME); | |
516 exit(2); | |
517 } | |
518 if (afCloseFile(outhandle)) | |
519 { | |
520 fprintf(stderr, " Cannot close wave file '%s'\n", OUT_FILE_NAME); | |
521 exit(2); | |
522 } | |
523 afFreeFileSetup(filesetup); | |
524 | |
525 printf("'%s' transcoded to '%s' at %dbps.\n", IN_FILE_NAME, OUT_FILE_NAME, bit_rate); | |
526 } | |
527 return 0; | |
528 } | |
529 /*- End of function --------------------------------------------------------*/ | |
530 /*- End of file ------------------------------------------------------------*/ |