Mercurial > hg > audiostuff
diff spandsp-0.0.3/spandsp-0.0.3/tests/gsm0610_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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spandsp-0.0.3/spandsp-0.0.3/tests/gsm0610_tests.c Fri Jun 25 16:00:21 2010 +0200 @@ -0,0 +1,587 @@ +/* + * 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. + * + * $Id: gsm0610_tests.c,v 1.6 2006/11/19 14:07:27 steveu Exp $ + */ + +/*! \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. + +The speech file should be recorded at 16 bits/sample, 8000 samples/second, and named +"pre_gsm0610.wav". + +\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 spandsp. 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 ../localtests/short_nb_voice.wav +will be compressed to GSM 06.10 data, decompressed, and the resulting audio stored in post_gsm0610.wav. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#if defined(HAVE_TGMATH_H) +#include <tgmath.h> +#endif +#if defined(HAVE_MATH_H) +#include <math.h> +#endif +#include <assert.h> +#include <fcntl.h> +#include <ctype.h> +#include <stdio.h> +#include <audiofile.h> +#include <tiffio.h> + +#include "spandsp.h" + +#define BLOCK_LEN 160 + +#define TEST_DIR "../etsitests/gsm0610/unpacked/fr_" + +#define IN_FILE_NAME "../localtests/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", TEST_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", TEST_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", TEST_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; +} + +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", TEST_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", TEST_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", TEST_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", TEST_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; +} + +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/BLOCK_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_release(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/BLOCK_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_release(gsm0610_dec_state); + printf("Test passed\n"); + return 0; +} + +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/BLOCK_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_release(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/BLOCK_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_release(gsm0610_dec_state); + printf("Test passed\n"); + return 0; +} + +int main(int argc, char *argv[]) +{ + AFfilehandle inhandle; + AFfilehandle outhandle; + AFfilesetup filesetup; + int frames; + int outframes; + float x; + 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 etsitests; + int packing; + int i; + + etsitests = TRUE; + packing = GSM0610_PACKING_NONE; + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-l") == 0) + { + etsitests = FALSE; + continue; + } + if (strcmp(argv[i], "-p") == 0) + { + packing = atoi(argv[++i]); + continue; + } + fprintf(stderr, "Unknown parameter %s specified.\n", argv[i]); + exit(2); + } + + if (etsitests) + { + 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"); + + printf("Tests passed.\n"); + } + else + { + if ((inhandle = afOpenFile(IN_FILE_NAME, "r", 0)) == AF_NULL_FILEHANDLE) + { + printf(" Cannot open wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetFrameSize(inhandle, AF_DEFAULT_TRACK, 1)) != 2.0) + { + printf(" Unexpected frame size in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetRate(inhandle, AF_DEFAULT_TRACK)) != (float) SAMPLE_RATE) + { + printf(" Unexpected sample rate in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((x = afGetChannels(inhandle, AF_DEFAULT_TRACK)) != 1.0) + { + printf(" Unexpected number of channels in wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) + { + fprintf(stderr, " Failed to create file setup\n"); + exit(2); + } + afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); + afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); + afInitFileFormat(filesetup, AF_FILE_WAVE); + afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); + + outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup); + if (outhandle == AF_NULL_FILEHANDLE) + { + fprintf(stderr, " Cannot create wave 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 = afReadFrames(inhandle, AF_DEFAULT_TRACK, pre_amp, 2*BLOCK_LEN))) + { + gsm0610_encode(gsm0610_enc_state, gsm0610_data, pre_amp, (packing == GSM0610_PACKING_WAV49) ? 1 : 2); + gsm0610_decode(gsm0610_dec_state, post_amp, gsm0610_data, (packing == GSM0610_PACKING_WAV49) ? 1 : 2); + outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, post_amp, frames); + } + + if (afCloseFile(inhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", IN_FILE_NAME); + exit(2); + } + if (afCloseFile(outhandle) != 0) + { + printf(" Cannot close wave file '%s'\n", OUT_FILE_NAME); + exit(2); + } + afFreeFileSetup(filesetup); + gsm0610_release(gsm0610_enc_state); + gsm0610_release(gsm0610_dec_state); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/