Mercurial > hg > audiostuff
diff spandsp-0.0.6pre17/src/super_tone_tx.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/src/super_tone_tx.c Fri Jun 25 15:50:58 2010 +0200 @@ -0,0 +1,288 @@ +/* + * 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 Lesser General Public License version 2.1, + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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.30 2009/02/10 17:44:18 steveu Exp $ + */ + +/*! \file */ + +#if defined(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 "floating_fudge.h" + +#include "spandsp/telephony.h" +#include "spandsp/fast_convert.h" +#include "spandsp/complex.h" +#include "spandsp/dds.h" +#include "spandsp/tone_generate.h" +#include "spandsp/super_tone_tx.h" + +#include "spandsp/private/tone_generate.h" +#include "spandsp/private/super_tone_tx.h" + +/* + The tone played to wake folk up when they have left the phone off hook is an + oddity amongst supervisory tones. It is designed to sound loud and nasty. Most + tones are one or two pure sine pitches, or one AM moduluated pitch. This alert + tone varies between countries, but AT&T are a typical example. + + AT&T Receiver Off-Hook Tone is 1400 Hz, 2060 Hz, 2450 Hz and 2600 Hz at 0dBm0/frequency + on and off every .1 second. On some older space division switching systems + Receiver Off-Hook was 1400 Hz, 2060 Hz, 2450 Hz and 2600 Hz at +5 VU on and + off every .1 second. On a No. 5 ESS this continues for 30 seconds. On a No. + 2/2B ESS this continues for 40 seconds. On some other AT&T switches there are + two iterations of 50 seconds each. +*/ + +SPAN_DECLARE(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) + { + if ((s = (super_tone_tx_step_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + if (f1 >= 1.0f) + { + s->tone[0].phase_rate = dds_phase_ratef(f1); + s->tone[0].gain = dds_scaling_dbm0f(l1); + } + else + { + s->tone[0].phase_rate = 0; + s->tone[0].gain = 0.0f; + } + if (f2 >= 1.0f) + { + s->tone[1].phase_rate = dds_phase_ratef(f2); + s->tone[1].gain = dds_scaling_dbm0f(l2); + } + else + { + s->tone[1].phase_rate = 0; + s->tone[1].gain = 0.0f; + } + s->tone_on = (f1 > 0.0f); + s->length = length*SAMPLE_RATE/1000; + s->cycles = cycles; + s->next = NULL; + s->nest = NULL; + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) super_tone_tx_free_tone(super_tone_tx_step_t *s) +{ + super_tone_tx_step_t *t; + + while (s) + { + /* Follow nesting... */ + if (s->nest) + super_tone_tx_free_tone(s->nest); + t = s; + s = s->next; + free(t); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(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; + if (s == NULL) + { + if ((s = (super_tone_tx_state_t *) malloc(sizeof(*s))) == 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 --------------------------------------------------------*/ + +SPAN_DECLARE(int) super_tone_tx_release(super_tone_tx_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) super_tone_tx_free(super_tone_tx_state_t *s) +{ + if (s) + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) super_tone_tx(super_tone_tx_state_t *s, int16_t amp[], int max_samples) +{ + int samples; + int limit; + int len; + int i; + 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_on) + { + /* A period of tone. A length of zero means infinite length. */ + if (s->current_position == 0) + { + /* New step - prepare the tone generator */ + for (i = 0; i < 4; i++) + s->tone[i] = tree->tone[i]; + } + 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; + } + if (s->tone[0].phase_rate < 0) + { + for (limit = len + samples; samples < limit; samples++) + { + /* There must be two, and only two tones */ + xamp = dds_modf(&s->phase[0], -s->tone[0].phase_rate, s->tone[0].gain, 0) + *(1.0f + dds_modf(&s->phase[1], s->tone[1].phase_rate, s->tone[1].gain, 0)); + amp[samples] = (int16_t) lfastrintf(xamp); + } + } + else + { + for (limit = len + samples; samples < limit; samples++) + { + xamp = 0.0f; + for (i = 0; i < 4; i++) + { + if (s->tone[i].phase_rate == 0) + break; + xamp += dds_modf(&s->phase[i], s->tone[i].phase_rate, s->tone[i].gain, 0); + } + amp[samples] = (int16_t) lfastrintf(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 ------------------------------------------------------------*/