diff spandsp-0.0.6pre17/spandsp-sim/test_utils.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/spandsp-sim/test_utils.c	Fri Jun 25 15:50:58 2010 +0200
@@ -0,0 +1,402 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * test_utils.c - Utility routines for module tests.
+ *
+ * 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: test_utils.c,v 1.14 2009/06/01 16:27:12 steveu Exp $
+ */
+
+/*! \file */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+#if defined(HAVE_TGMATH_H)
+#include <tgmath.h>
+#endif
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#endif
+#include "floating_fudge.h"
+#include <time.h>
+#include <fcntl.h>
+#include <sndfile.h>
+
+#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
+#include "spandsp.h"
+#include "spandsp-sim.h"
+
+#define MAX_FFT_LEN     8192
+
+struct codec_munge_state_s
+{
+    int munging_codec;
+    g726_state_t g726_enc_state;
+    g726_state_t g726_dec_state;
+    int rbs_pattern;
+    int sequence;
+};
+
+struct complexify_state_s
+{
+    float history[128];
+    int ptr;
+};
+
+static complex_t circle[MAX_FFT_LEN/2];
+static int circle_init = FALSE;
+static complex_t icircle[MAX_FFT_LEN/2];
+static int icircle_init = FALSE;
+
+SPAN_DECLARE(complexify_state_t *) complexify_init(void)
+{
+    complexify_state_t *s;
+    int i;
+
+    if ((s = (complexify_state_t *) malloc(sizeof(*s))))
+    {
+        s->ptr = 0;
+        for (i = 0;  i < 128;  i++)
+            s->history[i] = 0.0f;
+    }
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(void) complexify_release(complexify_state_t *s)
+{
+    free(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(complexf_t) complexify(complexify_state_t *s, int16_t amp)
+{
+#define HILBERT_GAIN    1.569546344
+    static const float hilbert_coeffs[] =
+    {
+        +0.0012698413f, +0.0013489483f,
+        +0.0015105196f, +0.0017620440f,
+        +0.0021112899f, +0.0025663788f,
+        +0.0031358856f, +0.0038289705f,
+        +0.0046555545f, +0.0056265487f,
+        +0.0067541562f, +0.0080522707f,
+        +0.0095370033f, +0.0112273888f,
+        +0.0131463382f, +0.0153219442f,
+        +0.0177892941f, +0.0205930381f,
+        +0.0237910974f, +0.0274601544f,
+        +0.0317040029f, +0.0366666667f,
+        +0.0425537942f, +0.0496691462f,
+        +0.0584802574f, +0.0697446887f,
+        +0.0847739823f, +0.1060495199f,
+        +0.1388940865f, +0.1971551103f,
+        +0.3316207267f, +0.9994281838f,
+    };
+    float famp;
+    int i;
+    int j;
+    int k;
+    complexf_t res;
+
+    s->history[s->ptr] = amp;
+    i = s->ptr - 63;
+    if (i < 0)
+        i += 128;
+    res.re = s->history[i];
+
+    famp = 0.0f;
+    j = s->ptr - 126;
+    if (j < 0)
+        j += 128;
+    for (i = 0, k = s->ptr;  i < 32;  i++)
+    {
+        famp += (s->history[k] - s->history[j])*hilbert_coeffs[i];
+        j += 2;
+        if (j >= 128)
+            j -= 128;
+        k -= 2;
+        if (k < 0)
+            k += 128;
+    }
+    res.im = famp/HILBERT_GAIN;
+
+    if (++s->ptr >= 128)
+        s->ptr = 0;
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ complex_t expj(double theta)
+{
+    return complex_set(cos(theta), sin(theta));
+}
+/*- End of function --------------------------------------------------------*/
+
+static void fftx(complex_t data[], complex_t temp[], int n)
+{
+    int i;
+    int h;
+    int p;
+    int t;
+    int i2;
+    complex_t wkt;
+
+    if (n > 1)
+    {
+        h = n/2;
+        for (i = 0;  i < h;  i++)
+        {
+            i2 = i*2;
+            temp[i] = data[i2];         /* Even */
+            temp[h + i] = data[i2 + 1]; /* Odd */
+        }
+        fftx(&temp[0], &data[0], h);
+        fftx(&temp[h], &data[h], h);
+        p = 0;
+        t = MAX_FFT_LEN/n;
+        for (i = 0;  i < h;  i++)
+        {
+            wkt = complex_mul(&circle[p], &temp[h + i]);
+            data[i] = complex_add(&temp[i], &wkt);
+            data[h + i] = complex_sub(&temp[i], &wkt);
+            p += t;
+        }
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void ifftx(complex_t data[], complex_t temp[], int n)
+{
+    int i;
+    int h;
+    int p;
+    int t;
+    int i2;
+    complex_t wkt;
+
+    if (n > 1)
+    {
+        h = n/2;
+        for (i = 0;  i < h;  i++)
+        {
+            i2 = i*2;
+            temp[i] = data[i2];         /* Even */
+            temp[h + i] = data[i2 + 1]; /* Odd */
+        }
+        fftx(&temp[0], &data[0], h);
+        fftx(&temp[h], &data[h], h);
+        p = 0;
+        t = MAX_FFT_LEN/n;
+        for (i = 0;  i < h;  i++)
+        {
+            wkt = complex_mul(&icircle[p], &temp[h + i]);
+            data[i] = complex_add(&temp[i], &wkt);
+            data[h + i] = complex_sub(&temp[i], &wkt);
+            p += t;
+        }
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(void) fft(complex_t data[], int len)
+{
+    int i;
+    double x;
+    complex_t temp[MAX_FFT_LEN];
+
+    /* A very slow and clunky FFT, that's just fine for tests. */
+    if (!circle_init)
+    {
+        for (i = 0;  i < MAX_FFT_LEN/2;  i++)
+        {
+            x = -(2.0*3.1415926535*i)/(double) MAX_FFT_LEN;
+            circle[i] = expj(x);
+        }
+        circle_init = TRUE;
+    }
+    fftx(data, temp, len);
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(void) ifft(complex_t data[], int len)
+{
+    int i;
+    double x;
+    complex_t temp[MAX_FFT_LEN];
+
+    /* A very slow and clunky FFT, that's just fine for tests. */
+    if (!icircle_init)
+    {
+        for (i = 0;  i < MAX_FFT_LEN/2;  i++)
+        {
+            x = (2.0*3.1415926535*i)/(double) MAX_FFT_LEN;
+            icircle[i] = expj(x);
+        }
+        icircle_init = TRUE;
+    }
+    ifftx(data, temp, len);
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(codec_munge_state_t *) codec_munge_init(int codec, int info)
+{
+    codec_munge_state_t *s;
+    
+    if ((s = (codec_munge_state_t *) malloc(sizeof(*s))))
+    {
+        switch (codec)
+        {
+        case MUNGE_CODEC_G726_40K:
+            g726_init(&s->g726_enc_state, 40000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            g726_init(&s->g726_dec_state, 40000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            s->munging_codec = MUNGE_CODEC_G726_32K;
+            break;
+        case MUNGE_CODEC_G726_32K:
+            g726_init(&s->g726_enc_state, 32000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            g726_init(&s->g726_dec_state, 32000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            s->munging_codec = MUNGE_CODEC_G726_32K;
+            break;
+        case MUNGE_CODEC_G726_24K:
+            g726_init(&s->g726_enc_state, 24000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            g726_init(&s->g726_dec_state, 24000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            s->munging_codec = MUNGE_CODEC_G726_32K;
+            break;
+        case MUNGE_CODEC_G726_16K:
+            g726_init(&s->g726_enc_state, 16000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            g726_init(&s->g726_dec_state, 16000, G726_ENCODING_LINEAR, G726_PACKING_NONE);
+            s->munging_codec = MUNGE_CODEC_G726_32K;
+            break;
+        default:
+            s->munging_codec = codec;
+            break;
+        }
+        s->sequence = 0;
+        s->rbs_pattern = info;
+    }
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(void) codec_munge_release(codec_munge_state_t *s)
+{
+    free(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(void) codec_munge(codec_munge_state_t *s, int16_t amp[], int len)
+{
+    uint8_t law;
+    uint8_t adpcmdata[160];
+    int i;
+    int adpcm;
+    int x;
+
+    switch (s->munging_codec)
+    {
+    case MUNGE_CODEC_NONE:
+        /* Do nothing */
+        break;
+    case MUNGE_CODEC_ALAW:
+        for (i = 0;  i < len;  i++)
+        {
+            law = linear_to_alaw(amp[i]);
+            amp[i] = alaw_to_linear(law);
+        }
+        break;
+    case MUNGE_CODEC_ULAW:
+        for (i = 0;  i < len;  i++)
+        {
+            law = linear_to_ulaw(amp[i]);
+            if (s->rbs_pattern & (1 << s->sequence))
+            {
+                /* Strip the bottom bit at the RBS rate */
+                law &= 0xFE;
+            }
+            amp[i] = ulaw_to_linear(law);
+        }
+        break;
+    case MUNGE_CODEC_G726_32K:
+        /* This could actually be any of the G.726 rates */
+        for (i = 0;  i < len;  i += x)
+        {
+            x = (len - i >= 160)  ?  160  :  (len - i);
+            adpcm = g726_encode(&s->g726_enc_state, adpcmdata, amp + i, x);
+            g726_decode(&s->g726_dec_state, amp + i, adpcmdata, adpcm);
+        }
+        break;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(SNDFILE *) sf_open_telephony_read(const char *name, int channels)
+{
+    SNDFILE *handle;
+    SF_INFO info;
+
+    memset(&info, 0, sizeof(info));
+    if ((handle = sf_open(name, SFM_READ, &info)) == NULL)
+    {
+        fprintf(stderr, "    Cannot open audio file '%s' for reading\n", name);
+        exit(2);
+    }
+    if (info.samplerate != SAMPLE_RATE)
+    {
+        printf("    Unexpected sample rate in audio file '%s'\n", name);
+        exit(2);
+    }
+    if (info.channels != channels)
+    {
+        printf("    Unexpected number of channels in audio file '%s'\n", name);
+        exit(2);
+    }
+
+    return handle;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(SNDFILE *) sf_open_telephony_write(const char *name, int channels)
+{
+    SNDFILE *handle;
+    SF_INFO info;
+
+    memset(&info, 0, sizeof(info));
+    info.frames = 0;
+    info.samplerate = SAMPLE_RATE;
+    info.channels = channels;
+    info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+    info.sections = 1;
+    info.seekable = 1;
+
+    if ((handle = sf_open(name, SFM_WRITE, &info)) == NULL)
+    {
+        fprintf(stderr, "    Cannot open audio file '%s' for writing\n", name);
+        exit(2);
+    }
+
+    return handle;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

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