Mercurial > hg > audiostuff
view 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 source
/* * 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 ------------------------------------------------------------*/