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