File: | libs/libteletone/src/libteletone_detect.c |
Location: | line 324, column 2 |
Description: | Value stored to 'hit' is never read |
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_ENG10000000 10000000 |
104 | #define ZC2 2 |
105 | static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR4]; |
106 | static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR4]; |
107 | static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR4]; |
108 | static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR4]; |
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 | |
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 | |
120 | TELETONE_API(void)__attribute__((visibility("default"))) 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)) (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac)) |
138 | |
139 | TELETONE_API(void)__attribute__((visibility("default"))) 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_FACTOR4; i++) { |
151 | theta = (float)(M_TWO_PI2.0*3.14159265358979323846*(dtmf_row[i]/(float)sample_rate)); |
152 | dtmf_detect_row[i].fac = (float)(2.0*cos(theta)); |
153 | |
154 | theta = (float)(M_TWO_PI2.0*3.14159265358979323846*(dtmf_col[i]/(float)sample_rate)); |
155 | dtmf_detect_col[i].fac = (float)(2.0*cos(theta)); |
156 | |
157 | theta = (float)(M_TWO_PI2.0*3.14159265358979323846*(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_PI2.0*3.14159265358979323846*(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 | |
177 | TELETONE_API(void)__attribute__((visibility("default"))) 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_TONES18; x++) { |
205 | if ((int) map->freqs[x] == 0) { |
206 | break; |
207 | } |
208 | mt->tone_count++; |
209 | theta = (float)(M_TWO_PI2.0*3.14159265358979323846*(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 | |
217 | TELETONE_API(int)__attribute__((visibility("default"))) 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_TONES18] = {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_TONES18 && 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_TONES18 && x < mt->tone_count; x++) { |
261 | eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x])(double)(((&mt->gs[x])->v3 * (&mt->gs[x])-> v3 + (&mt->gs[x])->v2 * (&mt->gs[x])->v2 - (&mt->gs[x])->v2 * (&mt->gs[x])->v3 * (& mt->gs[x])->fac))); |
262 | eng_sum += eng_all[x]; |
263 | } |
264 | |
265 | gtest = 0; |
266 | for(x = 0; x < TELETONE_MAX_TONES18 && x < mt->tone_count; x++) { |
267 | gtest += teletone_goertzel_result (&mt->gs2[x])(double)(((&mt->gs2[x])->v3 * (&mt->gs2[x])-> v3 + (&mt->gs2[x])->v2 * (&mt->gs2[x])->v2 - (&mt->gs2[x])->v2 * (&mt->gs2[x])->v3 * (&mt->gs2[x])->fac)) < 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_TONES18 && 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 | |
307 | TELETONE_API(teletone_hit_type_t)__attribute__((visibility("default"))) 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_FACTOR4]; |
312 | float col_energy[GRID_FACTOR4]; |
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; |
321 | int limit; |
322 | teletone_hit_type_t r = 0; |
323 | |
324 | hit = 0; |
Value stored to 'hit' is never read | |
325 | for (sample = 0; sample < samples; sample = limit) { |
326 | /* BLOCK_LEN is optimised to meet the DTMF specs. */ |
327 | if ((samples - sample) >= (BLOCK_LEN102 - dtmf_detect_state->current_sample)) { |
328 | limit = sample + (BLOCK_LEN102 - dtmf_detect_state->current_sample); |
329 | } else { |
330 | limit = samples; |
331 | } |
332 | |
333 | for (j = sample; j < limit; j++) { |
334 | int x = 0; |
335 | famp = sample_buffer[j]; |
336 | |
337 | dtmf_detect_state->energy += famp*famp; |
338 | |
339 | for(x = 0; x < GRID_FACTOR4; x++) { |
340 | v1 = dtmf_detect_state->row_out[x].v2; |
341 | dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3; |
342 | dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp); |
343 | |
344 | v1 = dtmf_detect_state->col_out[x].v2; |
345 | dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3; |
346 | dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp); |
347 | |
348 | v1 = dtmf_detect_state->col_out2nd[x].v2; |
349 | dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3; |
350 | dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp); |
351 | |
352 | v1 = dtmf_detect_state->row_out2nd[x].v2; |
353 | dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3; |
354 | dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp); |
355 | } |
356 | |
357 | } |
358 | |
359 | if (dtmf_detect_state->zc > 0) { |
360 | if (dtmf_detect_state->energy < LOW_ENG10000000 && dtmf_detect_state->lenergy < LOW_ENG10000000) { |
361 | if (!--dtmf_detect_state->zc) { |
362 | /* Reinitialise the detector for the next block */ |
363 | dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0; |
364 | for (i = 0; i < GRID_FACTOR4; i++) { |
365 | goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]); |
366 | goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]); |
367 | goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]); |
368 | goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]); |
369 | } |
370 | dtmf_detect_state->dur -= samples; |
371 | return TT_HIT_END; |
372 | } |
373 | } |
374 | |
375 | dtmf_detect_state->dur += samples; |
376 | dtmf_detect_state->lenergy = dtmf_detect_state->energy; |
377 | dtmf_detect_state->energy = 0.0; |
378 | dtmf_detect_state->current_sample = 0; |
379 | return TT_HIT_MIDDLE; |
380 | } else if (dtmf_detect_state->digit) { |
381 | return TT_HIT_END; |
382 | } |
383 | |
384 | |
385 | dtmf_detect_state->current_sample += (limit - sample); |
386 | if (dtmf_detect_state->current_sample < BLOCK_LEN102) { |
387 | continue; |
388 | } |
389 | /* We are at the end of a DTMF detection block */ |
390 | /* Find the peak row and the peak column */ |
391 | row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0])(double)(((&dtmf_detect_state->row_out[0])->v3 * (& dtmf_detect_state->row_out[0])->v3 + (&dtmf_detect_state ->row_out[0])->v2 * (&dtmf_detect_state->row_out [0])->v2 - (&dtmf_detect_state->row_out[0])->v2 * (&dtmf_detect_state->row_out[0])->v3 * (&dtmf_detect_state ->row_out[0])->fac)); |
392 | col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0])(double)(((&dtmf_detect_state->col_out[0])->v3 * (& dtmf_detect_state->col_out[0])->v3 + (&dtmf_detect_state ->col_out[0])->v2 * (&dtmf_detect_state->col_out [0])->v2 - (&dtmf_detect_state->col_out[0])->v2 * (&dtmf_detect_state->col_out[0])->v3 * (&dtmf_detect_state ->col_out[0])->fac)); |
393 | |
394 | for (best_row = best_col = 0, i = 1; i < GRID_FACTOR4; i++) { |
395 | row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i])(double)(((&dtmf_detect_state->row_out[i])->v3 * (& dtmf_detect_state->row_out[i])->v3 + (&dtmf_detect_state ->row_out[i])->v2 * (&dtmf_detect_state->row_out [i])->v2 - (&dtmf_detect_state->row_out[i])->v2 * (&dtmf_detect_state->row_out[i])->v3 * (&dtmf_detect_state ->row_out[i])->fac)); |
396 | if (row_energy[i] > row_energy[best_row]) { |
397 | best_row = i; |
398 | } |
399 | col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i])(double)(((&dtmf_detect_state->col_out[i])->v3 * (& dtmf_detect_state->col_out[i])->v3 + (&dtmf_detect_state ->col_out[i])->v2 * (&dtmf_detect_state->col_out [i])->v2 - (&dtmf_detect_state->col_out[i])->v2 * (&dtmf_detect_state->col_out[i])->v3 * (&dtmf_detect_state ->col_out[i])->fac)); |
400 | if (col_energy[i] > col_energy[best_col]) { |
401 | best_col = i; |
402 | } |
403 | } |
404 | hit = 0; |
405 | /* Basic signal level test and the twist test */ |
406 | if (row_energy[best_row] >= DTMF_THRESHOLD8.0e7 && |
407 | col_energy[best_col] >= DTMF_THRESHOLD8.0e7 && |
408 | col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST2.5 && |
409 | col_energy[best_col]*DTMF_NORMAL_TWIST6.3 > row_energy[best_row]) { |
410 | /* Relative peak test */ |
411 | for (i = 0; i < GRID_FACTOR4; i++) { |
412 | if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL6.3 > col_energy[best_col]) || |
413 | (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW6.3 > row_energy[best_row])) { |
414 | break; |
415 | } |
416 | } |
417 | /* ... and second harmonic test */ |
418 | if (i >= GRID_FACTOR4 && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy && |
419 | teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])(double)(((&dtmf_detect_state->col_out2nd[best_col])-> v3 * (&dtmf_detect_state->col_out2nd[best_col])->v3 + (&dtmf_detect_state->col_out2nd[best_col])->v2 * (&dtmf_detect_state->col_out2nd[best_col])->v2 - ( &dtmf_detect_state->col_out2nd[best_col])->v2 * (& dtmf_detect_state->col_out2nd[best_col])->v3 * (&dtmf_detect_state ->col_out2nd[best_col])->fac))*DTMF_2ND_HARMONIC_COL63.1 < col_energy[best_col] && |
420 | teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])(double)(((&dtmf_detect_state->row_out2nd[best_row])-> v3 * (&dtmf_detect_state->row_out2nd[best_row])->v3 + (&dtmf_detect_state->row_out2nd[best_row])->v2 * (&dtmf_detect_state->row_out2nd[best_row])->v2 - ( &dtmf_detect_state->row_out2nd[best_row])->v2 * (& dtmf_detect_state->row_out2nd[best_row])->v3 * (&dtmf_detect_state ->row_out2nd[best_row])->fac))*DTMF_2ND_HARMONIC_ROW2.5 < row_energy[best_row]) { |
421 | hit = dtmf_positions[(best_row << 2) + best_col]; |
422 | /* Look for two successive similar results */ |
423 | /* The logic in the next test is: |
424 | We need two successive identical clean detects, with |
425 | something different preceeding it. This can work with |
426 | back to back differing digits. More importantly, it |
427 | can work with nasty phones that give a very wobbly start |
428 | to a digit. */ |
429 | if (! r && hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) { |
430 | dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++; |
431 | dtmf_detect_state->detected_digits++; |
432 | if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS128) { |
433 | dtmf_detect_state->digit = hit; |
434 | } else { |
435 | dtmf_detect_state->lost_digits++; |
436 | } |
437 | |
438 | if (!dtmf_detect_state->zc) { |
439 | dtmf_detect_state->zc = ZC2; |
440 | dtmf_detect_state->dur = 0; |
441 | r = TT_HIT_BEGIN; |
442 | break; |
443 | } |
444 | |
445 | } |
446 | } |
447 | } |
448 | |
449 | dtmf_detect_state->hit1 = dtmf_detect_state->hit2; |
450 | dtmf_detect_state->hit2 = dtmf_detect_state->hit3; |
451 | dtmf_detect_state->hit3 = hit; |
452 | |
453 | dtmf_detect_state->energy = 0.0; |
454 | dtmf_detect_state->current_sample = 0; |
455 | |
456 | } |
457 | |
458 | return r; |
459 | } |
460 | |
461 | |
462 | TELETONE_API(int)__attribute__((visibility("default"))) int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur) |
463 | { |
464 | if (!dtmf_detect_state->digit) { |
465 | return 0; |
466 | } |
467 | |
468 | *buf = dtmf_detect_state->digit; |
469 | |
470 | *dur = dtmf_detect_state->dur; |
471 | |
472 | if (!dtmf_detect_state->zc) { |
473 | dtmf_detect_state->dur = 0; |
474 | dtmf_detect_state->digit = 0; |
475 | } |
476 | |
477 | return 1; |
478 | } |
479 | |
480 | /* For Emacs: |
481 | * Local Variables: |
482 | * mode:c |
483 | * indent-tabs-mode:t |
484 | * tab-width:4 |
485 | * c-basic-offset:4 |
486 | * End: |
487 | * For VIM: |
488 | * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: |
489 | */ |