Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/sig_tone.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 * sig_tone.c - Signalling tone processing for the 2280Hz, 2600Hz and similar | |
5 * signalling tone used in older protocols. | |
6 * | |
7 * Written by Steve Underwood <steveu@coppice.org> | |
8 * | |
9 * Copyright (C) 2004 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: sig_tone.c,v 1.15 2006/11/19 14:07:25 steveu Exp $ | |
27 */ | |
28 | |
29 /*! \file */ | |
30 | |
31 #ifdef HAVE_CONFIG_H | |
32 #include <config.h> | |
33 #endif | |
34 | |
35 #include <stdlib.h> | |
36 #include <stdio.h> | |
37 #include <inttypes.h> | |
38 #if defined(HAVE_TGMATH_H) | |
39 #include <tgmath.h> | |
40 #endif | |
41 #if defined(HAVE_MATH_H) | |
42 #include <math.h> | |
43 #endif | |
44 #include <memory.h> | |
45 #include <string.h> | |
46 | |
47 #include "spandsp/telephony.h" | |
48 #include "spandsp/dc_restore.h" | |
49 #include "spandsp/dds.h" | |
50 #include "spandsp/sig_tone.h" | |
51 | |
52 #define PI 3.14159265358979323 | |
53 | |
54 /* The coefficients for the data notch filter. This filter is also the | |
55 guard filter for tone detection. */ | |
56 | |
57 sig_tone_descriptor_t sig_tones[4] = | |
58 { | |
59 { | |
60 /* 2280Hz (e.g. AC15, and many other European protocols) */ | |
61 {2280, 0}, | |
62 {-10, -20}, | |
63 400*8, | |
64 | |
65 225*8, | |
66 | |
67 225*8, | |
68 TRUE, | |
69 | |
70 24, | |
71 64, | |
72 | |
73 { 3600, 14397, 32767}, | |
74 { 0, -9425, -28954}, | |
75 { 0, 14196, 32767}, | |
76 { 0, -17393, -28954}, | |
77 12, | |
78 /* | |
79 0.1098633, 0.4393615, 1.0, | |
80 0, -0.2876274, -0.8836059, | |
81 0, 0.4332275, 1.0, | |
82 0, -0.5307922, -0.8836059, | |
83 */ | |
84 { 12900, -16384, -16384}, | |
85 { 0, -8578, -11796}, | |
86 15, | |
87 | |
88 31744, | |
89 1024, | |
90 | |
91 31744, | |
92 187, | |
93 | |
94 31744, | |
95 187, | |
96 | |
97 -1, | |
98 -32, | |
99 | |
100 57 | |
101 }, | |
102 { | |
103 /* 2600Hz (e.g. many US protocols) */ | |
104 {2600, 0}, | |
105 {-8, -8}, | |
106 400*8, | |
107 | |
108 225*8, | |
109 | |
110 225*8, | |
111 FALSE, | |
112 | |
113 24, | |
114 64, | |
115 | |
116 { 3539, 29569, 32767}, | |
117 { 0, -24010, -28341}, | |
118 { 0, 29844, 32767}, | |
119 { 0, -31208, -28341}, | |
120 12, | |
121 /* | |
122 0.1080017, 0.9023743, 1.0, | |
123 0, -0.7327271, -0.86489868, | |
124 0, 0.9107666, 1.0, | |
125 0, -0.9523925, -0.86489868, | |
126 */ | |
127 { 32768, 0, 0}, | |
128 { 0, 0, 0}, | |
129 15, | |
130 | |
131 31744, | |
132 1024, | |
133 | |
134 31744, | |
135 170, | |
136 | |
137 31744, | |
138 170, | |
139 | |
140 -1, | |
141 -32, | |
142 | |
143 52 | |
144 }, | |
145 { | |
146 /* 2400Hz / 2600Hz (e.g. SS5 and SS5bis) */ | |
147 {2400, 2600}, | |
148 {-8, -8}, | |
149 400*8, | |
150 | |
151 225*8, | |
152 | |
153 225*8, | |
154 FALSE, | |
155 | |
156 24, | |
157 64, | |
158 | |
159 { 3539, 20349, 32767}, | |
160 { 0, -22075, -31856}, | |
161 { 0, 20174, 32767}, | |
162 { 0, -17832, -31836}, | |
163 12, | |
164 /* | |
165 0.1080017, 0.6210065, 1.0, | |
166 0, -0.6736673, -0.9721678, | |
167 0, 0.6156693, 1.0, | |
168 0, -0.5441804, -0.9715460, | |
169 */ | |
170 | |
171 { 32768, 0, 0}, | |
172 { 0, 0, 0}, | |
173 15, | |
174 | |
175 31744, | |
176 1024, | |
177 | |
178 31744, | |
179 170, | |
180 | |
181 31744, | |
182 170, | |
183 | |
184 -1, | |
185 -32, | |
186 | |
187 52 | |
188 } | |
189 }; | |
190 | |
191 int sig_tone_rx(sig_tone_state_t *s, int16_t amp[], int len) | |
192 { | |
193 int32_t x; | |
194 int32_t notched_signal; | |
195 int32_t bandpass_signal; | |
196 int i; | |
197 | |
198 for (i = 0; i < len; i++) | |
199 { | |
200 if (s->signaling_state_duration < 0xFFFF) | |
201 s->signaling_state_duration++; | |
202 /*endif*/ | |
203 /* The notch filter is two cascaded biquads. */ | |
204 notched_signal = amp[i]; | |
205 | |
206 notched_signal *= s->desc->notch_a1[0]; | |
207 notched_signal += s->notch_z1[1]*s->desc->notch_b1[1]; | |
208 notched_signal += s->notch_z1[2]*s->desc->notch_b1[2]; | |
209 x = notched_signal; | |
210 notched_signal += s->notch_z1[1]*s->desc->notch_a1[1]; | |
211 notched_signal += s->notch_z1[2]*s->desc->notch_a1[2]; | |
212 s->notch_z1[2] = s->notch_z1[1]; | |
213 s->notch_z1[1] = x >> 15; | |
214 | |
215 notched_signal += s->notch_z2[1]*s->desc->notch_b2[1]; | |
216 notched_signal += s->notch_z2[2]*s->desc->notch_b2[2]; | |
217 x = notched_signal; | |
218 notched_signal += s->notch_z2[1]*s->desc->notch_a2[1]; | |
219 notched_signal += s->notch_z2[2]*s->desc->notch_a2[2]; | |
220 s->notch_z2[2] = s->notch_z2[1]; | |
221 s->notch_z2[1] = x >> 15; | |
222 | |
223 notched_signal >>= s->desc->notch_postscale; | |
224 | |
225 /* Modulus and leaky integrate the notched data. The result of | |
226 this isn't used in low tone detect mode, but we must keep notch_zl | |
227 rolling along. */ | |
228 s->notch_zl = ((s->notch_zl*s->desc->notch_slugi) >> 15) | |
229 + ((abs(notched_signal)*s->desc->notch_slugp) >> 15); | |
230 | |
231 /* Mow the grass to weed out the noise! */ | |
232 s->mown_notch = s->notch_zl & s->desc->notch_threshold; | |
233 | |
234 if (s->tone_present) | |
235 { | |
236 if (s->flat_mode_timeout <= 0) | |
237 s->flat_mode = TRUE; | |
238 else | |
239 s->flat_mode_timeout--; | |
240 /*endif*/ | |
241 } | |
242 else | |
243 { | |
244 s->flat_mode_timeout = s->desc->sharp_flat_timeout; | |
245 s->flat_mode = FALSE; | |
246 } | |
247 /*endif*/ | |
248 | |
249 if (s->flat_mode) | |
250 { | |
251 /* Flat mode */ | |
252 | |
253 /* The bandpass filter is a single bi-quad stage */ | |
254 bandpass_signal = amp[i]; | |
255 bandpass_signal *= s->desc->broad_a[0]; | |
256 bandpass_signal += s->broad_z[1]*s->desc->broad_b[1]; | |
257 bandpass_signal += s->broad_z[2]*s->desc->broad_b[2]; | |
258 x = bandpass_signal; | |
259 bandpass_signal += s->broad_z[1]*s->desc->broad_a[1]; | |
260 bandpass_signal += s->broad_z[2]*s->desc->broad_a[2]; | |
261 s->broad_z[2] = s->broad_z[1]; | |
262 s->broad_z[1] = x >> 15; | |
263 bandpass_signal >>= s->desc->broad_postscale; | |
264 | |
265 /* Leaky integrate the bandpassed data */ | |
266 s->broad_zl = ((s->broad_zl*s->desc->broad_slugi) >> 15) | |
267 + ((abs(bandpass_signal)*s->desc->broad_slugp) >> 15); | |
268 | |
269 /* For the broad band receiver we use a simple linear threshold! */ | |
270 if (s->tone_present) | |
271 { | |
272 s->tone_present = (s->broad_zl > s->desc->broad_threshold); | |
273 if (!s->tone_present) | |
274 { | |
275 if (s->sig_update) | |
276 s->sig_update(s->user_data, SIG_TONE_1_CHANGE | (s->signaling_state_duration << 16)); | |
277 /*endif*/ | |
278 s->signaling_state_duration = 0; | |
279 } | |
280 /*endif*/ | |
281 } | |
282 else | |
283 { | |
284 s->tone_present = (s->broad_zl > s->desc->broad_threshold); | |
285 if (s->tone_present) | |
286 { | |
287 if (s->sig_update) | |
288 s->sig_update(s->user_data, SIG_TONE_1_CHANGE | SIG_TONE_1_PRESENT | (s->signaling_state_duration << 16)); | |
289 /*endif*/ | |
290 s->signaling_state_duration = 0; | |
291 } | |
292 /*endif*/ | |
293 } | |
294 /*endif*/ | |
295 /* Notch insertion logic */ | |
296 | |
297 /* tone_present and tone_on are equivalent in flat mode */ | |
298 if (s->tone_present) | |
299 { | |
300 s->notch_enabled = s->desc->notch_allowed; | |
301 s->notch_insertion_timeout = s->desc->notch_lag_time; | |
302 } | |
303 else | |
304 { | |
305 if (s->notch_insertion_timeout > 0) | |
306 s->notch_insertion_timeout--; | |
307 else | |
308 s->notch_enabled = FALSE; | |
309 /*endif*/ | |
310 } | |
311 /*endif*/ | |
312 } | |
313 else | |
314 { | |
315 /* Sharp mode */ | |
316 | |
317 /* Modulus and leaky integrate the data */ | |
318 s->broad_zl = ((s->broad_zl*s->desc->unfiltered_slugi) >> 15) | |
319 + ((abs(amp[i])*s->desc->unfiltered_slugp) >> 15); | |
320 | |
321 /* Mow the grass to weed out the noise! */ | |
322 s->mown_bandpass = s->broad_zl & s->desc->unfiltered_threshold; | |
323 | |
324 /* Persistence checking and notch insertion logic */ | |
325 if (!s->tone_present) | |
326 { | |
327 if (s->mown_notch < s->mown_bandpass) | |
328 { | |
329 /* Tone is detected this sample */ | |
330 if (s->tone_persistence_timeout <= 0) | |
331 { | |
332 s->tone_present = TRUE; | |
333 s->notch_enabled = s->desc->notch_allowed; | |
334 s->tone_persistence_timeout = s->desc->tone_off_check_time; | |
335 s->notch_insertion_timeout = s->desc->notch_lag_time; | |
336 if (s->sig_update) | |
337 s->sig_update(s->user_data, SIG_TONE_1_CHANGE | SIG_TONE_1_PRESENT | (s->signaling_state_duration << 16)); | |
338 /*endif*/ | |
339 s->signaling_state_duration = 0; | |
340 } | |
341 else | |
342 { | |
343 s->tone_persistence_timeout--; | |
344 if (s->notch_insertion_timeout > 0) | |
345 s->notch_insertion_timeout--; | |
346 else | |
347 s->notch_enabled = FALSE; | |
348 /*endif*/ | |
349 } | |
350 /*endif*/ | |
351 } | |
352 else | |
353 { | |
354 s->tone_persistence_timeout = s->desc->tone_on_check_time; | |
355 if (s->notch_insertion_timeout > 0) | |
356 s->notch_insertion_timeout--; | |
357 else | |
358 s->notch_enabled = FALSE; | |
359 /*endif*/ | |
360 } | |
361 /*endif*/ | |
362 } | |
363 else | |
364 { | |
365 if (s->mown_notch > s->mown_bandpass) | |
366 { | |
367 /* Tone is not detected this sample */ | |
368 if (s->tone_persistence_timeout <= 0) | |
369 { | |
370 s->tone_present = FALSE; | |
371 s->tone_persistence_timeout = s->desc->tone_on_check_time; | |
372 if (s->sig_update) | |
373 s->sig_update(s->user_data, SIG_TONE_1_CHANGE | (s->signaling_state_duration << 16)); | |
374 /*endif*/ | |
375 s->signaling_state_duration = 0; | |
376 } | |
377 else | |
378 { | |
379 s->tone_persistence_timeout--; | |
380 } | |
381 /*endif*/ | |
382 } | |
383 else | |
384 { | |
385 s->tone_persistence_timeout = s->desc->tone_off_check_time; | |
386 } | |
387 /*endif*/ | |
388 } | |
389 /*endif*/ | |
390 } | |
391 /*endif*/ | |
392 | |
393 if ((s->current_tx_tone & SIG_TONE_RX_PASSTHROUGH)) | |
394 { | |
395 //if (s->notch_enabled) | |
396 amp[i] = (int16_t) notched_signal; | |
397 /*endif*/ | |
398 } | |
399 else | |
400 { | |
401 amp[i] = 0; | |
402 } | |
403 /*endif*/ | |
404 } | |
405 /*endfor*/ | |
406 return len; | |
407 } | |
408 /*- End of function --------------------------------------------------------*/ | |
409 | |
410 int sig_tone_tx(sig_tone_state_t *s, int16_t amp[], int len) | |
411 { | |
412 int i; | |
413 int16_t tone; | |
414 int update; | |
415 int high_low; | |
416 | |
417 if (s->current_tx_tone & SIG_TONE_1_PRESENT) | |
418 { | |
419 for (i = 0; i < len; i++) | |
420 { | |
421 if (s->high_low_timer > 0 && --s->high_low_timer > 0) | |
422 high_low = 1; | |
423 else | |
424 high_low = 0; | |
425 /*endif*/ | |
426 tone = dds_mod(&(s->phase_acc[0]), s->phase_rate[0], s->tone_scaling[high_low], 0); | |
427 if (s->current_tx_tone & SIG_TONE_TX_PASSTHROUGH) | |
428 amp[i] = saturate(amp[i] + tone); | |
429 else | |
430 amp[i] = tone; | |
431 /*endif*/ | |
432 if (--s->current_tx_timeout <= 0) | |
433 { | |
434 if (s->sig_update) | |
435 { | |
436 update = s->sig_update(s->user_data, SIG_TONE_UPDATE_REQUEST); | |
437 if ((update & 0x03) == 0x03 && !(s->current_tx_tone & SIG_TONE_1_PRESENT)) | |
438 s->high_low_timer = s->desc->high_low_timeout; | |
439 /*endif*/ | |
440 s->current_tx_tone = update & 0xFFFF; | |
441 s->current_tx_timeout = (update >> 16) & 0xFFFF; | |
442 } | |
443 /*endif*/ | |
444 } | |
445 /*endif*/ | |
446 } | |
447 /*endfor*/ | |
448 } | |
449 else | |
450 { | |
451 for (i = 0; i < len; ) | |
452 { | |
453 if (s->current_tx_timeout < len - i) | |
454 { | |
455 if (!(s->current_tx_tone & SIG_TONE_TX_PASSTHROUGH)) | |
456 { | |
457 /* Zap any audio in the buffer */ | |
458 memset(amp + i, 0, sizeof(int16_t)*s->current_tx_timeout); | |
459 } | |
460 /*endif*/ | |
461 i += s->current_tx_timeout; | |
462 if (s->sig_update) | |
463 { | |
464 update = s->sig_update(s->user_data, SIG_TONE_UPDATE_REQUEST); | |
465 if ((update & 0x03) == 0x03) | |
466 s->high_low_timer = s->desc->high_low_timeout; | |
467 /*endif*/ | |
468 s->current_tx_tone = update & 0xFFFF; | |
469 s->current_tx_timeout = (update >> 16) & 0xFFFF; | |
470 } | |
471 /*endif*/ | |
472 } | |
473 else | |
474 { | |
475 s->current_tx_timeout -= (len - i); | |
476 if (!(s->current_tx_tone & SIG_TONE_TX_PASSTHROUGH)) | |
477 { | |
478 /* Zap any audio in the buffer */ | |
479 memset(amp + i, 0, sizeof(int16_t)*(len - i)); | |
480 i = len; | |
481 } | |
482 /*endif*/ | |
483 } | |
484 /*endif*/ | |
485 } | |
486 /*endfor*/ | |
487 } | |
488 /*endif*/ | |
489 return len; | |
490 } | |
491 /*- End of function --------------------------------------------------------*/ | |
492 | |
493 sig_tone_state_t *sig_tone_init(sig_tone_state_t *s, int tone_type, sig_tone_func_t sig_update, void *user_data) | |
494 { | |
495 if (tone_type <= 0 || tone_type > 3) | |
496 return NULL; | |
497 /*endif*/ | |
498 | |
499 memset(s, 0, sizeof(*s)); | |
500 | |
501 s->sig_update = sig_update; | |
502 s->user_data = user_data; | |
503 | |
504 s->desc = &sig_tones[tone_type - 1]; | |
505 | |
506 /* Set up the transmit side */ | |
507 s->phase_rate[0] = dds_phase_rate((float) s->desc->tone_freq[0]); | |
508 if (s->desc->tone_freq[1]) | |
509 s->phase_rate[1] = dds_phase_rate((float) s->desc->tone_freq[1]); | |
510 else | |
511 s->phase_rate[1] = 0; | |
512 /*endif*/ | |
513 s->tone_scaling[0] = dds_scaling_dbm0((float) s->desc->tone_amp[0]); | |
514 s->tone_scaling[1] = dds_scaling_dbm0((float) s->desc->tone_amp[1]); | |
515 | |
516 /* Set up the receive side */ | |
517 s->flat_mode_timeout = 0; | |
518 s->notch_insertion_timeout = 0; | |
519 s->tone_persistence_timeout = 0; | |
520 s->signaling_state_duration = 0; | |
521 return s; | |
522 } | |
523 /*- End of function --------------------------------------------------------*/ | |
524 /*- End of file ------------------------------------------------------------*/ |