Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
detect.cpp
Go to the documentation of this file.
1 // Copyright (C) 2008-2011 David Sugar, Tycho Softworks.
2 //
3 // This file is part of GNU Bayonne.
4 //
5 // GNU Bayonne is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // GNU Bayonne is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with GNU Bayonne. If not, see <http://www.gnu.org/licenses/>.
17 
18 #include <config.h>
19 #include <ucommon/ucommon.h>
20 #include <ucommon/export.h>
21 #include <bayonne.h>
22 
23 #ifdef HAVE_MATH_H
24 #include <math.h>
25 #endif
26 
27 #ifdef HAVE_STDINT_H
28 #include <stdint.h>
29 #endif
30 
31 #ifndef M_PI
32 #define M_PI 3.14159265358979323846
33 #endif
34 
35 using namespace BAYONNE_NAMESPACE;
36 using namespace UCOMMON_NAMESPACE;
37 
38 //
39 // DTMF Receiver module, part of:
40 // BSD Telephony Of Mexico "Zapata" Telecom Library, version 1.10 12/9/01
41 //
42 // Part of the "Zapata" Computer Telephony Technology.
43 //
44 // See http://www.bsdtelephony.com.mx
45 //
46 // The technologies, software, hardware, designs, drawings, scheumatics, board
47 // layouts and/or artwork, concepts, methodologies (including the use of all
48 // of these, and that which is derived from the use of all of these), all other
49 // intellectual properties contained herein, and all intellectual property
50 // rights have been and shall continue to be expressly for the benefit of all
51 // mankind, and are perpetually placed in the public domain, and may be used,
52 // copied, and/or modified by anyone, in any manner, for any legal purpose,
53 // without restriction.
54 //
55 // tone_detect.c - General telephony tone detection, and specific
56 // detection of DTMF.
57 //
58 // Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
59 //
60 // Despite my general liking of the GPL, I place this code in the
61 // public domain for the benefit of all mankind - even the slimy
62 // ones who might try to proprietize my work and use it to my
63 // detriment.
64 //
65 
66 /* Basic DTMF specs:
67  *
68  * Minimum tone on = 40ms
69  * Minimum tone off = 50ms
70  * Maximum digit rate = 10 per second
71  * Normal twist <= 8dB accepted
72  * Reverse twist <= 4dB accepted
73  * S/N >= 15dB will detect OK
74  * Attenuation <= 26dB will detect OK
75  * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
76  */
77 
78 #define SAMPLE_RATE 8000.0
79 
80 #define DTMF_THRESHOLD 8.0e7
81 #define FAX_THRESHOLD 8.0e7
82 #define FAX_2ND_HARMONIC 2.0 /* 4dB */
83 #define DTMF_NORMAL_TWIST 8.0 /* 8dB */
84 #define DTMF_REVERSE_TWIST 4.0 /* 4dB normal */
85 #define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */
86 #define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */
87 #define DTMF_2ND_HARMONIC_ROW 2.5 /* 4dB normal */
88 #define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */
89 
90 DTMFDetect::DTMFDetect()
91 {
92  int i;
93  float theta;
94  static float dtmf_row[] = { 697.0, 770.0, 852.0, 941.0 };
95  static float dtmf_col[] = { 1209.0, 1336.0, 1477.0, 1633.0 };
96  static float fax_freq = 1100.0;
97 
98  state = (dtmf_detect_state_t *)malloc(sizeof(dtmf_detect_state_t));
99  memset(state, 0, sizeof(state));
100 
101  for(i = 0; i < 4; i++)
102  {
103  theta = (float)(2.0 * M_PI * (dtmf_row[i] / SAMPLE_RATE));
104  dtmf_detect_row[i].fac = (float)(2.0 * cos(theta));
105 
106  theta = (float)(2.0 * M_PI * (dtmf_col[i] / SAMPLE_RATE));
107  dtmf_detect_col[i].fac = (float)(2.0 * cos(theta));
108 
109  theta = (float)(2.0 * M_PI * (dtmf_row[i] * 2.0 / SAMPLE_RATE));
110  dtmf_detect_row_2nd[i].fac = (float)(2.0 * cos(theta));
111 
112  theta = (float)(2.0 * M_PI * (dtmf_col[i] * 2.0 / SAMPLE_RATE));
113  dtmf_detect_col_2nd[i].fac = (float)(2.0 * cos(theta));
114 
115  goertzelInit(&state->row_out[i], &dtmf_detect_row[i]);
116  goertzelInit(&state->col_out[i], &dtmf_detect_col[i]);
117  goertzelInit(&state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
118  goertzelInit(&state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
119 
120  state->energy = 0.0;
121  }
122 
123  // Same for the fax detector
124  theta = (float)(2.0 * M_PI * (fax_freq / SAMPLE_RATE));
125  fax_detect.fac = (float)(2.0 * cos(theta));
126  goertzelInit(&state->fax_tone, &fax_detect);
127 
128  // Same for the fax detector 2nd harmonic
129  theta = (float)(2.0 * M_PI * (fax_freq / SAMPLE_RATE));
130  fax_detect_2nd.fac = (float)(2.0 * cos(theta));
131  goertzelInit(&state->fax_tone2nd, &fax_detect_2nd);
132 
133  state->current_digits = 0;
134  state->current_sample = 0;
135  state->detected_digits = 0;
136  state->lost_digits = 0;
137  state->digits[0] = '\0';
138  state->mhit = 0;
139 }
140 
141 DTMFDetect::~DTMFDetect()
142 {
143  if(state) {
144  free(state);
145  state = NULL;
146  }
147  return;
148 }
149 
150 void DTMFDetect::goertzelInit(goertzel_state_t *s, tone_detection_descriptor_t *t)
151 {
152  s->v2 = s->v3 = 0.0;
153  s->fac = t->fac;
154 }
155 
156 void DTMFDetect::goertzelUpdate(goertzel_state_t *s,
157  sample_t x[],
158  int samples)
159 {
160  int i;
161  float v1;
162 
163  for (i = 0; i < samples; i++)
164  {
165  v1 = s->v2;
166  s->v2 = s->v3;
167  s->v3 = s->fac*s->v2 - v1 + x[i];
168  }
169 }
170 
171 float DTMFDetect::goertzelResult (goertzel_state_t *s)
172 {
173  return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 *s->v3 *s->fac;
174 }
175 
176 int DTMFDetect::putSamples(linear_t amp, int samples)
177 {
178  static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
179  float row_energy[4];
180  float col_energy[4];
181  float fax_energy;
182  float fax_energy_2nd;
183  float famp;
184  float v1;
185  int i;
186  int j;
187  int sample;
188  int best_row;
189  int best_col;
190  int hit;
191  int limit;
192 
193  hit = 0;
194  for (sample = 0; sample < samples; sample = limit)
195  {
196  // 102 is optimised to meet the DTMF specs.
197  if ((samples - sample) >= (102 - state->current_sample))
198  limit = sample + (102 - state->current_sample);
199  else
200  limit = samples;
201 
202  // The following unrolled loop takes only 35% (rough estimate) of the
203  // time of a rolled loop on the machine on which it was developed
204  for(j = sample; j < limit; j++)
205  {
206  famp = amp[j];
207  state->energy += famp*famp;
208 
209  // With GCC 2.95, the following unrolled code seems to take about 35%
210  // (rough estimate) as long as a neat little 0-3 loop
211  v1 = state->row_out[0].v2;
212  state->row_out[0].v2 = state->row_out[0].v3;
213  state->row_out[0].v3 = state->row_out[0].fac*state->row_out[0].v2 - v1 + famp;
214 
215  v1 = state->col_out[0].v2;
216  state->col_out[0].v2 = state->col_out[0].v3;
217  state->col_out[0].v3 = state->col_out[0].fac*state->col_out[0].v2 - v1 + famp;
218 
219  v1 = state->row_out[1].v2;
220  state->row_out[1].v2 = state->row_out[1].v3;
221  state->row_out[1].v3 = state->row_out[1].fac*state->row_out[1].v2 - v1 + famp;
222 
223  v1 = state->col_out[1].v2;
224  state->col_out[1].v2 = state->col_out[1].v3;
225  state->col_out[1].v3 = state->col_out[1].fac*state->col_out[1].v2 - v1 + famp;
226 
227  v1 = state->row_out[2].v2;
228  state->row_out[2].v2 = state->row_out[2].v3;
229  state->row_out[2].v3 = state->row_out[2].fac*state->row_out[2].v2 - v1 + famp;
230 
231  v1 = state->col_out[2].v2;
232  state->col_out[2].v2 = state->col_out[2].v3;
233  state->col_out[2].v3 = state->col_out[2].fac*state->col_out[2].v2 - v1 + famp;
234 
235  v1 = state->row_out[3].v2;
236  state->row_out[3].v2 = state->row_out[3].v3;
237  state->row_out[3].v3 = state->row_out[3].fac*state->row_out[3].v2 - v1 + famp;
238 
239  v1 = state->col_out[3].v2;
240  state->col_out[3].v2 = state->col_out[3].v3;
241  state->col_out[3].v3 = state->col_out[3].fac*state->col_out[3].v2 - v1 + famp;
242 
243  v1 = state->col_out2nd[0].v2;
244  state->col_out2nd[0].v2 = state->col_out2nd[0].v3;
245  state->col_out2nd[0].v3 = state->col_out2nd[0].fac*state->col_out2nd[0].v2 - v1 + famp;
246 
247  v1 = state->row_out2nd[0].v2;
248  state->row_out2nd[0].v2 = state->row_out2nd[0].v3;
249  state->row_out2nd[0].v3 = state->row_out2nd[0].fac*state->row_out2nd[0].v2 - v1 + famp;
250 
251  v1 = state->col_out2nd[1].v2;
252  state->col_out2nd[1].v2 = state->col_out2nd[1].v3;
253  state->col_out2nd[1].v3 = state->col_out2nd[1].fac*state->col_out2nd[1].v2 - v1 + famp;
254 
255  v1 = state->row_out2nd[1].v2;
256  state->row_out2nd[1].v2 = state->row_out2nd[1].v3;
257  state->row_out2nd[1].v3 = state->row_out2nd[1].fac*state->row_out2nd[1].v2 - v1 + famp;
258 
259  v1 = state->col_out2nd[2].v2;
260  state->col_out2nd[2].v2 = state->col_out2nd[2].v3;
261  state->col_out2nd[2].v3 = state->col_out2nd[2].fac*state->col_out2nd[2].v2 - v1 + famp;
262 
263  v1 = state->row_out2nd[2].v2;
264  state->row_out2nd[2].v2 = state->row_out2nd[2].v3;
265  state->row_out2nd[2].v3 = state->row_out2nd[2].fac*state->row_out2nd[2].v2 - v1 + famp;
266 
267  v1 = state->col_out2nd[3].v2;
268  state->col_out2nd[3].v2 = state->col_out2nd[3].v3;
269  state->col_out2nd[3].v3 = state->col_out2nd[3].fac*state->col_out2nd[3].v2 - v1 + famp;
270 
271  v1 = state->row_out2nd[3].v2;
272  state->row_out2nd[3].v2 = state->row_out2nd[3].v3;
273  state->row_out2nd[3].v3 = state->row_out2nd[3].fac*state->row_out2nd[3].v2 - v1 + famp;
274 
275  v1 = state->fax_tone.v2;
276  state->fax_tone.v2 = state->fax_tone.v3;
277  state->fax_tone.v3 = state->fax_tone.fac*state->fax_tone.v2 - v1 + famp;
278 
279  v1 = state->fax_tone.v2;
280  state->fax_tone2nd.v2 = state->fax_tone2nd.v3;
281  state->fax_tone2nd.v3 = state->fax_tone2nd.fac*state->fax_tone2nd.v2 - v1 + famp;
282  }
283  state->current_sample += (limit - sample);
284  if(state->current_sample < 102)
285  continue;
286 
287  fax_energy = goertzelResult(&state->fax_tone);
288 
289  // We are at the end of a DTMF detection block
290  // Find the peak row and the peak column
291  row_energy[0] = goertzelResult (&state->row_out[0]);
292  col_energy[0] = goertzelResult (&state->col_out[0]);
293 
294  for(best_row = best_col = 0, i = 1; i < 4; i++)
295  {
296  row_energy[i] = goertzelResult (&state->row_out[i]);
297  if(row_energy[i] > row_energy[best_row])
298  best_row = i;
299  col_energy[i] = goertzelResult (&state->col_out[i]);
300  if(col_energy[i] > col_energy[best_col])
301  best_col = i;
302  }
303  hit = 0;
304 
305  // Basic signal level test and the twist test
306  if(row_energy[best_row] >= DTMF_THRESHOLD &&
307  col_energy[best_col] >= DTMF_THRESHOLD &&
308  col_energy[best_col] < row_energy[best_row] * DTMF_REVERSE_TWIST &&
309  col_energy[best_col] * DTMF_NORMAL_TWIST > row_energy[best_row])
310  {
311  // Relative peak test
312  for(i = 0; i < 4; i++)
313  {
314  if ((i != best_col &&
315  col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
316  (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row]))
317  break;
318  }
319  // ... and second harmonic test
320  if(i >= 4 &&
321  (row_energy[best_row] + col_energy[best_col]) > 42.0*state->energy &&
322  goertzelResult (&state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] &&
323  goertzelResult (&state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row])
324  {
325  hit = dtmf_positions[(best_row << 2) + best_col];
326  // Look for two successive similar results
327  // The logic in the next test is:
328  // We need two successive identical clean detects, with
329  // something different preceeding it. This can work with
330  // back to back differing digits. More importantly, it
331  // can work with nasty phones that give a very wobbly start
332  // to a digit.
333  if (hit == state->hit3 && state->hit3 != state->hit2) {
334  state->mhit = hit;
335  state->digit_hits[(best_row << 2) + best_col]++;
336  state->detected_digits++;
337  if (state->current_digits < 128) {
338  state->digits[state->current_digits++] = hit;
339  state->digits[state->current_digits] = '\0';
340  }
341  else {
342  state->lost_digits++;
343  }
344  }
345  }
346  }
347 
348  if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > state->energy * 21.0)) {
349  fax_energy_2nd = goertzelResult(&state->fax_tone2nd);
350  if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) {
351  // XXX Probably need better checking than just this the energy
352  hit = 'f';
353  state->fax_hits++;
354  } /* Don't reset fax hits counter */
355  } else {
356  if (state->fax_hits > 5) {
357  state->mhit = 'f';
358  state->detected_digits++;
359  if (state->current_digits < 128) {
360  state->digits[state->current_digits++] = hit;
361  state->digits[state->current_digits] = '\0';
362  }
363  else
364  state->lost_digits++;
365  }
366  state->fax_hits = 0;
367  }
368  state->hit1 = state->hit2;
369  state->hit2 = state->hit3;
370  state->hit3 = hit;
371  // Reinitialise the detector for the next block
372  for (i = 0; i < 4; i++)
373  {
374  goertzelInit (&state->row_out[i], &dtmf_detect_row[i]);
375  goertzelInit (&state->col_out[i], &dtmf_detect_col[i]);
376  goertzelInit (&state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
377  goertzelInit (&state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
378  }
379  goertzelInit (&state->fax_tone, &fax_detect);
380  goertzelInit (&state->fax_tone2nd, &fax_detect_2nd);
381  state->energy = 0.0;
382  state->current_sample = 0;
383  }
384  if ((!state->mhit) || (state->mhit != hit)) {
385  state->mhit = 0;
386  return(0);
387  }
388  return (hit);
389 }
390 
391 int DTMFDetect::getResult(char *buf, int max)
392 {
393  if (max > state->current_digits)
394  max = state->current_digits;
395  if (max > 0) {
396  memcpy (buf, state->digits, max);
397  memmove (state->digits, state->digits + max, state->current_digits - max);
398  state->current_digits -= max;
399  }
400  buf[max] = '\0';
401  return max;
402 }
403 
404 
#define M_PI
Definition: detect.cpp:32
#define FAX_THRESHOLD
Definition: detect.cpp:81
#define BAYONNE_NAMESPACE
Definition: bayonne.h:25
#define DTMF_REVERSE_TWIST
Definition: detect.cpp:84
#define DTMF_RELATIVE_PEAK_ROW
Definition: detect.cpp:85
#define DTMF_2ND_HARMONIC_COL
Definition: detect.cpp:88
#define DTMF_NORMAL_TWIST
Definition: detect.cpp:83
#define SAMPLE_RATE
Definition: detect.cpp:78
GNU Bayonne library namespace.
#define DTMF_2ND_HARMONIC_ROW
Definition: detect.cpp:87
#define FAX_2ND_HARMONIC
Definition: detect.cpp:82
#define DTMF_THRESHOLD
Definition: detect.cpp:80
#define DTMF_RELATIVE_PEAK_COL
Definition: detect.cpp:86