| 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 | */ |