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
105 static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
106 static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];
107 static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR];
108 static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR];
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
goertzel_init(teletone_goertzel_state_t * goertzel_state,teletone_detection_descriptor_t * tdesc)115 static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc) {
116 goertzel_state->v2 = goertzel_state->v3 = 0.0;
117 goertzel_state->fac = tdesc->fac;
118 }
119
teletone_goertzel_update(teletone_goertzel_state_t * goertzel_state,int16_t sample_buffer[],int samples)120 TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
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
teletone_dtmf_detect_init(teletone_dtmf_detect_state_t * dtmf_detect_state,int sample_rate)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
teletone_multi_tone_init(teletone_multi_tone_t * mt,teletone_tone_map_t * map)177 TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
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
teletone_multi_tone_detect(teletone_multi_tone_t * mt,int16_t sample_buffer[],int samples)217 TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
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
teletone_dtmf_detect(teletone_dtmf_detect_state_t * dtmf_detect_state,int16_t sample_buffer[],int samples)307 TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
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
teletone_dtmf_get(teletone_dtmf_detect_state_t * dtmf_detect_state,char * buf,unsigned int * dur)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 */
489