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>
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
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));
100
101 for(i = 0; i < 4; i++)
102 {
104 dtmf_detect_row[i].fac = (float)(2.0 * cos(theta));
105
107 dtmf_detect_col[i].fac = (float)(2.0 * cos(theta));
108
110 dtmf_detect_row_2nd[i].fac = (float)(2.0 * cos(theta));
111
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
121 }
122
123 // Same for the fax detector
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
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円';
139 }
140
141 DTMFDetect::~DTMFDetect()
142 {
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;
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;
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;
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;
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;
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;
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;
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;
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;
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
310 {
311 // Relative peak test
312 for(i = 0; i < 4; i++)
313 {
314 if ((i != best_col &&
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 &&
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.
335 state->digit_hits[(best_row << 2) + best_col]++;
336 state->detected_digits++;
337 if (
state->current_digits < 128) {
340 }
341 else {
342 state->lost_digits++;
343 }
344 }
345 }
346 }
347
349 fax_energy_2nd = goertzelResult(&
state->fax_tone2nd);
351 // XXX Probably need better checking than just this the energy
352 hit = 'f';
354 } /* Don't reset fax hits counter */
355 } else {
356 if (
state->fax_hits > 5) {
358 state->detected_digits++;
359 if (
state->current_digits < 128) {
362 }
363 else
364 state->lost_digits++;
365 }
367 }
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);
382 state->current_sample = 0;
383 }
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 BAYONNE_NAMESPACE
#define DTMF_REVERSE_TWIST
#define DTMF_RELATIVE_PEAK_ROW
#define DTMF_2ND_HARMONIC_COL
#define DTMF_NORMAL_TWIST
GNU Bayonne library namespace.
#define DTMF_2ND_HARMONIC_ROW
#define DTMF_RELATIVE_PEAK_COL