2 * DTMF Receiver module, part of:
3 * BSD Telephony Of Mexico "Zapata" Telecom Library, version 1.10 12/9/01
5 * Part of the "Zapata" Computer Telephony Technology.
7 * See http://www.bsdtelephony.com.mx
10 * The technologies, software, hardware, designs, drawings, scheumatics, board
11 * layouts and/or artwork, concepts, methodologies (including the use of all
12 * of these, and that which is derived from the use of all of these), all other
13 * intellectual properties contained herein, and all intellectual property
14 * rights have been and shall continue to be expressly for the benefit of all
15 * mankind, and are perpetually placed in the public domain, and may be used,
16 * copied, and/or modified by anyone, in any manner, for any legal purpose,
17 * without restriction.
19 * This module written by Stephen Underwood.
23 tone_detect.c - General telephony tone detection, and specific
26 Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
28 Despite my general liking of the GPL, I place this code in the
29 public domain for the benefit of all mankind - even the slimy
30 ones who might try to proprietize my work and use it to my
39 #include "tone_detect.h"
52 * Minimum tone on = 40ms
53 * Minimum tone off = 50ms
54 * Maximum digit rate = 10 per second
55 * Normal twist <= 8dB accepted
56 * Reverse twist <= 4dB accepted
57 * S/N >= 15dB will detect OK
58 * Attenuation <= 26dB will detect OK
59 * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
62 #define SAMPLE_RATE 8000.0
64 #define DTMF_THRESHOLD 8.0e7
65 #define FAX_THRESHOLD 8.0e7
66 #define FAX_2ND_HARMONIC 2.0 /* 4dB */
67 #define DTMF_NORMAL_TWIST 6.3 /* 8dB */
68 #define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */
69 #define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */
70 #define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */
71 #define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */
72 #define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */
74 static tone_detection_descriptor_t dtmf_detect_row[4];
75 static tone_detection_descriptor_t dtmf_detect_col[4];
76 static tone_detection_descriptor_t dtmf_detect_row_2nd[4];
77 static tone_detection_descriptor_t dtmf_detect_col_2nd[4];
78 static tone_detection_descriptor_t fax_detect;
79 static tone_detection_descriptor_t fax_detect_2nd;
81 static float dtmf_row[] = {
82 697.0, 770.0, 852.0, 941.0
85 static float dtmf_col[] = {
86 1209.0, 1336.0, 1477.0, 1633.0
89 static float fax_freq = 1100.0;
91 static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
94 goertzel_init (goertzel_state_t * s, tone_detection_descriptor_t * t)
100 /*- End of function --------------------------------------------------------*/
102 #if defined(USE_3DNOW)
104 _dtmf_goertzel_update (goertzel_state_t * s, float x[], int samples)
126 //s->v3 = s->fac*s->v2 - v1 + x[0];
128 __asm__ __volatile__ (" femms;\n"
129 " movq 16(%%edx),%%mm2;\n"
130 " movq 24(%%edx),%%mm3;\n"
131 " movq 32(%%edx),%%mm4;\n"
132 " movq 40(%%edx),%%mm5;\n"
133 " movq 48(%%edx),%%mm6;\n"
134 " movq 56(%%edx),%%mm7;\n"
138 " prefetch (%%eax);\n"
139 " movq %%mm3,%%mm1;\n"
140 " movq %%mm2,%%mm0;\n"
141 " movq %%mm5,%%mm3;\n"
142 " movq %%mm4,%%mm2;\n"
143 " pfmul %%mm7,%%mm5;\n"
144 " pfmul %%mm6,%%mm4;\n"
145 " pfsub %%mm1,%%mm5;\n"
146 " pfsub %%mm0,%%mm4;\n"
147 " movq (%%eax),%%mm0;\n"
148 " movq %%mm0,%%mm1;\n"
149 " punpckldq %%mm0,%%mm1;\n"
151 " pfadd %%mm1,%%mm5;\n"
152 " pfadd %%mm1,%%mm4;\n"
155 " movq %%mm2,16(%%edx);\n"
156 " movq %%mm3,24(%%edx);\n"
157 " movq %%mm4,32(%%edx);\n"
158 " movq %%mm5,40(%%edx);\n"
159 " femms;\n"::"c" (samples), "a" (x), "d" (vv)
160 :"memory", "eax", "ecx");
172 /*- End of function --------------------------------------------------------*/
175 zap_goertzel_update (goertzel_state_t * s, int16_t x[], int samples)
180 for (i = 0; i < samples; i++) {
183 s->v3 = s->fac * s->v2 - v1 + x[i];
187 /*- End of function --------------------------------------------------------*/
190 zap_goertzel_result (goertzel_state_t * s)
192 return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac;
195 /*- End of function --------------------------------------------------------*/
198 zap_dtmf_detect_init (dtmf_detect_state_t * s)
203 s->hit1 = s->hit2 = 0;
205 for (i = 0; i < 4; i++) {
206 theta = 2.0 * G_PI * (dtmf_row[i] / SAMPLE_RATE);
207 dtmf_detect_row[i].fac = 2.0 * cos (theta);
209 theta = 2.0 * G_PI * (dtmf_col[i] / SAMPLE_RATE);
210 dtmf_detect_col[i].fac = 2.0 * cos (theta);
212 theta = 2.0 * G_PI * (dtmf_row[i] * 2.0 / SAMPLE_RATE);
213 dtmf_detect_row_2nd[i].fac = 2.0 * cos (theta);
215 theta = 2.0 * G_PI * (dtmf_col[i] * 2.0 / SAMPLE_RATE);
216 dtmf_detect_col_2nd[i].fac = 2.0 * cos (theta);
218 goertzel_init (&s->row_out[i], &dtmf_detect_row[i]);
219 goertzel_init (&s->col_out[i], &dtmf_detect_col[i]);
220 goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]);
221 goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]);
226 /* Same for the fax dector */
227 theta = 2.0 * G_PI * (fax_freq / SAMPLE_RATE);
228 fax_detect.fac = 2.0 * cos (theta);
229 goertzel_init (&s->fax_tone, &fax_detect);
231 /* Same for the fax dector 2nd harmonic */
232 theta = 2.0 * G_PI * (fax_freq * 2.0 / SAMPLE_RATE);
233 fax_detect_2nd.fac = 2.0 * cos (theta);
234 goertzel_init (&s->fax_tone2nd, &fax_detect_2nd);
236 s->current_sample = 0;
237 s->detected_digits = 0;
243 /*- End of function --------------------------------------------------------*/
246 zap_dtmf_detect (dtmf_detect_state_t * s,
247 int16_t amp[], int samples, int isradio)
253 float fax_energy_2nd;
265 for (sample = 0; sample < samples; sample = limit) {
266 /* 102 is optimised to meet the DTMF specs. */
267 if ((samples - sample) >= (102 - s->current_sample))
268 limit = sample + (102 - s->current_sample);
271 #if defined(USE_3DNOW)
272 _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
273 _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
274 _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
275 _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
276 /* XXX Need to fax detect for 3dnow too XXX */
277 #warning "Fax Support Broken"
279 /* The following unrolled loop takes only 35% (rough estimate) of the
280 time of a rolled loop on the machine on which it was developed */
281 for (j = sample; j < limit; j++) {
284 s->energy += famp * famp;
286 /* With GCC 2.95, the following unrolled code seems to take about 35%
287 (rough estimate) as long as a neat little 0-3 loop */
288 v1 = s->row_out[0].v2;
289 s->row_out[0].v2 = s->row_out[0].v3;
290 s->row_out[0].v3 = s->row_out[0].fac * s->row_out[0].v2 - v1 + famp;
292 v1 = s->col_out[0].v2;
293 s->col_out[0].v2 = s->col_out[0].v3;
294 s->col_out[0].v3 = s->col_out[0].fac * s->col_out[0].v2 - v1 + famp;
296 v1 = s->row_out[1].v2;
297 s->row_out[1].v2 = s->row_out[1].v3;
298 s->row_out[1].v3 = s->row_out[1].fac * s->row_out[1].v2 - v1 + famp;
300 v1 = s->col_out[1].v2;
301 s->col_out[1].v2 = s->col_out[1].v3;
302 s->col_out[1].v3 = s->col_out[1].fac * s->col_out[1].v2 - v1 + famp;
304 v1 = s->row_out[2].v2;
305 s->row_out[2].v2 = s->row_out[2].v3;
306 s->row_out[2].v3 = s->row_out[2].fac * s->row_out[2].v2 - v1 + famp;
308 v1 = s->col_out[2].v2;
309 s->col_out[2].v2 = s->col_out[2].v3;
310 s->col_out[2].v3 = s->col_out[2].fac * s->col_out[2].v2 - v1 + famp;
312 v1 = s->row_out[3].v2;
313 s->row_out[3].v2 = s->row_out[3].v3;
314 s->row_out[3].v3 = s->row_out[3].fac * s->row_out[3].v2 - v1 + famp;
316 v1 = s->col_out[3].v2;
317 s->col_out[3].v2 = s->col_out[3].v3;
318 s->col_out[3].v3 = s->col_out[3].fac * s->col_out[3].v2 - v1 + famp;
320 v1 = s->col_out2nd[0].v2;
321 s->col_out2nd[0].v2 = s->col_out2nd[0].v3;
322 s->col_out2nd[0].v3 =
323 s->col_out2nd[0].fac * s->col_out2nd[0].v2 - v1 + famp;
325 v1 = s->row_out2nd[0].v2;
326 s->row_out2nd[0].v2 = s->row_out2nd[0].v3;
327 s->row_out2nd[0].v3 =
328 s->row_out2nd[0].fac * s->row_out2nd[0].v2 - v1 + famp;
330 v1 = s->col_out2nd[1].v2;
331 s->col_out2nd[1].v2 = s->col_out2nd[1].v3;
332 s->col_out2nd[1].v3 =
333 s->col_out2nd[1].fac * s->col_out2nd[1].v2 - v1 + famp;
335 v1 = s->row_out2nd[1].v2;
336 s->row_out2nd[1].v2 = s->row_out2nd[1].v3;
337 s->row_out2nd[1].v3 =
338 s->row_out2nd[1].fac * s->row_out2nd[1].v2 - v1 + famp;
340 v1 = s->col_out2nd[2].v2;
341 s->col_out2nd[2].v2 = s->col_out2nd[2].v3;
342 s->col_out2nd[2].v3 =
343 s->col_out2nd[2].fac * s->col_out2nd[2].v2 - v1 + famp;
345 v1 = s->row_out2nd[2].v2;
346 s->row_out2nd[2].v2 = s->row_out2nd[2].v3;
347 s->row_out2nd[2].v3 =
348 s->row_out2nd[2].fac * s->row_out2nd[2].v2 - v1 + famp;
350 v1 = s->col_out2nd[3].v2;
351 s->col_out2nd[3].v2 = s->col_out2nd[3].v3;
352 s->col_out2nd[3].v3 =
353 s->col_out2nd[3].fac * s->col_out2nd[3].v2 - v1 + famp;
355 v1 = s->row_out2nd[3].v2;
356 s->row_out2nd[3].v2 = s->row_out2nd[3].v3;
357 s->row_out2nd[3].v3 =
358 s->row_out2nd[3].fac * s->row_out2nd[3].v2 - v1 + famp;
360 /* Update fax tone */
362 s->fax_tone.v2 = s->fax_tone.v3;
363 s->fax_tone.v3 = s->fax_tone.fac * s->fax_tone.v2 - v1 + famp;
366 s->fax_tone2nd.v2 = s->fax_tone2nd.v3;
367 s->fax_tone2nd.v3 = s->fax_tone2nd.fac * s->fax_tone2nd.v2 - v1 + famp;
370 s->current_sample += (limit - sample);
371 if (s->current_sample < 102)
374 /* Detect the fax energy, too */
375 fax_energy = zap_goertzel_result (&s->fax_tone);
377 /* We are at the end of a DTMF detection block */
378 /* Find the peak row and the peak column */
379 row_energy[0] = zap_goertzel_result (&s->row_out[0]);
380 col_energy[0] = zap_goertzel_result (&s->col_out[0]);
382 for (best_row = best_col = 0, i = 1; i < 4; i++) {
383 row_energy[i] = zap_goertzel_result (&s->row_out[i]);
384 if (row_energy[i] > row_energy[best_row])
386 col_energy[i] = zap_goertzel_result (&s->col_out[i]);
387 if (col_energy[i] > col_energy[best_col])
391 /* Basic signal level test and the twist test */
392 if (row_energy[best_row] >= DTMF_THRESHOLD
394 col_energy[best_col] >= DTMF_THRESHOLD
396 col_energy[best_col] < row_energy[best_row] * DTMF_REVERSE_TWIST
397 && col_energy[best_col] * DTMF_NORMAL_TWIST > row_energy[best_row]) {
398 /* Relative peak test */
399 for (i = 0; i < 4; i++) {
401 && col_energy[i] * DTMF_RELATIVE_PEAK_COL >
402 col_energy[best_col])
404 && row_energy[i] * DTMF_RELATIVE_PEAK_ROW >
405 row_energy[best_row])) {
409 /* ... and second harmonic test */
412 (row_energy[best_row] + col_energy[best_col]) > 42.0 * s->energy
414 zap_goertzel_result (&s->col_out2nd[best_col]) *
415 DTMF_2ND_HARMONIC_COL < col_energy[best_col]
416 && zap_goertzel_result (&s->row_out2nd[best_row]) *
417 DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
418 hit = dtmf_positions[(best_row << 2) + best_col];
419 /* Look for two successive similar results */
420 /* The logic in the next test is:
421 We need two successive identical clean detects, with
422 something different preceeding it. This can work with
423 back to back differing digits. More importantly, it
424 can work with nasty phones that give a very wobbly start
426 if (hit == s->hit3 && s->hit3 != s->hit2) {
428 s->digit_hits[(best_row << 2) + best_col]++;
429 s->detected_digits++;
430 if (s->current_digits < MAX_DTMF_DIGITS) {
431 s->digits[s->current_digits++] = hit;
432 s->digits[s->current_digits] = '\0';
439 if (!hit && (fax_energy >= FAX_THRESHOLD)
440 && (fax_energy > s->energy * 21.0)) {
441 fax_energy_2nd = zap_goertzel_result (&s->fax_tone2nd);
442 if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) {
444 printf ("Fax energy/Second Harmonic: %f/%f\n", fax_energy,
447 /* XXX Probably need better checking than just this the energy XXX */
450 } /* Don't reset fax hits counter */
452 if (s->fax_hits > 5) {
454 s->detected_digits++;
455 if (s->current_digits < MAX_DTMF_DIGITS) {
456 s->digits[s->current_digits++] = hit;
457 s->digits[s->current_digits] = '\0';
467 /* Reinitialise the detector for the next block */
468 for (i = 0; i < 4; i++) {
469 goertzel_init (&s->row_out[i], &dtmf_detect_row[i]);
470 goertzel_init (&s->col_out[i], &dtmf_detect_col[i]);
471 goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]);
472 goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]);
474 goertzel_init (&s->fax_tone, &fax_detect);
475 goertzel_init (&s->fax_tone2nd, &fax_detect_2nd);
477 s->current_sample = 0;
479 if ((!s->mhit) || (s->mhit != hit)) {
486 /*- End of function --------------------------------------------------------*/
489 zap_dtmf_get (dtmf_detect_state_t * s, char *buf, int max)
491 if (max > s->current_digits)
492 max = s->current_digits;
494 memcpy (buf, s->digits, max);
495 memmove (s->digits, s->digits + max, s->current_digits - max);
496 s->current_digits -= max;
502 /*- End of function --------------------------------------------------------*/
503 /*- End of file ------------------------------------------------------------*/