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