diff spandsp-0.0.3/spandsp-0.0.3/src/super_tone_tx.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/src/super_tone_tx.c	Fri Jun 25 16:00:21 2010 +0200
@@ -0,0 +1,236 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * super_tone_tx.c - Flexible telephony supervisory tone generation.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2003 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: super_tone_tx.c,v 1.15 2006/11/19 14:07:25 steveu Exp $
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <time.h>
+#include <inttypes.h>
+#if defined(HAVE_TGMATH_H)
+#include <tgmath.h>
+#endif
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#endif
+
+#include "spandsp/telephony.h"
+#include "spandsp/complex.h"
+#include "spandsp/dds.h"
+#include "spandsp/super_tone_tx.h"
+
+super_tone_tx_step_t *super_tone_tx_make_step(super_tone_tx_step_t *s,
+                                              float f1,
+                                              float l1,
+                                              float f2,
+                                              float l2,
+                                              int length,
+                                              int cycles)
+{
+    if (s == NULL)
+    {
+        s = (super_tone_tx_step_t *) malloc(sizeof(super_tone_tx_step_t));
+        if (s == NULL)
+            return NULL;
+    }
+    if (f1 >= 1.0)
+    {    
+        s->phase_rate[0] = dds_phase_ratef(f1);
+        s->gain[0] = dds_scaling_dbm0f(l1);
+    }
+    else
+    {
+        s->phase_rate[0] = 0;
+        s->gain[0] = 0;
+    }
+    if (f2 >= 1.0)
+    {
+        s->phase_rate[1] = dds_phase_ratef(f2);
+        s->gain[1] = dds_scaling_dbm0f(l2);
+    }
+    else
+    {
+        s->phase_rate[1] = 0;
+        s->gain[1] = 0;
+    }
+    s->tone = (f1 > 0.0);
+    s->length = length*8;
+    s->cycles = cycles;
+    s->next = NULL;
+    s->nest = NULL;
+    return  s;
+}
+/*- End of function --------------------------------------------------------*/
+
+void super_tone_tx_free(super_tone_tx_step_t *s)
+{
+    super_tone_tx_step_t *t;
+
+    while (s)
+    {
+        /* Follow nesting... */
+        if (s->nest)
+            super_tone_tx_free(s->nest);
+        t = s;
+        s = s->next;
+        free(t);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+super_tone_tx_state_t *super_tone_tx_init(super_tone_tx_state_t *s, super_tone_tx_step_t *tree)
+{
+    if (tree == NULL)
+        return NULL;
+    memset(s, 0, sizeof(*s));
+    s->level = 0;
+    s->levels[0] = tree;
+    s->cycles[0] = tree->cycles;
+
+    s->current_position = 0;
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+int super_tone_tx(super_tone_tx_state_t *s, int16_t amp[], int max_samples)
+{
+    int samples;
+    int limit;
+    int len;
+    float xamp;
+    super_tone_tx_step_t *tree;
+
+    if (s->level < 0  ||  s->level > 3)
+        return  0;
+    samples = 0;
+    tree = s->levels[s->level];
+    while (tree  &&  samples < max_samples)
+    {
+        if (tree->tone)
+        {
+            /* A period of tone. A length of zero means infinite
+               length. */
+            if (s->current_position == 0)
+            {
+                /* New step - prepare the tone generator */
+                s->phase_rate[0] = tree->phase_rate[0];
+                s->gain[0] = tree->gain[0];
+                s->phase_rate[1] = tree->phase_rate[1];
+                s->gain[1] = tree->gain[1];
+            }
+            len = tree->length - s->current_position;
+            if (tree->length == 0)
+            {
+                len = max_samples - samples;
+                /* We just need to make current position non-zero */
+                s->current_position = 1;
+            }
+            else if (len > max_samples - samples)
+            {
+                len = max_samples - samples;
+                s->current_position += len;
+            }
+            else
+            {
+                s->current_position = 0;
+            }
+            for (limit = len + samples;  samples < limit;  samples++)
+            {
+                xamp = 0.0;
+                if (s->phase_rate[0])
+                    xamp += dds_modf(&(s->phase[0]), s->phase_rate[0], s->gain[0], 0);
+                if (s->phase_rate[1])
+                    xamp += dds_modf(&(s->phase[1]), s->phase_rate[1], s->gain[1], 0);
+                amp[samples] = (int16_t) lrintf(xamp);
+            }
+            if (s->current_position)
+                return samples;
+        }
+        else if (tree->length)
+        {
+            /* A period of silence. The length must always
+               be explicitly stated. A length of zero does
+               not give infinite silence. */
+            len = tree->length - s->current_position;
+            if (len > max_samples - samples)
+            {
+                len = max_samples - samples;
+                s->current_position += len;
+            }
+            else
+            {
+                s->current_position = 0;
+            }
+            memset(amp + samples, 0, sizeof(uint16_t)*len);
+            samples += len;
+            if (s->current_position)
+                return samples;
+        }
+        /* Nesting has priority... */
+        if (tree->nest)
+        {
+            tree = tree->nest;
+            s->levels[++s->level] = tree;
+            s->cycles[s->level] = tree->cycles;
+        }
+        else
+        {
+            /* ...Next comes repeating, and finally moving forward a step. */
+            /* When repeating, note that zero cycles really means endless cycles. */
+            while (tree->cycles  &&  --s->cycles[s->level] <= 0)
+            {
+                tree = tree->next;
+                if (tree)
+                {
+                    /* A fresh new step. */
+                    s->levels[s->level] = tree;
+                    s->cycles[s->level] = tree->cycles;
+                    break;
+                }
+                /* If we are nested we need to pop, otherwise this is the end. */
+                if (s->level <= 0)
+                {
+                    /* Mark the tone as completed */
+                    s->levels[0] = NULL;
+                    break;
+                }
+                tree = s->levels[--s->level];
+            }
+        }
+        
+    }
+    return  samples;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

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