comparison 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
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * super_tone_tx.c - Flexible telephony supervisory tone generation.
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2003 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 2.1,
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: super_tone_tx.c,v 1.30 2009/02/10 17:44:18 steveu Exp $
26 */
27
28 /*! \file */
29
30 #if defined(HAVE_CONFIG_H)
31 #include "config.h"
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <ctype.h>
39 #include <time.h>
40 #include <inttypes.h>
41 #if defined(HAVE_TGMATH_H)
42 #include <tgmath.h>
43 #endif
44 #if defined(HAVE_MATH_H)
45 #include <math.h>
46 #endif
47 #include "floating_fudge.h"
48
49 #include "spandsp/telephony.h"
50 #include "spandsp/fast_convert.h"
51 #include "spandsp/complex.h"
52 #include "spandsp/dds.h"
53 #include "spandsp/tone_generate.h"
54 #include "spandsp/super_tone_tx.h"
55
56 #include "spandsp/private/tone_generate.h"
57 #include "spandsp/private/super_tone_tx.h"
58
59 /*
60 The tone played to wake folk up when they have left the phone off hook is an
61 oddity amongst supervisory tones. It is designed to sound loud and nasty. Most
62 tones are one or two pure sine pitches, or one AM moduluated pitch. This alert
63 tone varies between countries, but AT&T are a typical example.
64
65 AT&T Receiver Off-Hook Tone is 1400 Hz, 2060 Hz, 2450 Hz and 2600 Hz at 0dBm0/frequency
66 on and off every .1 second. On some older space division switching systems
67 Receiver Off-Hook was 1400 Hz, 2060 Hz, 2450 Hz and 2600 Hz at +5 VU on and
68 off every .1 second. On a No. 5 ESS this continues for 30 seconds. On a No.
69 2/2B ESS this continues for 40 seconds. On some other AT&T switches there are
70 two iterations of 50 seconds each.
71 */
72
73 SPAN_DECLARE(super_tone_tx_step_t *) super_tone_tx_make_step(super_tone_tx_step_t *s,
74 float f1,
75 float l1,
76 float f2,
77 float l2,
78 int length,
79 int cycles)
80 {
81 if (s == NULL)
82 {
83 if ((s = (super_tone_tx_step_t *) malloc(sizeof(*s))) == NULL)
84 return NULL;
85 }
86 if (f1 >= 1.0f)
87 {
88 s->tone[0].phase_rate = dds_phase_ratef(f1);
89 s->tone[0].gain = dds_scaling_dbm0f(l1);
90 }
91 else
92 {
93 s->tone[0].phase_rate = 0;
94 s->tone[0].gain = 0.0f;
95 }
96 if (f2 >= 1.0f)
97 {
98 s->tone[1].phase_rate = dds_phase_ratef(f2);
99 s->tone[1].gain = dds_scaling_dbm0f(l2);
100 }
101 else
102 {
103 s->tone[1].phase_rate = 0;
104 s->tone[1].gain = 0.0f;
105 }
106 s->tone_on = (f1 > 0.0f);
107 s->length = length*SAMPLE_RATE/1000;
108 s->cycles = cycles;
109 s->next = NULL;
110 s->nest = NULL;
111 return s;
112 }
113 /*- End of function --------------------------------------------------------*/
114
115 SPAN_DECLARE(int) super_tone_tx_free_tone(super_tone_tx_step_t *s)
116 {
117 super_tone_tx_step_t *t;
118
119 while (s)
120 {
121 /* Follow nesting... */
122 if (s->nest)
123 super_tone_tx_free_tone(s->nest);
124 t = s;
125 s = s->next;
126 free(t);
127 }
128 return 0;
129 }
130 /*- End of function --------------------------------------------------------*/
131
132 SPAN_DECLARE(super_tone_tx_state_t *) super_tone_tx_init(super_tone_tx_state_t *s, super_tone_tx_step_t *tree)
133 {
134 if (tree == NULL)
135 return NULL;
136 if (s == NULL)
137 {
138 if ((s = (super_tone_tx_state_t *) malloc(sizeof(*s))) == NULL)
139 return NULL;
140 }
141 memset(s, 0, sizeof(*s));
142 s->level = 0;
143 s->levels[0] = tree;
144 s->cycles[0] = tree->cycles;
145
146 s->current_position = 0;
147 return s;
148 }
149 /*- End of function --------------------------------------------------------*/
150
151 SPAN_DECLARE(int) super_tone_tx_release(super_tone_tx_state_t *s)
152 {
153 return 0;
154 }
155 /*- End of function --------------------------------------------------------*/
156
157 SPAN_DECLARE(int) super_tone_tx_free(super_tone_tx_state_t *s)
158 {
159 if (s)
160 free(s);
161 return 0;
162 }
163 /*- End of function --------------------------------------------------------*/
164
165 SPAN_DECLARE(int) super_tone_tx(super_tone_tx_state_t *s, int16_t amp[], int max_samples)
166 {
167 int samples;
168 int limit;
169 int len;
170 int i;
171 float xamp;
172 super_tone_tx_step_t *tree;
173
174 if (s->level < 0 || s->level > 3)
175 return 0;
176 samples = 0;
177 tree = s->levels[s->level];
178 while (tree && samples < max_samples)
179 {
180 if (tree->tone_on)
181 {
182 /* A period of tone. A length of zero means infinite length. */
183 if (s->current_position == 0)
184 {
185 /* New step - prepare the tone generator */
186 for (i = 0; i < 4; i++)
187 s->tone[i] = tree->tone[i];
188 }
189 len = tree->length - s->current_position;
190 if (tree->length == 0)
191 {
192 len = max_samples - samples;
193 /* We just need to make current position non-zero */
194 s->current_position = 1;
195 }
196 else if (len > max_samples - samples)
197 {
198 len = max_samples - samples;
199 s->current_position += len;
200 }
201 else
202 {
203 s->current_position = 0;
204 }
205 if (s->tone[0].phase_rate < 0)
206 {
207 for (limit = len + samples; samples < limit; samples++)
208 {
209 /* There must be two, and only two tones */
210 xamp = dds_modf(&s->phase[0], -s->tone[0].phase_rate, s->tone[0].gain, 0)
211 *(1.0f + dds_modf(&s->phase[1], s->tone[1].phase_rate, s->tone[1].gain, 0));
212 amp[samples] = (int16_t) lfastrintf(xamp);
213 }
214 }
215 else
216 {
217 for (limit = len + samples; samples < limit; samples++)
218 {
219 xamp = 0.0f;
220 for (i = 0; i < 4; i++)
221 {
222 if (s->tone[i].phase_rate == 0)
223 break;
224 xamp += dds_modf(&s->phase[i], s->tone[i].phase_rate, s->tone[i].gain, 0);
225 }
226 amp[samples] = (int16_t) lfastrintf(xamp);
227 }
228 }
229 if (s->current_position)
230 return samples;
231 }
232 else if (tree->length)
233 {
234 /* A period of silence. The length must always
235 be explicitly stated. A length of zero does
236 not give infinite silence. */
237 len = tree->length - s->current_position;
238 if (len > max_samples - samples)
239 {
240 len = max_samples - samples;
241 s->current_position += len;
242 }
243 else
244 {
245 s->current_position = 0;
246 }
247 memset(amp + samples, 0, sizeof(uint16_t)*len);
248 samples += len;
249 if (s->current_position)
250 return samples;
251 }
252 /* Nesting has priority... */
253 if (tree->nest)
254 {
255 tree = tree->nest;
256 s->levels[++s->level] = tree;
257 s->cycles[s->level] = tree->cycles;
258 }
259 else
260 {
261 /* ...Next comes repeating, and finally moving forward a step. */
262 /* When repeating, note that zero cycles really means endless cycles. */
263 while (tree->cycles && --s->cycles[s->level] <= 0)
264 {
265 tree = tree->next;
266 if (tree)
267 {
268 /* A fresh new step. */
269 s->levels[s->level] = tree;
270 s->cycles[s->level] = tree->cycles;
271 break;
272 }
273 /* If we are nested we need to pop, otherwise this is the end. */
274 if (s->level <= 0)
275 {
276 /* Mark the tone as completed */
277 s->levels[0] = NULL;
278 break;
279 }
280 tree = s->levels[--s->level];
281 }
282 }
283
284 }
285 return samples;
286 }
287 /*- End of function --------------------------------------------------------*/
288 /*- End of file ------------------------------------------------------------*/

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