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
26 /*! \file */
27
28 /*! \page g722_tests_page G.722 tests
29 \section g722_tests_page_sec_1 What does it do?
30 This modules implements two sets of tests:
31 - The tests defined in the G.722 specification, using the test data files supplied
32 with the specification.
33 - A generally audio quality test, consisting of compressing and decompressing a speeech
34 file for audible comparison.
35
36 The speech file should be recorded at 16 bits/sample, 16000 samples/second, and named
37 "pre_g722.wav".
38
39 The ITU tests use the codec in a special mode, in which the QMFs, which split and recombine the
40 sub-bands, are disabled. This means they do not test 100% of the codec. This is the reason for
41 including the additional listening test.
42
43 \section g722_tests_page_sec_2 How is it used?
44 To perform the tests in the G.722 specification you need to obtain the test data files from the
45 specification. These are copyright material, and so cannot be distributed with this test software.
46
47 The files, containing test vectors, which are supplied with the G.722 specification, should be
48 copied to itutests/g722. The ITU tests can then be run by executing g722_tests without
49 any parameters.
50
51 To perform a general audio quality test, g722_tests should be run with a parameter specifying
52 the required bit rate for compression. The valid parameters are "-48", "-56", and "-64".
53 The file ../test-data/local/short_wb_voice.wav will be compressed to the specified bit rate, decompressed,
54 and the resulting audio stored in post_g722.wav.
55 */
56
57 #if defined(HAVE_CONFIG_H)
58 #include "config.h"
59 #endif
60
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <fcntl.h>
64 #include <unistd.h>
65 #include <memory.h>
66 #include <ctype.h>
67 #include <sndfile.h>
68
69 #include "spandsp.h"
70
71 #include "spandsp/private/g722.h"
72
73 #define G722_SAMPLE_RATE 16000
74
75 #define BLOCK_LEN 320
76
77 #define MAX_TEST_VECTOR_LEN 40000
78
79 #define TESTDATA_DIR "../test-data/itu/g722/"
80
81 #define EIGHTK_IN_FILE_NAME "../test-data/local/short_nb_voice.wav"
82 #define IN_FILE_NAME "../test-data/local/short_wb_voice.wav"
83 #define ENCODED_FILE_NAME "g722.g722"
84 #define OUT_FILE_NAME "post_g722.wav"
85
86 #if 0
87 static const char *itu_test_files[] =
88 {
89 TESTDATA_DIR "T1C1.XMT", /* 69973 bytes */
90 TESTDATA_DIR "T1C2.XMT", /* 3605 bytes */
91 TESTDATA_DIR "T1D3.COD", /* 69973 bytes */
92
93 TESTDATA_DIR "T2R1.COD", /* 69973 bytes */
94 TESTDATA_DIR "T2R2.COD", /* 3605 bytes */
95
96 TESTDATA_DIR "T3L1.RC1", /* 69973 bytes */
97 TESTDATA_DIR "T3L1.RC2", /* 69973 bytes */
98 TESTDATA_DIR "T3L1.RC3", /* 69973 bytes */
99 TESTDATA_DIR "T3H1.RC0", /* 69973 bytes */
100 TESTDATA_DIR "T3L2.RC1", /* 3605 bytes */
101 TESTDATA_DIR "T3L2.RC2", /* 3605 bytes */
102 TESTDATA_DIR "T3L2.RC3", /* 3605 bytes */
103 TESTDATA_DIR "T3H2.RC0", /* 3605 bytes */
104 TESTDATA_DIR "T3L3.RC1", /* 69973 bytes */
105 TESTDATA_DIR "T3L3.RC2", /* 69973 bytes */
106 TESTDATA_DIR "T3L3.RC3", /* 69973 bytes */
107 TESTDATA_DIR "T3H3.RC0" /* 69973 bytes */
108 };
109 #endif
110
111 static const char *encode_test_files[] =
112 {
113 TESTDATA_DIR "T1C1.XMT",
114 TESTDATA_DIR "T2R1.COD",
115 TESTDATA_DIR "T1C2.XMT",
116 TESTDATA_DIR "T2R2.COD",
117 NULL
118 };
119
120 static const char *decode_test_files[] =
121 {
122 TESTDATA_DIR "T2R1.COD",
123 TESTDATA_DIR "T3L1.RC1",
124 TESTDATA_DIR "T3L1.RC2",
125 TESTDATA_DIR "T3L1.RC3",
126 TESTDATA_DIR "T3H1.RC0",
127
128 TESTDATA_DIR "T2R2.COD",
129 TESTDATA_DIR "T3L2.RC1",
130 TESTDATA_DIR "T3L2.RC2",
131 TESTDATA_DIR "T3L2.RC3",
132 TESTDATA_DIR "T3H2.RC0",
133
134 TESTDATA_DIR "T1D3.COD",
135 TESTDATA_DIR "T3L3.RC1",
136 TESTDATA_DIR "T3L3.RC2",
137 TESTDATA_DIR "T3L3.RC3",
138 TESTDATA_DIR "T3H3.RC0",
139
140 NULL
141 };
142
143 int16_t itu_data[MAX_TEST_VECTOR_LEN];
144 uint16_t itu_ref[MAX_TEST_VECTOR_LEN];
145 uint16_t itu_ref_upper[MAX_TEST_VECTOR_LEN];
146 uint8_t compressed[MAX_TEST_VECTOR_LEN];
147 int16_t decompressed[MAX_TEST_VECTOR_LEN];
148
hex_get(char * s)149 static int hex_get(char *s)
150 {
151 int i;
152 int value;
153 int x;
154
155 for (value = i = 0; i < 4; i++)
156 {
157 x = *s++ - 0x30;
158 if (x > 9)
159 x -= 0x07;
160 if (x > 15)
161 x -= 0x20;
162 if (x < 0 || x > 15)
163 return -1;
164 value <<= 4;
165 value |= x;
166 }
167 return value;
168 }
169 /*- End of function --------------------------------------------------------*/
170
get_vector(FILE * file,uint16_t vec[])171 static int get_vector(FILE *file, uint16_t vec[])
172 {
173 char buf[132 + 1];
174 char *s;
175 int i;
176 int value;
177
178 while (fgets(buf, 133, file))
179 {
180 if (buf[0] == '/' && buf[1] == '*')
181 continue;
182 s = buf;
183 i = 0;
184 while ((value = hex_get(s)) >= 0)
185 {
186 vec[i++] = value;
187 s += 4;
188 }
189 return i;
190 }
191 return 0;
192 }
193 /*- End of function --------------------------------------------------------*/
194
get_test_vector(const char * file,uint16_t buf[],int max_len)195 static int get_test_vector(const char *file, uint16_t buf[], int max_len)
196 {
197 int octets;
198 int i;
199 FILE *infile;
200
201 if ((infile = fopen(file, "r")) == NULL)
202 {
203 fprintf(stderr, " Failed to open '%s'\n", file);
204 exit(2);
205 }
206 octets = 0;
207 while ((i = get_vector(infile, buf + octets)) > 0)
208 octets += i;
209 fclose(infile);
210 return octets;
211 }
212 /*- End of function --------------------------------------------------------*/
213
itu_compliance_tests(void)214 static void itu_compliance_tests(void)
215 {
216 g722_encode_state_t *enc_state;
217 g722_decode_state_t *dec_state;
218 int i;
219 int j;
220 int k;
221 int len_comp;
222 int len_comp_lower;
223 int len_comp_upper;
224 int len_data;
225 int len;
226 int len2;
227 int mode;
228 int file;
229
230 #if 1
231 /* ITU G.722 encode tests, using configuration 1. The QMF is bypassed */
232 for (file = 0; encode_test_files[file]; file += 2)
233 {
234 printf("Testing %s -> %s\n", encode_test_files[file], encode_test_files[file + 1]);
235
236 /* Get the input data */
237 len_data = get_test_vector(encode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN);
238
239 /* Get the reference output data */
240 len_comp = get_test_vector(encode_test_files[file + 1], itu_ref, MAX_TEST_VECTOR_LEN);
241
242 if (len_data != len_comp)
243 {
244 printf("Test data length mismatch\n");
245 exit(2);
246 }
247 /* Process the input data */
248 /* Skip the reset stuff at each end of the data */
249 for (i = 0; i < len_data; i++)
250 {
251 if ((itu_data[i] & 1) == 0)
252 break;
253 }
254 for (j = i; j < len_data; j++)
255 {
256 if ((itu_data[j] & 1))
257 break;
258 }
259 len = j - i;
260 enc_state = g722_encode_init(NULL, 64000, 0);
261 enc_state->itu_test_mode = true;
262 len2 = g722_encode(enc_state, compressed, itu_data + i, len);
263
264 /* Check the result against the ITU's reference output data */
265 j = 0;
266 for (k = 0; k < len2; k++)
267 {
268 if ((compressed[k] & 0xFF) != ((itu_ref[k + i] >> 8) & 0xFF))
269 {
270 printf(">>> %6d %4x %4x\n", k, compressed[k] & 0xFF, itu_ref[k + i] & 0xFFFF);
271 j++;
272 }
273 }
274 printf("%d bad samples, out of %d/%d samples\n", j, len, len_data);
275 if (j)
276 {
277 printf("Test failed\n");
278 exit(2);
279 }
280 printf("Test passed\n");
281 g722_encode_free(enc_state);
282 }
283 #endif
284 #if 1
285 /* ITU G.722 decode tests, using configuration 2. The QMF is bypassed */
286 /* Run each of the tests for each of the modes - 48kbps, 56kbps and 64kbps. */
287 for (mode = 1; mode <= 3; mode++)
288 {
289 for (file = 0; decode_test_files[file]; file += 5)
290 {
291 printf("Testing mode %d, %s -> %s + %s\n",
292 mode,
293 decode_test_files[file],
294 decode_test_files[file + mode],
295 decode_test_files[file + 4]);
296
297 /* Get the input data */
298 len_data = get_test_vector(decode_test_files[file], (uint16_t *) itu_data, MAX_TEST_VECTOR_LEN);
299
300 /* Get the lower reference output data */
301 len_comp_lower = get_test_vector(decode_test_files[file + mode], itu_ref, MAX_TEST_VECTOR_LEN);
302
303 /* Get the upper reference output data */
304 len_comp_upper = get_test_vector(decode_test_files[file + 4], itu_ref_upper, MAX_TEST_VECTOR_LEN);
305
306 if (len_data != len_comp_lower || len_data != len_comp_upper)
307 {
308 printf("Test data length mismatch\n");
309 exit(2);
310 }
311 /* Process the input data */
312 /* Skip the reset stuff at each end of the data */
313 for (i = 0; i < len_data; i++)
314 {
315 if ((itu_data[i] & 1) == 0)
316 break;
317 }
318 for (j = i; j < len_data; j++)
319 {
320 if ((itu_data[j] & 1))
321 break;
322 }
323 len = j - i;
324 for (k = 0; k < len; k++)
325 compressed[k] = itu_data[k + i] >> ((mode == 3) ? 10 : (mode == 2) ? 9 : 8);
326
327 dec_state = g722_decode_init(NULL, (mode == 3) ? 48000 : (mode == 2) ? 56000 : 64000, 0);
328 dec_state->itu_test_mode = true;
329 len2 = g722_decode(dec_state, decompressed, compressed, len);
330
331 /* Check the result against the ITU's reference output data */
332 j = 0;
333 for (k = 0; k < len2; k += 2)
334 {
335 if ((decompressed[k] & 0xFFFF) != (itu_ref[(k >> 1) + i] & 0xFFFF)
336 ||
337 (decompressed[k + 1] & 0xFFFF) != (itu_ref_upper[(k >> 1) + i] & 0xFFFF))
338 {
339 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);
340 j++;
341 }
342 }
343 printf("%d bad samples, out of %d/%d samples\n", j, len, len_data);
344 if (j)
345 {
346 printf("Test failed\n");
347 exit(2);
348 }
349 printf("Test passed\n");
350 g722_decode_free(dec_state);
351 }
352 }
353 #endif
354 printf("Tests passed.\n");
355 }
356 /*- End of function --------------------------------------------------------*/
357
signal_to_distortion_tests(void)358 static void signal_to_distortion_tests(void)
359 {
360 g722_encode_state_t *enc_state;
361 g722_decode_state_t *dec_state;
362 swept_tone_state_t *swept;
363 power_meter_t *in_meter;
364 power_meter_t *out_meter;
365 int16_t original[1024];
366 uint8_t compressed[1024];
367 int16_t decompressed[1024];
368 int len;
369 int len2;
370 int len3;
371 int i;
372 int32_t in_level;
373 int32_t out_level;
374
375 /* Test a back to back encoder/decoder pair to ensure we comply with Figure 11/G.722 to
376 Figure 16/G.722, Figure A.1/G.722, and Figure A.2/G.722 */
377 enc_state = g722_encode_init(NULL, 64000, 0);
378 dec_state = g722_decode_init(NULL, 64000, 0);
379 in_meter = power_meter_init(NULL, 7);
380 out_meter = power_meter_init(NULL, 7);
381
382 /* First some silence */
383 len = 1024;
384 memset(original, 0, len*sizeof(original[0]));
385 for (i = 0; i < len; i++)
386 in_level = power_meter_update(in_meter, original[i]);
387 len2 = g722_encode(enc_state, compressed, original, len);
388 len3 = g722_decode(dec_state, decompressed, compressed, len2);
389 out_level = 0;
390 for (i = 0; i < len3; i++)
391 out_level = power_meter_update(out_meter, decompressed[i]);
392 printf("Silence produces %d at the output\n", out_level);
393
394 /* Now a swept tone test */
395 swept = swept_tone_init(NULL, 25.0f, 3500.0f, -10.0f, 60*16000, false);
396 do
397 {
398 len = swept_tone(swept, original, 1024);
399 for (i = 0; i < len; i++)
400 in_level = power_meter_update(in_meter, original[i]);
401 len2 = g722_encode(enc_state, compressed, original, len);
402 len3 = g722_decode(dec_state, decompressed, compressed, len2);
403 for (i = 0; i < len3; i++)
404 out_level = power_meter_update(out_meter, decompressed[i]);
405 printf("%10d, %10d, %f\n", in_level, out_level, (float) out_level/in_level);
406 }
407 while (len > 0);
408 swept_tone_free(swept);
409 g722_encode_free(enc_state);
410 g722_decode_free(dec_state);
411 power_meter_free(in_meter);
412 power_meter_free(out_meter);
413 }
414 /*- End of function --------------------------------------------------------*/
415
main(int argc,char * argv[])416 int main(int argc, char *argv[])
417 {
418 g722_encode_state_t *enc_state;
419 g722_decode_state_t *dec_state;
420 int len2;
421 int len3;
422 int i;
423 int file;
424 SNDFILE *inhandle;
425 SNDFILE *outhandle;
426 SF_INFO info;
427 int outframes;
428 int samples;
429 int opt;
430 int itutests;
431 int bit_rate;
432 int eight_k_in;
433 int eight_k_out;
434 int encode;
435 int decode;
436 int tone_test;
437 const char *in_file;
438 const char *out_file;
439 int16_t indata[BLOCK_LEN];
440 int16_t outdata[BLOCK_LEN];
441 uint8_t adpcmdata[BLOCK_LEN];
442 float tone_level;
443 uint32_t tone_phase;
444 int32_t tone_phase_rate;
445
446 bit_rate = 64000;
447 eight_k_in = false;
448 eight_k_out = false;
449 itutests = true;
450 encode = false;
451 decode = false;
452 tone_test = false;
453 in_file = NULL;
454 out_file = NULL;
455 while ((opt = getopt(argc, argv, "b:d:e:i:l:o:t")) != -1)
456 {
457 switch (opt)
458 {
459 case 'b':
460 bit_rate = atoi(optarg);
461 if (bit_rate != 48000 && bit_rate != 56000 && bit_rate != 64000)
462 {
463 fprintf(stderr, "Invalid bit rate selected. Only 48000, 56000 and 64000 are valid.\n");
464 exit(2);
465 }
466 itutests = false;
467 break;
468 case 'd':
469 in_file = optarg;
470 decode = true;
471 itutests = false;
472 break;
473 case 'e':
474 in_file = optarg;
475 encode = true;
476 itutests = false;
477 break;
478 case 'i':
479 i = atoi(optarg);
480 if (i != 8000 && i != 16000)
481 {
482 fprintf(stderr, "Invalid incoming sample rate. Only 8000 and 16000 are valid.\n");
483 exit(2);
484 }
485 eight_k_in = (i == 8000);
486 if (eight_k_in)
487 in_file = EIGHTK_IN_FILE_NAME;
488 break;
489 case 'l':
490 out_file = optarg;
491 break;
492 case 'o':
493 i = atoi(optarg);
494 if (i != 8000 && i != 16000)
495 {
496 fprintf(stderr, "Invalid outgoing sample rate. Only 8000 and 16000 are valid.\n");
497 exit(2);
498 }
499 eight_k_out = (i == 8000);
500 break;
501 case 't':
502 tone_test = true;
503 itutests = false;
504 break;
505 default:
506 //usage();
507 exit(2);
508 }
509 }
510
511 if (itutests)
512 {
513 itu_compliance_tests();
514 signal_to_distortion_tests();
515 }
516 else
517 {
518 tone_level = dds_scaling_dbm0f(2.5f);
519 tone_phase = 0;
520 tone_phase_rate = dds_phase_ratef(1500.0f/2.0f);
521 if (!decode && !encode)
522 {
523 decode =
524 encode = true;
525 }
526 if (in_file == NULL)
527 {
528 if (encode)
529 {
530 if (eight_k_in)
531 in_file = EIGHTK_IN_FILE_NAME;
532 else
533 in_file = IN_FILE_NAME;
534 }
535 else
536 {
537 in_file = ENCODED_FILE_NAME;
538 }
539 }
540 if (out_file == NULL)
541 {
542 out_file = (decode) ? OUT_FILE_NAME : ENCODED_FILE_NAME;
543 }
544 inhandle = NULL;
545 outhandle = NULL;
546 file = -1;
547 if (encode)
548 {
549 if (eight_k_in)
550 {
551 if ((inhandle = sf_open(in_file, SFM_READ, &info)) == NULL)
552 {
553 fprintf(stderr, " Cannot open audio file '%s'\n", in_file);
554 exit(2);
555 }
556 if (info.samplerate != SAMPLE_RATE)
557 {
558 fprintf(stderr, " Unexpected sample rate %d in audio file '%s'\n", info.samplerate, in_file);
559 exit(2);
560 }
561 if (info.channels != 1)
562 {
563 fprintf(stderr, " Unexpected number of channels in audio file '%s'\n", in_file);
564 exit(2);
565 }
566 enc_state = g722_encode_init(NULL, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000);
567 }
568 else
569 {
570 if ((inhandle = sf_open(in_file, SFM_READ, &info)) == NULL)
571 {
572 fprintf(stderr, " Cannot open audio file '%s'\n", in_file);
573 exit(2);
574 }
575 if (info.samplerate != G722_SAMPLE_RATE)
576 {
577 fprintf(stderr, " Unexpected sample rate %d in audio file '%s'\n", info.samplerate, in_file);
578 exit(2);
579 }
580 if (info.channels != 1)
581 {
582 fprintf(stderr, " Unexpected number of channels in audio file '%s'\n", in_file);
583 exit(2);
584 }
585 enc_state = g722_encode_init(NULL, bit_rate, G722_PACKED);
586 }
587 }
588 else
589 {
590 if ((file = open(in_file, O_RDONLY)) < 0)
591 {
592 fprintf(stderr, " Failed to open '%s'\n", in_file);
593 exit(2);
594 }
595 }
596 dec_state = NULL;
597 if (decode)
598 {
599 memset(&info, 0, sizeof(info));
600 info.frames = 0;
601 info.samplerate = (eight_k_out) ? SAMPLE_RATE : G722_SAMPLE_RATE;
602 info.channels = 1;
603 info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
604 info.sections = 1;
605 info.seekable = 1;
606 if ((outhandle = sf_open(out_file, SFM_WRITE, &info)) == NULL)
607 {
608 fprintf(stderr, " Cannot create audio file '%s'\n", out_file);
609 exit(2);
610 }
611 if (eight_k_out)
612 dec_state = g722_decode_init(NULL, bit_rate, G722_PACKED | G722_SAMPLE_RATE_8000);
613 else
614 dec_state = g722_decode_init(NULL, bit_rate, G722_PACKED);
615 }
616 else
617 {
618 if ((file = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
619 {
620 fprintf(stderr, " Failed to open '%s'\n", out_file);
621 exit(2);
622 }
623 }
624 for (;;)
625 {
626 if (encode)
627 {
628 samples = sf_readf_short(inhandle, indata, BLOCK_LEN);
629 if (samples <= 0)
630 break;
631 if (tone_test)
632 {
633 for (i = 0; i < samples; i++)
634 indata[i] = dds_modf(&tone_phase, tone_phase_rate, tone_level, 0);
635 }
636 len2 = g722_encode(enc_state, adpcmdata, indata, samples);
637 }
638 else
639 {
640 len2 = read(file, adpcmdata, BLOCK_LEN);
641 if (len2 <= 0)
642 break;
643 }
644 if (decode)
645 {
646 len3 = g722_decode(dec_state, outdata, adpcmdata, len2);
647 outframes = sf_writef_short(outhandle, outdata, len3);
648 if (outframes != len3)
649 {
650 fprintf(stderr, " Error writing audio file\n");
651 exit(2);
652 }
653 }
654 else
655 {
656 len3 = write(file, adpcmdata, len2);
657 if (len3 <= 0)
658 break;
659 }
660 }
661 if (encode)
662 {
663 if (sf_close(inhandle))
664 {
665 fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME);
666 exit(2);
667 }
668 g722_encode_free(enc_state);
669 }
670 else
671 {
672 close(file);
673 }
674 if (decode)
675 {
676 if (sf_close(outhandle))
677 {
678 fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
679 exit(2);
680 }
681 g722_decode_free(dec_state);
682 }
683 else
684 {
685 close(file);
686 }
687 printf("'%s' translated to '%s' at %dbps.\n", in_file, out_file, bit_rate);
688 }
689 return 0;
690 }
691 /*- End of function --------------------------------------------------------*/
692 /*- End of file ------------------------------------------------------------*/
693