123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622 |
- /*
- * SpanDSP - a series of DSP components for telephony
- *
- * gsm0610_tests.c - Test the GSM 06.10 FR codec.
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2006 Steve Underwood
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- /*! \file */
- /*! \page gsm0610_tests_page GSM 06.10 full rate codec tests
- \section gsm0610_tests_page_sec_1 What does it do?
- Two sets of tests are performed:
- - The tests defined in the GSM 06.10 specification, using the test data files supplied with
- the specification.
- - A generally audio quality test, consisting of compressing and decompressing a speeech
- file for audible comparison.
- \section gsm0610_tests_page_sec_2 How is it used?
- To perform the tests in the GSM 06.10 specification you need to obtain the test data files from the
- specification. These are copyright material, and so cannot be distributed with this test software.
- They can, however, be freely downloaded from the ETSI web site.
- The files, containing test vectors, which are supplied with the GSM 06.10 specification, should be
- copied to etsitests/gsm0610/unpacked so the files are arranged in the following directories.
- ./fr_A:
- Seq01-A.cod Seq01-A.inp Seq01-A.out
- Seq02-A.cod Seq02-A.inp Seq02-A.out
- Seq03-A.cod Seq03-A.inp Seq03-A.out
- Seq04-A.cod Seq04-A.inp Seq04-A.out
- Seq05-A.out
- ./fr_L:
- Seq01.cod Seq01.inp Seq01.out
- Seq02.cod Seq02.inp Seq02.out
- Seq03.cod Seq03.inp Seq03.out
- Seq04.cod Seq04.inp Seq04.out
- Seq05.cod Seq05.out
- ./fr_U:
- Seq01-U.cod Seq01-U.inp Seq01-U.out
- Seq02-U.cod Seq02-U.inp Seq02-U.out
- Seq03-U.cod Seq03-U.inp Seq03-U.out
- Seq04-U.cod Seq04-U.inp Seq04-U.out
- Seq05-U.out
- ./fr_homing_A:
- Homing01_A.out
- Seq01H_A.cod Seq01H_A.inp Seq01H_A.out
- Seq02H_A.cod Seq02H_A.inp Seq02H_A.out
- Seq03H_A.cod Seq03H_A.inp Seq03H_A.out
- Seq04H_A.cod Seq04H_A.inp Seq04H_A.out
- Seq05H_A.out
- Seq06H_A.cod Seq06H_A.inp
- ./fr_homing_L:
- Homing01.cod Homing01.out
- Seq01h.cod Seq01h.inp Seq01h.out
- Seq02h.cod Seq02h.inp Seq02h.out
- Seq03h.cod Seq03h.inp Seq03h.out
- Seq04h.cod Seq04h.inp Seq04h.out
- Seq05h.cod Seq05h.out
- Seq06h.cod Seq06h.inp
- ./fr_homing_U:
- Homing01_U.out
- Seq01H_U.cod Seq01H_U.inp Seq01H_U.out
- Seq02H_U.cod Seq02H_U.inp Seq02H_U.out
- Seq03H_U.cod Seq03H_U.inp Seq03H_U.out
- Seq04H_U.cod Seq04H_U.inp Seq04H_U.out
- Seq05H_U.out
- Seq06H_U.cod Seq06H_U.inp
- ./fr_sync_A:
- Seqsync_A.inp
- Sync000_A.cod --to-- Sync159_A.cod
- ./fr_sync_L:
- Bitsync.inp
- Seqsync.inp
- Sync000.cod --to-- Sync159.cod
- ./fr_sync_U:
- Seqsync_U.inp
- Sync000_U.cod --to-- Sync159_U.cod
- This is different from the directory structure in which they are supplied. Also, the files names are a little
- different. The supplied names are messy, and inconsistent across the sets. The names required by these tests
- just clean up these inconsistencies. Note that you will need a Windows machine to unpack some of the supplied
- files.
- To perform a general audio quality test, gsm0610_tests should be run. The file ../test-data/local/short_nb_voice.wav
- will be compressed to GSM 06.10 data, decompressed, and the resulting audio stored in post_gsm0610.wav.
- */
- #if defined(HAVE_CONFIG_H)
- #include "config.h"
- #endif
- #include <stdlib.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <ctype.h>
- #include <sndfile.h>
- #include "spandsp.h"
- #include "spandsp-sim.h"
- #define BLOCK_LEN 160
- #define TESTDATA_DIR "../test-data/etsi/gsm0610/unpacked/fr_"
- #define IN_FILE_NAME "../test-data/local/short_nb_voice.wav"
- #define OUT_FILE_NAME "post_gsm0610.wav"
- #define HIST_LEN 1000
- uint8_t law_in_vector[1000000];
- int16_t in_vector[1000000];
- uint16_t code_vector_buf[1000000];
- uint8_t code_vector[1000000];
- uint8_t ref_code_vector[1000000];
- uint8_t decoder_code_vector[1000000];
- uint8_t law_out_vector[1000000];
- int16_t out_vector[1000000];
- int16_t ref_out_vector[1000000];
- uint8_t ref_law_out_vector[1000000];
- int vector_len;
- static int get_test_vector(int full, int disk, const char *name)
- {
- char buf[500];
- int in;
- int len;
- int i;
- if (full)
- {
- sprintf(buf, "%s%c/%s.inp", TESTDATA_DIR, 'L', name);
- if ((in = open(buf, O_RDONLY)) < 0)
- {
- fprintf(stderr, "Cannot open %s\n", buf);
- exit(2);
- }
- len = read(in, in_vector, 1000000);
- close(in);
- len /= sizeof(int16_t);
- vector_len = len;
- }
- sprintf(buf, "%s%c/%s.out", TESTDATA_DIR, 'L', name);
- if ((in = open(buf, O_RDONLY)) < 0)
- {
- fprintf(stderr, "Cannot open %s\n", buf);
- exit(2);
- }
- len = read(in, ref_out_vector, 1000000);
- close(in);
- len /= sizeof(int16_t);
- if (full)
- {
- if (len != vector_len)
- {
- fprintf(stderr, "Input and reference vector lengths do not match - %d %d\n", vector_len, len);
- exit(2);
- }
- }
- else
- {
- vector_len = len;
- }
- sprintf(buf, "%s%c/%s.cod", TESTDATA_DIR, 'L', name);
- if ((in = open(buf, O_RDONLY)) < 0)
- {
- fprintf(stderr, "Cannot open %s\n", buf);
- exit(2);
- }
- len = read(in, code_vector_buf, 1000000);
- close(in);
- len /= sizeof(int16_t);
- for (i = 0; i < len; i++)
- {
- ref_code_vector[i] = code_vector_buf[i];
- decoder_code_vector[i] = code_vector_buf[i];
- }
- if (len*BLOCK_LEN != vector_len*76)
- {
- fprintf(stderr, "Input and code vector lengths do not match - %d %d\n", vector_len, len);
- exit(2);
- }
- return len;
- }
- /*- End of function --------------------------------------------------------*/
- static int get_law_test_vector(int full, int law, const char *name)
- {
- char buf[500];
- int in;
- int len;
- int i;
- int law_uc;
- law_uc = toupper(law);
- if (full)
- {
- sprintf(buf, "%s%c/%s-%c.inp", TESTDATA_DIR, law_uc, name, law_uc);
- if ((in = open(buf, O_RDONLY)) < 0)
- {
- fprintf(stderr, "Cannot open %s\n", buf);
- exit(2);
- }
- len = read(in, law_in_vector, 1000000);
- close(in);
- vector_len = len;
- sprintf(buf, "%s%c/%s-%c.cod", TESTDATA_DIR, law_uc, name, law_uc);
- if ((in = open(buf, O_RDONLY)) < 0)
- {
- fprintf(stderr, "Cannot open %s\n", buf);
- exit(2);
- }
- len = read(in, code_vector_buf, 1000000);
- close(in);
- len /= sizeof(int16_t);
- for (i = 0; i < len; i++)
- ref_code_vector[i] = code_vector_buf[i];
- if (len*BLOCK_LEN != vector_len*76)
- {
- fprintf(stderr, "Input and code vector lengths do not match - %d %d\n", vector_len, len);
- exit(2);
- }
- }
- sprintf(buf, "%s%c/%s-%c.out", TESTDATA_DIR, law_uc, name, law_uc);
- if ((in = open(buf, O_RDONLY)) < 0)
- {
- fprintf(stderr, "Cannot open %s\n", buf);
- exit(2);
- }
- len = read(in, ref_law_out_vector, 1000000);
- close(in);
- if (full)
- {
- if (len != vector_len)
- {
- fprintf(stderr, "Input and reference vector lengths do not match - %d %d\n", vector_len, len);
- exit(2);
- }
- }
- else
- {
- vector_len = len;
- }
- sprintf(buf, "%s%c/%s.cod", TESTDATA_DIR, 'L', name);
- if ((in = open(buf, O_RDONLY)) < 0)
- {
- fprintf(stderr, "Cannot open %s\n", buf);
- exit(2);
- }
- len = read(in, code_vector_buf, 1000000);
- close(in);
- len /= sizeof(int16_t);
- for (i = 0; i < len; i++)
- decoder_code_vector[i] = code_vector_buf[i];
- return len;
- }
- /*- End of function --------------------------------------------------------*/
- static int perform_linear_test(int full, int disk, const char *name)
- {
- gsm0610_state_t *gsm0610_enc_state;
- gsm0610_state_t *gsm0610_dec_state;
- int i;
- int xxx;
- int mismatches;
- printf("Performing linear test '%s' from disk %d\n", name, disk);
- get_test_vector(full, disk, name);
- if (full)
- {
- if ((gsm0610_enc_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL)
- {
- fprintf(stderr, " Cannot create encoder\n");
- exit(2);
- }
- xxx = gsm0610_encode(gsm0610_enc_state, code_vector, in_vector, vector_len);
- printf("Check code vector of length %d\n", xxx);
- for (i = 0, mismatches = 0; i < xxx; i++)
- {
- if (code_vector[i] != ref_code_vector[i])
- {
- printf("%8d/%3d: %6d %6d\n", i/76, i%76, code_vector[i], ref_code_vector[i]);
- mismatches++;
- }
- }
- gsm0610_free(gsm0610_enc_state);
- if (mismatches)
- {
- printf("Test failed: %d of %d samples mismatch\n", mismatches, xxx);
- exit(2);
- }
- printf("Test passed\n");
- }
- if ((gsm0610_dec_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL)
- {
- fprintf(stderr, " Cannot create decoder\n");
- exit(2);
- }
- xxx = gsm0610_decode(gsm0610_dec_state, out_vector, decoder_code_vector, vector_len);
- printf("Check output vector of length %d\n", vector_len);
- for (i = 0, mismatches = 0; i < vector_len; i++)
- {
- if (out_vector[i] != ref_out_vector[i])
- {
- printf("%8d: %6d %6d\n", i, out_vector[i], ref_out_vector[i]);
- mismatches++;
- }
- }
- if (mismatches)
- {
- printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len);
- exit(2);
- }
- gsm0610_free(gsm0610_dec_state);
- printf("Test passed\n");
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- static int perform_law_test(int full, int law, const char *name)
- {
- gsm0610_state_t *gsm0610_enc_state;
- gsm0610_state_t *gsm0610_dec_state;
- int i;
- int xxx;
- int mismatches;
- if (law == 'a')
- printf("Performing A-law test '%s'\n", name);
- else
- printf("Performing u-law test '%s'\n", name);
- get_law_test_vector(full, law, name);
- if (full)
- {
- if ((gsm0610_enc_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL)
- {
- fprintf(stderr, " Cannot create encoder\n");
- exit(2);
- }
- if (law == 'a')
- {
- for (i = 0; i < vector_len; i++)
- in_vector[i] = alaw_to_linear(law_in_vector[i]);
- }
- else
- {
- for (i = 0; i < vector_len; i++)
- in_vector[i] = ulaw_to_linear(law_in_vector[i]);
- }
- xxx = gsm0610_encode(gsm0610_enc_state, code_vector, in_vector, vector_len);
- printf("Check code vector of length %d\n", xxx);
- for (i = 0, mismatches = 0; i < xxx; i++)
- {
- if (code_vector[i] != ref_code_vector[i])
- {
- printf("%8d/%3d: %6d %6d %6d\n", i/76, i%76, code_vector[i], ref_code_vector[i], decoder_code_vector[i]);
- mismatches++;
- }
- }
- if (mismatches)
- {
- printf("Test failed: %d of %d samples mismatch\n", mismatches, xxx);
- exit(2);
- }
- printf("Test passed\n");
- gsm0610_free(gsm0610_enc_state);
- }
- if ((gsm0610_dec_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL)
- {
- fprintf(stderr, " Cannot create decoder\n");
- exit(2);
- }
- xxx = gsm0610_decode(gsm0610_dec_state, out_vector, decoder_code_vector, vector_len);
- if (law == 'a')
- {
- for (i = 0; i < vector_len; i++)
- law_out_vector[i] = linear_to_alaw(out_vector[i]);
- }
- else
- {
- for (i = 0; i < vector_len; i++)
- law_out_vector[i] = linear_to_ulaw(out_vector[i]);
- }
- printf("Check output vector of length %d\n", vector_len);
- for (i = 0, mismatches = 0; i < vector_len; i++)
- {
- if (law_out_vector[i] != ref_law_out_vector[i])
- {
- printf("%8d: %6d %6d\n", i, law_out_vector[i], ref_law_out_vector[i]);
- mismatches++;
- }
- }
- if (mismatches)
- {
- printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len);
- exit(2);
- }
- gsm0610_free(gsm0610_dec_state);
- printf("Test passed\n");
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- static int repack_gsm0610_voip_to_wav49(uint8_t c[], const uint8_t d[])
- {
- gsm0610_frame_t frame[2];
- int n;
- n = gsm0610_unpack_voip(&frame[0], d);
- gsm0610_unpack_voip(&frame[1], d + n);
- n = gsm0610_pack_wav49(c, frame);
- return n;
- }
- /*- End of function --------------------------------------------------------*/
- static int repack_gsm0610_wav49_to_voip(uint8_t d[], const uint8_t c[])
- {
- gsm0610_frame_t frame[2];
- int n[2];
- gsm0610_unpack_wav49(frame, c);
- n[0] = gsm0610_pack_voip(d, &frame[0]);
- n[1] = gsm0610_pack_voip(d + n[0], &frame[1]);
- return n[0] + n[1];
- }
- /*- End of function --------------------------------------------------------*/
- static int perform_pack_unpack_test(void)
- {
- uint8_t a[66];
- uint8_t b[66];
- uint8_t c[66];
- int i;
- int j;
- printf("Performing packing/unpacking tests (not part of the ETSI conformance tests).\n");
- /* Try trans-packing a lot of random data looking for before/after mismatch. */
- for (j = 0; j < 1000; j++)
- {
- for (i = 0; i < 65; i++)
- a[i] = rand();
- repack_gsm0610_wav49_to_voip(b, a);
- repack_gsm0610_voip_to_wav49(c, b);
- if (memcmp(a, c, 65))
- {
- printf("Test failed: data mismatch\n");
- exit(2);
- }
- for (i = 0; i < 66; i++)
- a[i] = rand();
- /* Insert the magic code */
- a[0] = (a[0] & 0xF) | 0xD0;
- a[33] = (a[33] & 0xF) | 0xD0;
- repack_gsm0610_voip_to_wav49(b, a);
- repack_gsm0610_wav49_to_voip(c, b);
- //for (i = 0; i < 66; i++)
- // printf("%2d: 0x%02X 0x%02X\n", i, a[i], c[i]);
- if (memcmp(a, c, 66))
- {
- printf("Test failed: data mismatch\n");
- exit(2);
- }
- }
- printf("Test passed\n");
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- static void etsi_compliance_tests(void)
- {
- perform_linear_test(true, 1, "Seq01");
- perform_linear_test(true, 1, "Seq02");
- perform_linear_test(true, 1, "Seq03");
- perform_linear_test(true, 1, "Seq04");
- perform_linear_test(false, 1, "Seq05");
- perform_law_test(true, 'a', "Seq01");
- perform_law_test(true, 'a', "Seq02");
- perform_law_test(true, 'a', "Seq03");
- perform_law_test(true, 'a', "Seq04");
- perform_law_test(false, 'a', "Seq05");
- perform_law_test(true, 'u', "Seq01");
- perform_law_test(true, 'u', "Seq02");
- perform_law_test(true, 'u', "Seq03");
- perform_law_test(true, 'u', "Seq04");
- perform_law_test(false, 'u', "Seq05");
- /* This is not actually an ETSI test */
- perform_pack_unpack_test();
- printf("Tests passed.\n");
- }
- /*- End of function --------------------------------------------------------*/
- int main(int argc, char *argv[])
- {
- SNDFILE *inhandle;
- SNDFILE *outhandle;
- int frames;
- int bytes;
- int16_t pre_amp[HIST_LEN];
- int16_t post_amp[HIST_LEN];
- uint8_t gsm0610_data[HIST_LEN];
- gsm0610_state_t *gsm0610_enc_state;
- gsm0610_state_t *gsm0610_dec_state;
- int opt;
- int etsitests;
- int packing;
- etsitests = true;
- packing = GSM0610_PACKING_NONE;
- while ((opt = getopt(argc, argv, "lp:")) != -1)
- {
- switch (opt)
- {
- case 'l':
- etsitests = false;
- break;
- case 'p':
- packing = atoi(optarg);
- break;
- default:
- //usage();
- exit(2);
- }
- }
- if (etsitests)
- {
- etsi_compliance_tests();
- }
- else
- {
- if ((inhandle = sf_open_telephony_read(IN_FILE_NAME, 1)) == NULL)
- {
- fprintf(stderr, " Cannot open audio file '%s'\n", IN_FILE_NAME);
- exit(2);
- }
- if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL)
- {
- fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
- exit(2);
- }
- if ((gsm0610_enc_state = gsm0610_init(NULL, packing)) == NULL)
- {
- fprintf(stderr, " Cannot create encoder\n");
- exit(2);
- }
- if ((gsm0610_dec_state = gsm0610_init(NULL, packing)) == NULL)
- {
- fprintf(stderr, " Cannot create decoder\n");
- exit(2);
- }
- while ((frames = sf_readf_short(inhandle, pre_amp, 2*BLOCK_LEN)))
- {
- bytes = gsm0610_encode(gsm0610_enc_state, gsm0610_data, pre_amp, frames);
- gsm0610_decode(gsm0610_dec_state, post_amp, gsm0610_data, bytes);
- sf_writef_short(outhandle, post_amp, frames);
- }
- if (sf_close_telephony(inhandle))
- {
- fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME);
- exit(2);
- }
- if (sf_close_telephony(outhandle))
- {
- fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
- exit(2);
- }
- gsm0610_free(gsm0610_enc_state);
- gsm0610_free(gsm0610_dec_state);
- }
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- /*- End of file ------------------------------------------------------------*/
|