diff spandsp-0.0.6pre17/tests/gsm0610_tests.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spandsp-0.0.6pre17/tests/gsm0610_tests.c	Fri Jun 25 15:50:58 2010 +0200
@@ -0,0 +1,629 @@
+/*
+ * 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.25 2009/05/30 15:23:13 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.
+
+\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>
+
+//#if defined(WITH_SPANDSP_INTERNALS)
+#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
+//#endif
+
+#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_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);
+    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;
+}
+/*- 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_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);
+    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;
+}
+/*- 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 outframes;
+    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);
+            outframes = sf_writef_short(outhandle, post_amp, frames);
+        }
+    
+        if (sf_close(inhandle) != 0)
+        {
+            fprintf(stderr, "    Cannot close audio file '%s'\n", IN_FILE_NAME);
+            exit(2);
+        }
+        if (sf_close(outhandle) != 0)
+        {
+            fprintf(stderr, "    Cannot close audio file '%s'\n", OUT_FILE_NAME);
+            exit(2);
+        }
+        gsm0610_release(gsm0610_enc_state);
+        gsm0610_release(gsm0610_dec_state);
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.