5
|
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 ------------------------------------------------------------*/
|