RTS API Documentation  1.10.11
libteletone_detect.c
Go to the documentation of this file.
1 /*
2  * libteletone
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is tone_detect.c - General telephony tone detection, and specific detection of DTMF.
18  *
19  *
20  * The Initial Developer of the Original Code is
21  * Stephen Underwood <steveu@coppice.org>
22  * Portions created by the Initial Developer are Copyright (C)
23  * the Initial Developer. All Rights Reserved.
24  *
25  * Contributor(s):
26  *
27  * The the original interface designed by Steve Underwood was preserved to retain
28  *the optimizations when considering DTMF tones though the names were changed in the interest
29  * of namespace.
30  *
31  * Much less efficient expansion interface was added to allow for the detection of
32  * a single arbitrary tone combination which may also exceed 2 simultaneous tones.
33  * (controlled by compile time constant TELETONE_MAX_TONES)
34  *
35  * Copyright (C) 2006 Anthony Minessale II <anthm@freeswitch.org>
36  *
37  *
38  * libteletone_detect.c Tone Detection Code
39  *
40  *
41  *********************************************************************************
42  *
43  * Derived from tone_detect.c - General telephony tone detection, and specific
44  * detection of DTMF.
45  *
46  * Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
47  *
48  * Despite my general liking of the GPL, I place this code in the
49  * public domain for the benefit of all mankind - even the slimy
50  * ones who might try to proprietize my work and use it to my
51  * detriment.
52  *
53  *
54  * Exception:
55  * The author hereby grants the use of this source code under the
56  * following license if and only if the source code is distributed
57  * as part of the OpenZAP or FreeTDM library. Any use or distribution of this
58  * source code outside the scope of the OpenZAP or FreeTDM library will nullify the
59  * following license and reinact the MPL 1.1 as stated above.
60  *
61  * Copyright (c) 2007, Anthony Minessale II
62  * All rights reserved.
63  *
64  * Redistribution and use in source and binary forms, with or without
65  * modification, are permitted provided that the following conditions
66  * are met:
67  *
68  * * Redistributions of source code must retain the above copyright
69  * notice, this list of conditions and the following disclaimer.
70  *
71  * * Redistributions in binary form must reproduce the above copyright
72  * notice, this list of conditions and the following disclaimer in the
73  * documentation and/or other materials provided with the distribution.
74  *
75  * * Neither the name of the original author; nor the names of any contributors
76  * may be used to endorse or promote products derived from this software
77  * without specific prior written permission.
78  *
79  *
80  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
81  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
82  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
83  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
84  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
85  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
86  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
87  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
88  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
89  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
90  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91  */
92 
93 #include <libteletone_detect.h>
94 
95 #ifndef _MSC_VER
96 #include <stdint.h>
97 #endif
98 #include <string.h>
99 #include <stdio.h>
100 #include <time.h>
101 #include <fcntl.h>
102 
103 #define LOW_ENG 10000000
104 #define ZC 2
109 
110 static float dtmf_row[] = {697.0f, 770.0f, 852.0f, 941.0f};
111 static float dtmf_col[] = {1209.0f, 1336.0f, 1477.0f, 1633.0f};
112 
113 static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
114 
116  goertzel_state->v2 = goertzel_state->v3 = 0.0;
117  goertzel_state->fac = tdesc->fac;
118 }
119 
121  int16_t sample_buffer[],
122  int samples)
123 {
124  int i;
125  float v1;
126 
127  for (i = 0; i < samples; i++) {
128  v1 = goertzel_state->v2;
129  goertzel_state->v2 = goertzel_state->v3;
130  goertzel_state->v3 = (float)(goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]);
131  }
132 }
133 #ifdef _MSC_VER
134 #pragma warning(disable:4244)
135 #endif
136 
137 #define teletone_goertzel_result(gs) (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))
138 
139 TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
140 {
141  int i;
142  float theta;
143 
144  if (!sample_rate) {
145  sample_rate = 8000;
146  }
147 
148  dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
149 
150  for (i = 0; i < GRID_FACTOR; i++) {
151  theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate));
152  dtmf_detect_row[i].fac = (float)(2.0*cos(theta));
153 
154  theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate));
155  dtmf_detect_col[i].fac = (float)(2.0*cos(theta));
156 
157  theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate));
158  dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta));
159 
160  theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate));
161  dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta));
162 
163  goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
164  goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
165  goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
166  goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
167 
168  dtmf_detect_state->energy = 0.0;
169  }
170  dtmf_detect_state->current_sample = 0;
171  dtmf_detect_state->detected_digits = 0;
172  dtmf_detect_state->lost_digits = 0;
173  dtmf_detect_state->digit = 0;
174  dtmf_detect_state->dur = 0;
175 }
176 
178 {
179  float theta = 0;
180  int x = 0;
181 
182  if (!mt->sample_rate) {
183  mt->sample_rate = 8000;
184  }
185 
186  if (!mt->min_samples) {
187  mt->min_samples = 102;
188  }
189 
190  mt->min_samples *= (mt->sample_rate / 8000);
191 
192  if (!mt->positive_factor) {
193  mt->positive_factor = 2;
194  }
195 
196  if(!mt->negative_factor) {
197  mt->negative_factor = 10;
198  }
199 
200  if (!mt->hit_factor) {
201  mt->hit_factor = 2;
202  }
203 
204  for(x = 0; x < TELETONE_MAX_TONES; x++) {
205  if ((int) map->freqs[x] == 0) {
206  break;
207  }
208  mt->tone_count++;
209  theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate));
210  mt->tdd[x].fac = (float)(2.0 * cos(theta));
211  goertzel_init (&mt->gs[x], &mt->tdd[x]);
212  goertzel_init (&mt->gs2[x], &mt->tdd[x]);
213  }
214 
215 }
216 
218  int16_t sample_buffer[],
219  int samples)
220 {
221  int sample, limit = 0, j, x = 0;
222  float v1, famp;
223  float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0};
224  int gtest = 0, see_hit = 0;
225 
226  for (sample = 0; sample >= 0 && sample < samples; sample = limit) {
227  mt->total_samples++;
228 
229  if ((samples - sample) >= (mt->min_samples - mt->current_sample)) {
230  limit = sample + (mt->min_samples - mt->current_sample);
231  } else {
232  limit = samples;
233  }
234  if (limit < 0 || limit > samples) {
235  limit = samples;
236  }
237 
238  for (j = sample; j < limit; j++) {
239  famp = sample_buffer[j];
240 
241  mt->energy += famp*famp;
242 
243  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
244  v1 = mt->gs[x].v2;
245  mt->gs[x].v2 = mt->gs[x].v3;
246  mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp);
247 
248  v1 = mt->gs2[x].v2;
249  mt->gs2[x].v2 = mt->gs2[x].v3;
250  mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp);
251  }
252  }
253 
254  mt->current_sample += (limit - sample);
255  if (mt->current_sample < mt->min_samples) {
256  continue;
257  }
258 
259  eng_sum = 0;
260  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
261  eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x]));
262  eng_sum += eng_all[x];
263  }
264 
265  gtest = 0;
266  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
267  gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0;
268  }
269 
270  if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) {
271  if(mt->negatives) {
272  mt->negatives--;
273  }
274  mt->positives++;
275 
276  if(mt->positives >= mt->positive_factor) {
277  mt->hits++;
278  }
279  if (mt->hits >= mt->hit_factor) {
280  see_hit++;
281  mt->positives = mt->negatives = mt->hits = 0;
282  }
283  } else {
284  mt->negatives++;
285  if(mt->positives) {
286  mt->positives--;
287  }
288  if(mt->negatives > mt->negative_factor) {
289  mt->positives = mt->hits = 0;
290  }
291  }
292 
293  /* Reinitialise the detector for the next block */
294  for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
295  goertzel_init (&mt->gs[x], &mt->tdd[x]);
296  goertzel_init (&mt->gs2[x], &mt->tdd[x]);
297  }
298 
299  mt->energy = 0.0;
300  mt->current_sample = 0;
301  }
302 
303  return see_hit;
304 }
305 
306 
308  int16_t sample_buffer[],
309  int samples)
310 {
311  float row_energy[GRID_FACTOR];
312  float col_energy[GRID_FACTOR];
313  float famp;
314  float v1;
315  int i;
316  int j;
317  int sample;
318  int best_row;
319  int best_col;
320  char hit = 0;
321  int limit;
322  teletone_hit_type_t r = 0;
323 
324  for (sample = 0; sample < samples; sample = limit) {
325  /* BLOCK_LEN is optimised to meet the DTMF specs. */
326  if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) {
327  limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample);
328  } else {
329  limit = samples;
330  }
331 
332  for (j = sample; j < limit; j++) {
333  int x = 0;
334  famp = sample_buffer[j];
335 
336  dtmf_detect_state->energy += famp*famp;
337 
338  for(x = 0; x < GRID_FACTOR; x++) {
339  v1 = dtmf_detect_state->row_out[x].v2;
340  dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3;
341  dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp);
342 
343  v1 = dtmf_detect_state->col_out[x].v2;
344  dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3;
345  dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp);
346 
347  v1 = dtmf_detect_state->col_out2nd[x].v2;
348  dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3;
349  dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp);
350 
351  v1 = dtmf_detect_state->row_out2nd[x].v2;
352  dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3;
353  dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp);
354  }
355 
356  }
357 
358  if (dtmf_detect_state->zc > 0) {
359  if (dtmf_detect_state->energy < LOW_ENG && dtmf_detect_state->lenergy < LOW_ENG) {
360  if (!--dtmf_detect_state->zc) {
361  /* Reinitialise the detector for the next block */
362  dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
363  for (i = 0; i < GRID_FACTOR; i++) {
364  goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
365  goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
366  goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
367  goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
368  }
369  dtmf_detect_state->dur -= samples;
370  return TT_HIT_END;
371  }
372  }
373 
374  dtmf_detect_state->dur += samples;
375  dtmf_detect_state->lenergy = dtmf_detect_state->energy;
376  dtmf_detect_state->energy = 0.0;
377  dtmf_detect_state->current_sample = 0;
378  return TT_HIT_MIDDLE;
379  } else if (dtmf_detect_state->digit) {
380  return TT_HIT_END;
381  }
382 
383 
384  dtmf_detect_state->current_sample += (limit - sample);
385  if (dtmf_detect_state->current_sample < BLOCK_LEN) {
386  continue;
387  }
388  /* We are at the end of a DTMF detection block */
389  /* Find the peak row and the peak column */
390  row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]);
391  col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]);
392 
393  for (best_row = best_col = 0, i = 1; i < GRID_FACTOR; i++) {
394  row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]);
395  if (row_energy[i] > row_energy[best_row]) {
396  best_row = i;
397  }
398  col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]);
399  if (col_energy[i] > col_energy[best_col]) {
400  best_col = i;
401  }
402  }
403  hit = 0;
404  /* Basic signal level test and the twist test */
405  if (row_energy[best_row] >= DTMF_THRESHOLD &&
406  col_energy[best_col] >= DTMF_THRESHOLD &&
407  col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
408  col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
409  /* Relative peak test */
410  for (i = 0; i < GRID_FACTOR; i++) {
411  if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
412  (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
413  break;
414  }
415  }
416  /* ... and second harmonic test */
417  if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy &&
418  teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] &&
419  teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
420  hit = dtmf_positions[(best_row << 2) + best_col];
421  /* Look for two successive similar results */
422  /* The logic in the next test is:
423  We need two successive identical clean detects, with
424  something different preceeding it. This can work with
425  back to back differing digits. More importantly, it
426  can work with nasty phones that give a very wobbly start
427  to a digit. */
428  if (! r && hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
429  dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
430  dtmf_detect_state->detected_digits++;
431  if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
432  dtmf_detect_state->digit = hit;
433  } else {
434  dtmf_detect_state->lost_digits++;
435  }
436 
437  if (!dtmf_detect_state->zc) {
438  dtmf_detect_state->zc = ZC;
439  dtmf_detect_state->dur = 0;
440  r = TT_HIT_BEGIN;
441  break;
442  }
443 
444  }
445  }
446  }
447 
448  dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
449  dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
450  dtmf_detect_state->hit3 = hit;
451 
452  dtmf_detect_state->energy = 0.0;
453  dtmf_detect_state->current_sample = 0;
454 
455  }
456 
457  return r;
458 }
459 
460 
461 TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur)
462 {
463  if (!dtmf_detect_state->digit) {
464  return 0;
465  }
466 
467  *buf = dtmf_detect_state->digit;
468 
469  *dur = dtmf_detect_state->dur;
470 
471  if (!dtmf_detect_state->zc) {
472  dtmf_detect_state->dur = 0;
473  dtmf_detect_state->digit = 0;
474  }
475 
476  return 1;
477 }
478 
479 /* For Emacs:
480  * Local Variables:
481  * mode:c
482  * indent-tabs-mode:t
483  * tab-width:4
484  * c-basic-offset:4
485  * End:
486  * For VIM:
487  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
488  */
static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR]
#define DTMF_THRESHOLD
teletone_goertzel_state_t row_out[GRID_FACTOR]
#define TELETONE_MAX_TONES
Definition: libteletone.h:81
A container for a single multi-tone detection TELETONE_MAX_TONES dictates the maximum simultaneous to...
#define ZC
#define LOW_ENG
An abstraction to store a tone mapping.
Definition: libteletone.h:93
teletone_hit_type_t
Tone Detection Routines.
#define GRID_FACTOR
static float dtmf_col[]
A container for a DTMF detection state.
teletone_goertzel_state_t gs[TELETONE_MAX_TONES]
A continer for the elements of a Goertzel Algorithm (The names are from his formula) ...
#define TELETONE_API(type)
Definition: libteletone.h:133
#define DTMF_RELATIVE_PEAK_COL
teletone_goertzel_state_t row_out2nd[GRID_FACTOR]
void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
Initilize a multi-frequency tone detector.
static float dtmf_row[]
teletone_goertzel_state_t col_out2nd[GRID_FACTOR]
#define BLOCK_LEN
#define TELETONE_MAX_DTMF_DIGITS
Definition: libteletone.h:80
static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR]
switch_byte_t switch_byte_t * buf
teletone_process_t freqs[TELETONE_MAX_TONES]
Definition: libteletone.h:95
teletone_hit_type_t teletone_dtmf_detect(teletone_dtmf_detect_state_t *dtmf_detect_state, int16_t sample_buffer[], int samples)
Check a sample buffer for the presence of DTMF digits.
teletone_goertzel_state_t gs2[TELETONE_MAX_TONES]
#define M_TWO_PI
static char dtmf_positions[]
int teletone_dtmf_get(teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur)
retrieve any collected digits into a string buffer
#define DTMF_RELATIVE_PEAK_ROW
#define DTMF_NORMAL_TWIST
int teletone_multi_tone_detect(teletone_multi_tone_t *mt, int16_t sample_buffer[], int samples)
Check a sample buffer for the presence of the mulit-frequency tone described by mt.
An abstraction to store the coefficient of a tone frequency.
#define teletone_goertzel_result(gs)
static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR]
static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc)
#define DTMF_2ND_HARMONIC_COL
static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR]
teletone_goertzel_state_t col_out[GRID_FACTOR]
#define DTMF_2ND_HARMONIC_ROW
#define DTMF_REVERSE_TWIST
void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state, int16_t sample_buffer[], int samples)
Step through the Goertzel Algorithm for each sample in a buffer.
teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES]
void teletone_dtmf_detect_init(teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
Initilize a DTMF detection state object.