Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/modem_connect_tones.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 |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * modem_connect_tones.c - Generation and detection of tones | |
5 * associated with modems calling and answering calls. | |
6 * | |
7 * Written by Steve Underwood <steveu@coppice.org> | |
8 * | |
9 * Copyright (C) 2006 Steve Underwood | |
10 * | |
11 * All rights reserved. | |
12 * | |
13 * This program is free software; you can redistribute it and/or modify | |
14 * it under the terms of the GNU General Public License version 2, as | |
15 * published by the Free Software Foundation. | |
16 * | |
17 * This program is distributed in the hope that it will be useful, | |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 * GNU General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU General Public License | |
23 * along with this program; if not, write to the Free Software | |
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 * | |
26 * $Id: modem_connect_tones.c,v 1.6 2006/11/30 15:41:47 steveu Exp $ | |
27 */ | |
28 | |
29 /*! \file */ | |
30 | |
31 #ifdef HAVE_CONFIG_H | |
32 #include <config.h> | |
33 #endif | |
34 | |
35 #include <inttypes.h> | |
36 #include <stdlib.h> | |
37 #if defined(HAVE_TGMATH_H) | |
38 #include <tgmath.h> | |
39 #endif | |
40 #if defined(HAVE_MATH_H) | |
41 #include <math.h> | |
42 #endif | |
43 | |
44 #include "spandsp/telephony.h" | |
45 #include "spandsp/dds.h" | |
46 #include "spandsp/tone_detect.h" | |
47 #include "spandsp/tone_generate.h" | |
48 #include "spandsp/super_tone_rx.h" | |
49 #include "spandsp/modem_connect_tones.h" | |
50 | |
51 int modem_connect_tones_tx(modem_connect_tones_tx_state_t *s, | |
52 int16_t amp[], | |
53 int len) | |
54 { | |
55 int mod; | |
56 int i; | |
57 | |
58 switch (s->tone_type) | |
59 { | |
60 case MODEM_CONNECT_TONES_FAX_CNG: | |
61 case MODEM_CONNECT_TONES_FAX_CED: | |
62 len = tone_gen(&s->tone_tx, amp, len); | |
63 break; | |
64 case MODEM_CONNECT_TONES_EC_DISABLE: | |
65 for (i = 0; i < len; i++) | |
66 { | |
67 if (--s->hop_timer <= 0) | |
68 { | |
69 s->hop_timer = ms_to_samples(450); | |
70 s->tone_phase += 0x80000000; | |
71 } | |
72 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); | |
73 } | |
74 break; | |
75 case MODEM_CONNECT_TONES_EC_DISABLE_MOD: | |
76 for (i = 0; i < len; i++) | |
77 { | |
78 mod = s->level + dds_mod(&s->mod_phase, s->mod_phase_rate, s->mod_level, 0); | |
79 if (--s->hop_timer <= 0) | |
80 { | |
81 s->hop_timer = ms_to_samples(450); | |
82 s->tone_phase += 0x80000000; | |
83 } | |
84 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, mod, 0); | |
85 } | |
86 break; | |
87 } | |
88 return len; | |
89 } | |
90 /*- End of function --------------------------------------------------------*/ | |
91 | |
92 modem_connect_tones_tx_state_t *modem_connect_tones_tx_init(modem_connect_tones_tx_state_t *s, | |
93 int tone_type) | |
94 { | |
95 tone_gen_descriptor_t tone_desc; | |
96 | |
97 s->tone_type = tone_type; | |
98 switch (s->tone_type) | |
99 { | |
100 case MODEM_CONNECT_TONES_FAX_CNG: | |
101 make_tone_gen_descriptor(&tone_desc, | |
102 1100, | |
103 -11, | |
104 0, | |
105 0, | |
106 500, | |
107 3000, | |
108 0, | |
109 0, | |
110 TRUE); | |
111 tone_gen_init(&s->tone_tx, &tone_desc); | |
112 break; | |
113 case MODEM_CONNECT_TONES_FAX_CED: | |
114 make_tone_gen_descriptor(&tone_desc, | |
115 2100, | |
116 -11, | |
117 0, | |
118 0, | |
119 2600, | |
120 0, | |
121 0, | |
122 0, | |
123 FALSE); | |
124 tone_gen_init(&s->tone_tx, &tone_desc); | |
125 break; | |
126 case MODEM_CONNECT_TONES_EC_DISABLE: | |
127 case MODEM_CONNECT_TONES_EC_DISABLE_MOD: | |
128 s->tone_phase_rate = dds_phase_rate(2100.0); | |
129 s->mod_phase_rate = dds_phase_rate(15.0); | |
130 s->tone_phase = 0; | |
131 s->mod_phase = 0; | |
132 s->hop_timer = ms_to_samples(450); | |
133 s->level = dds_scaling_dbm0(-12); | |
134 if (s->tone_type == MODEM_CONNECT_TONES_EC_DISABLE_MOD) | |
135 s->mod_level = s->level/5; | |
136 else | |
137 s->mod_level = 0; | |
138 } | |
139 return s; | |
140 } | |
141 /*- End of function --------------------------------------------------------*/ | |
142 | |
143 int modem_connect_tones_rx(modem_connect_tones_rx_state_t *s, const int16_t amp[], int len) | |
144 { | |
145 int i; | |
146 int16_t notched; | |
147 float v1; | |
148 float famp; | |
149 | |
150 switch (s->tone_type) | |
151 { | |
152 case MODEM_CONNECT_TONES_FAX_CNG: | |
153 for (i = 0; i < len; i++) | |
154 { | |
155 /* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth | |
156 criteria. */ | |
157 famp = amp[i]; | |
158 v1 = 0.792928f*famp + 1.0018744927985f*s->z1 - 0.54196833412465f*s->z2; | |
159 famp = v1 - 1.2994747954630f*s->z1 + s->z2; | |
160 s->z2 = s->z1; | |
161 s->z1 = v1; | |
162 notched = rintf(famp); | |
163 | |
164 /* Estimate the overall energy in the channel, and the energy in | |
165 the notch (i.e. overall channel energy - tone energy => noise). | |
166 Use abs instead of multiply for speed (is it really faster?). */ | |
167 s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); | |
168 s->notch_level += ((abs(notched) - s->notch_level) >> 5); | |
169 if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) | |
170 { | |
171 /* There is adequate energy in the channel, and it is mostly at 1100Hz. */ | |
172 if (!s->tone_present) | |
173 { | |
174 if (++s->tone_cycle_duration >= ms_to_samples(415)) | |
175 { | |
176 if (s->tone_callback) | |
177 s->tone_callback(s->callback_data, TRUE); | |
178 else | |
179 s->hit = TRUE; | |
180 s->tone_present = TRUE; | |
181 } | |
182 } | |
183 } | |
184 else | |
185 { | |
186 s->tone_cycle_duration = 0; | |
187 } | |
188 } | |
189 break; | |
190 case MODEM_CONNECT_TONES_FAX_CED: | |
191 for (i = 0; i < len; i++) | |
192 { | |
193 /* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth | |
194 criteria. */ | |
195 famp = amp[i]; | |
196 v1 = 0.76000f*famp - 0.1183852f*s->z1 - 0.5104039f*s->z2; | |
197 famp = v1 + 0.1567596f*s->z1 + s->z2; | |
198 s->z2 = s->z1; | |
199 s->z1 = v1; | |
200 notched = rintf(famp); | |
201 /* Estimate the overall energy in the channel, and the energy in | |
202 the notch (i.e. overall channel energy - tone energy => noise). | |
203 Use abs instead of multiply for speed (is it really faster?). */ | |
204 s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); | |
205 s->notch_level += ((abs(notched) - s->notch_level) >> 5); | |
206 if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) | |
207 { | |
208 /* There is adequate energy in the channel, and it is mostly at 2100Hz. */ | |
209 if (!s->tone_present) | |
210 { | |
211 if (++s->tone_cycle_duration >= ms_to_samples(500)) | |
212 { | |
213 if (s->tone_callback) | |
214 s->tone_callback(s->callback_data, TRUE); | |
215 else | |
216 s->hit = TRUE; | |
217 s->tone_present = TRUE; | |
218 } | |
219 } | |
220 } | |
221 else | |
222 { | |
223 s->tone_cycle_duration = 0; | |
224 } | |
225 } | |
226 break; | |
227 case MODEM_CONNECT_TONES_EC_DISABLE: | |
228 case MODEM_CONNECT_TONES_EC_DISABLE_MOD: | |
229 for (i = 0; i < len; i++) | |
230 { | |
231 /* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth | |
232 criteria. */ | |
233 /* This is actually centred at 2095Hz, but gets the balance we want, due | |
234 to the asymmetric walls of the notch */ | |
235 famp = amp[i]; | |
236 v1 = 0.76000f*famp - 0.1183852f*s->z1 - 0.5104039f*s->z2; | |
237 famp = v1 + 0.1567596f*s->z1 + s->z2; | |
238 s->z2 = s->z1; | |
239 s->z1 = v1; | |
240 notched = rintf(famp); | |
241 /* Estimate the overall energy in the channel, and the energy in | |
242 the notch (i.e. overall channel energy - tone energy => noise). | |
243 Use abs instead of multiply for speed (is it really faster?). | |
244 Damp the overall energy a little more for a stable result. | |
245 Damp the notch energy a little less, so we don't damp out the | |
246 blip every time the phase reverses */ | |
247 s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); | |
248 s->notch_level += ((abs(notched) - s->notch_level) >> 4); | |
249 if (s->channel_level > 280) | |
250 { | |
251 /* There is adequate energy in the channel. Is it mostly at 2100Hz? */ | |
252 if (s->notch_level*6 < s->channel_level) | |
253 { | |
254 /* The notch says yes, so we have the tone. */ | |
255 if (!s->tone_present) | |
256 { | |
257 /* Do we get a kick every 450+-25ms? */ | |
258 if (s->tone_cycle_duration >= ms_to_samples(425) | |
259 && | |
260 s->tone_cycle_duration <= ms_to_samples(475)) | |
261 { | |
262 if (++s->good_cycles > 2) | |
263 { | |
264 if (s->tone_callback) | |
265 s->tone_callback(s->callback_data, TRUE); | |
266 else | |
267 s->hit = TRUE; | |
268 } | |
269 } | |
270 s->tone_cycle_duration = 0; | |
271 s->tone_present = TRUE; | |
272 } | |
273 } | |
274 else | |
275 { | |
276 s->tone_present = FALSE; | |
277 } | |
278 s->tone_cycle_duration++; | |
279 } | |
280 else | |
281 { | |
282 s->tone_present = FALSE; | |
283 s->tone_cycle_duration = 0; | |
284 s->good_cycles = 0; | |
285 } | |
286 } | |
287 } | |
288 return 0; | |
289 } | |
290 /*- End of function --------------------------------------------------------*/ | |
291 | |
292 int modem_connect_tones_rx_get(modem_connect_tones_rx_state_t *s) | |
293 { | |
294 int x; | |
295 | |
296 x = s->hit; | |
297 s->hit = FALSE; | |
298 return x; | |
299 } | |
300 /*- End of function --------------------------------------------------------*/ | |
301 | |
302 modem_connect_tones_rx_state_t *modem_connect_tones_rx_init(modem_connect_tones_rx_state_t *s, | |
303 int tone_type, | |
304 tone_report_func_t tone_callback, | |
305 void *user_data) | |
306 { | |
307 s->tone_type = tone_type; | |
308 s->channel_level = 0; | |
309 s->notch_level = 0; | |
310 s->tone_present = FALSE; | |
311 s->tone_cycle_duration = 0; | |
312 s->good_cycles = 0; | |
313 s->hit = FALSE; | |
314 s->tone_callback = tone_callback; | |
315 s->callback_data = user_data; | |
316 s->z1 = 0.0f; | |
317 s->z2 = 0.0f; | |
318 return s; | |
319 } | |
320 /*- End of function --------------------------------------------------------*/ | |
321 /*- End of file ------------------------------------------------------------*/ |