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