#include <libteletone.h>
Include dependency graph for libteletone_detect.h:
This graph shows which files directly or indirectly include this file:
Go to the source code of this file.
Data Structures | |
| struct | teletone_goertzel_state_t |
| A continer for the elements of a Goertzel Algorithm (The names are from his formula). More... | |
| struct | teletone_dtmf_detect_state_t |
| A container for a DTMF detection state. More... | |
| struct | teletone_detection_descriptor_t |
| An abstraction to store the coefficient of a tone frequency. More... | |
| struct | teletone_multi_tone_t |
| A container for a single multi-tone detection TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present in a multi-tone representation. More... | |
Defines | |
| #define | FALSE 0 |
| #define | TRUE (!FALSE) |
| #define | DTMF_THRESHOLD 8.0e7 |
| #define | DTMF_NORMAL_TWIST 6.3 |
| #define | DTMF_REVERSE_TWIST 2.5 |
| #define | DTMF_RELATIVE_PEAK_ROW 6.3 |
| #define | DTMF_RELATIVE_PEAK_COL 6.3 |
| #define | DTMF_2ND_HARMONIC_ROW 2.5 |
| #define | DTMF_2ND_HARMONIC_COL 63.1 |
| #define | GRID_FACTOR 4 |
| #define | BLOCK_LEN 102 |
| #define | M_TWO_PI 2.0*M_PI |
Enumerations | |
| enum | teletone_hit_type_t { TT_HIT_NONE = 0, TT_HIT_BEGIN = 1, TT_HIT_MIDDLE = 2, TT_HIT_END = 3 } |
Functions | |
| void | teletone_multi_tone_init (teletone_multi_tone_t *mt, teletone_tone_map_t *map) |
| Initilize a multi-frequency tone detector. | |
| 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. | |
| void | teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate) |
| Initilize a DTMF detection state object. | |
| 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. | |
| 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 | |
| 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. | |
This module is responsible for tone detection specifics
Definition in file libteletone_detect.h.
| #define BLOCK_LEN 102 |
| #define DTMF_2ND_HARMONIC_COL 63.1 |
Definition at line 132 of file libteletone_detect.h.
| #define DTMF_2ND_HARMONIC_ROW 2.5 |
Definition at line 131 of file libteletone_detect.h.
| #define DTMF_NORMAL_TWIST 6.3 |
Definition at line 127 of file libteletone_detect.h.
| #define DTMF_RELATIVE_PEAK_COL 6.3 |
Definition at line 130 of file libteletone_detect.h.
| #define DTMF_RELATIVE_PEAK_ROW 6.3 |
Definition at line 129 of file libteletone_detect.h.
| #define DTMF_REVERSE_TWIST 2.5 |
Definition at line 128 of file libteletone_detect.h.
| #define DTMF_THRESHOLD 8.0e7 |
Definition at line 126 of file libteletone_detect.h.
| #define FALSE 0 |
Definition at line 108 of file libteletone_detect.h.
| #define GRID_FACTOR 4 |
Definition at line 133 of file libteletone_detect.h.
Referenced by teletone_dtmf_detect(), and teletone_dtmf_detect_init().
| #define M_TWO_PI 2.0*M_PI |
Definition at line 135 of file libteletone_detect.h.
Referenced by teletone_dtmf_detect_init(), and teletone_multi_tone_init().
| #define TRUE (!FALSE) |
Definition at line 110 of file libteletone_detect.h.
| enum teletone_hit_type_t |
Definition at line 137 of file libteletone_detect.h.
00137 { 00138 TT_HIT_NONE = 0, 00139 TT_HIT_BEGIN = 1, 00140 TT_HIT_MIDDLE = 2, 00141 TT_HIT_END = 3 00142 } teletone_hit_type_t;
| 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.
| dtmf_detect_state | the detection state object to check | |
| sample_buffer | an array aof 16 bit signed linear samples | |
| samples | the number of samples present in sample_buffer |
Definition at line 303 of file libteletone_detect.c.
References BLOCK_LEN, dtmf_detect_col, dtmf_detect_col_2nd, dtmf_detect_row, dtmf_detect_row_2nd, goertzel_init(), GRID_FACTOR, LOW_ENG, and TT_HIT_END.
Referenced by inband_dtmf_callback().
00306 { 00307 float row_energy[GRID_FACTOR]; 00308 float col_energy[GRID_FACTOR]; 00309 float famp; 00310 float v1; 00311 int i; 00312 int j; 00313 int sample; 00314 int best_row; 00315 int best_col; 00316 char hit; 00317 int limit; 00318 teletone_hit_type_t r = 0; 00319 00320 hit = 0; 00321 for (sample = 0; sample < samples; sample = limit) { 00322 /* BLOCK_LEN is optimised to meet the DTMF specs. */ 00323 if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) { 00324 limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample); 00325 } else { 00326 limit = samples; 00327 } 00328 00329 for (j = sample; j < limit; j++) { 00330 int x = 0; 00331 famp = sample_buffer[j]; 00332 00333 dtmf_detect_state->energy += famp*famp; 00334 00335 for(x = 0; x < GRID_FACTOR; x++) { 00336 v1 = dtmf_detect_state->row_out[x].v2; 00337 dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3; 00338 dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp); 00339 00340 v1 = dtmf_detect_state->col_out[x].v2; 00341 dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3; 00342 dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp); 00343 00344 v1 = dtmf_detect_state->col_out2nd[x].v2; 00345 dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3; 00346 dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp); 00347 00348 v1 = dtmf_detect_state->row_out2nd[x].v2; 00349 dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3; 00350 dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp); 00351 } 00352 00353 } 00354 00355 if (dtmf_detect_state->zc > 0) { 00356 if (dtmf_detect_state->energy < LOW_ENG && dtmf_detect_state->lenergy < LOW_ENG) { 00357 if (!--dtmf_detect_state->zc) { 00358 /* Reinitialise the detector for the next block */ 00359 dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0; 00360 for (i = 0; i < GRID_FACTOR; i++) { 00361 goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]); 00362 goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]); 00363 goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]); 00364 goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]); 00365 } 00366 dtmf_detect_state->dur -= samples; 00367 return TT_HIT_END; 00368 } 00369 } 00370 00371 dtmf_detect_state->dur += samples; 00372 dtmf_detect_state->lenergy = dtmf_detect_state->energy; 00373 dtmf_detect_state->energy = 0.0; 00374 dtmf_detect_state->current_sample = 0; 00375 return TT_HIT_MIDDLE; 00376 } else if (dtmf_detect_state->digit) { 00377 return TT_HIT_END; 00378 } 00379 00380 00381 dtmf_detect_state->current_sample += (limit - sample); 00382 if (dtmf_detect_state->current_sample < BLOCK_LEN) { 00383 continue; 00384 } 00385 /* We are at the end of a DTMF detection block */ 00386 /* Find the peak row and the peak column */ 00387 row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]); 00388 col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]); 00389 00390 for (best_row = best_col = 0, i = 1; i < GRID_FACTOR; i++) { 00391 row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]); 00392 if (row_energy[i] > row_energy[best_row]) { 00393 best_row = i; 00394 } 00395 col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]); 00396 if (col_energy[i] > col_energy[best_col]) { 00397 best_col = i; 00398 } 00399 } 00400 hit = 0; 00401 /* Basic signal level test and the twist test */ 00402 if (row_energy[best_row] >= DTMF_THRESHOLD && 00403 col_energy[best_col] >= DTMF_THRESHOLD && 00404 col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST && 00405 col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) { 00406 /* Relative peak test */ 00407 for (i = 0; i < GRID_FACTOR; i++) { 00408 if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) || 00409 (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) { 00410 break; 00411 } 00412 } 00413 /* ... and second harmonic test */ 00414 if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy && 00415 teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] && 00416 teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) { 00417 hit = dtmf_positions[(best_row << 2) + best_col]; 00418 /* Look for two successive similar results */ 00419 /* The logic in the next test is: 00420 We need two successive identical clean detects, with 00421 something different preceeding it. This can work with 00422 back to back differing digits. More importantly, it 00423 can work with nasty phones that give a very wobbly start 00424 to a digit. */ 00425 if (! r && hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) { 00426 dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++; 00427 dtmf_detect_state->detected_digits++; 00428 if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) { 00429 dtmf_detect_state->digit = hit; 00430 } else { 00431 dtmf_detect_state->lost_digits++; 00432 } 00433 00434 if (!dtmf_detect_state->zc) { 00435 dtmf_detect_state->zc = ZC; 00436 dtmf_detect_state->dur = 0; 00437 r = TT_HIT_BEGIN; 00438 break; 00439 } 00440 00441 } 00442 } 00443 } 00444 00445 dtmf_detect_state->hit1 = dtmf_detect_state->hit2; 00446 dtmf_detect_state->hit2 = dtmf_detect_state->hit3; 00447 dtmf_detect_state->hit3 = hit; 00448 00449 dtmf_detect_state->energy = 0.0; 00450 dtmf_detect_state->current_sample = 0; 00451 00452 } 00453 00454 return r; 00455 }
| void teletone_dtmf_detect_init | ( | teletone_dtmf_detect_state_t * | dtmf_detect_state, | |
| int | sample_rate | |||
| ) |
Initilize a DTMF detection state object.
| dtmf_detect_state | the DTMF detection state to initilize | |
| sample_rate | the desired sample rate |
Definition at line 139 of file libteletone_detect.c.
References dtmf_col, dtmf_detect_col, dtmf_detect_col_2nd, dtmf_detect_row, dtmf_detect_row_2nd, dtmf_row, teletone_detection_descriptor_t::fac, goertzel_init(), GRID_FACTOR, and M_TWO_PI.
Referenced by switch_ivr_inband_dtmf_session().
00140 { 00141 int i; 00142 float theta; 00143 00144 dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0; 00145 00146 for (i = 0; i < GRID_FACTOR; i++) { 00147 theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate)); 00148 dtmf_detect_row[i].fac = (float)(2.0*cos(theta)); 00149 00150 theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate)); 00151 dtmf_detect_col[i].fac = (float)(2.0*cos(theta)); 00152 00153 theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate)); 00154 dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta)); 00155 00156 theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate)); 00157 dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta)); 00158 00159 goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]); 00160 goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]); 00161 goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]); 00162 goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]); 00163 00164 dtmf_detect_state->energy = 0.0; 00165 } 00166 dtmf_detect_state->current_sample = 0; 00167 dtmf_detect_state->detected_digits = 0; 00168 dtmf_detect_state->lost_digits = 0; 00169 dtmf_detect_state->digit = 0; 00170 dtmf_detect_state->dur = 0; 00171 }
| 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
| dtmf_detect_state | the detection state object to check | |
| buf | the string buffer to write to | |
| max | the maximum length of buf |
Definition at line 458 of file libteletone_detect.c.
Referenced by inband_dtmf_callback().
00459 { 00460 if (!dtmf_detect_state->digit) { 00461 return 0; 00462 } 00463 00464 *buf = dtmf_detect_state->digit; 00465 00466 *dur = dtmf_detect_state->dur; 00467 00468 if (!dtmf_detect_state->zc) { 00469 dtmf_detect_state->dur = 0; 00470 dtmf_detect_state->digit = 0; 00471 } 00472 00473 return 1; 00474 }
| 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.
| goertzel_state | the goertzel state to step the samples through | |
| sample_buffer | an array aof 16 bit signed linear samples | |
| samples | the number of samples present in sample_buffer |
Definition at line 120 of file libteletone_detect.c.
00123 { 00124 int i; 00125 float v1; 00126 00127 for (i = 0; i < samples; i++) { 00128 v1 = goertzel_state->v2; 00129 goertzel_state->v2 = goertzel_state->v3; 00130 goertzel_state->v3 = (float)(goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]); 00131 } 00132 }
| 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.
| mt | the multi-frequency tone descriptor | |
| sample_buffer | an array aof 16 bit signed linear samples | |
| samples | the number of samples present in sample_buffer |
Definition at line 213 of file libteletone_detect.c.
References TELETONE_MAX_TONES.
00216 { 00217 int sample, limit = 0, j, x = 0; 00218 float v1, famp; 00219 float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0}; 00220 int gtest = 0, see_hit = 0; 00221 00222 for (sample = 0; sample >= 0 && sample < samples; sample = limit) { 00223 mt->total_samples++; 00224 00225 if ((samples - sample) >= (mt->min_samples - mt->current_sample)) { 00226 limit = sample + (mt->min_samples - mt->current_sample); 00227 } else { 00228 limit = samples; 00229 } 00230 if (limit < 0 || limit > samples) { 00231 limit = samples; 00232 } 00233 00234 for (j = sample; j < limit; j++) { 00235 famp = sample_buffer[j]; 00236 00237 mt->energy += famp*famp; 00238 00239 for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { 00240 v1 = mt->gs[x].v2; 00241 mt->gs[x].v2 = mt->gs[x].v3; 00242 mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp); 00243 00244 v1 = mt->gs2[x].v2; 00245 mt->gs2[x].v2 = mt->gs2[x].v3; 00246 mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp); 00247 } 00248 } 00249 00250 mt->current_sample += (limit - sample); 00251 if (mt->current_sample < mt->min_samples) { 00252 continue; 00253 } 00254 00255 eng_sum = 0; 00256 for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { 00257 eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x])); 00258 eng_sum += eng_all[x]; 00259 } 00260 00261 gtest = 0; 00262 for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { 00263 gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0; 00264 } 00265 00266 if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) { 00267 if(mt->negatives) { 00268 mt->negatives--; 00269 } 00270 mt->positives++; 00271 00272 if(mt->positives >= mt->positive_factor) { 00273 mt->hits++; 00274 } 00275 if (mt->hits >= mt->hit_factor) { 00276 see_hit++; 00277 mt->positives = mt->negatives = mt->hits = 0; 00278 } 00279 } else { 00280 mt->negatives++; 00281 if(mt->positives) { 00282 mt->positives--; 00283 } 00284 if(mt->negatives > mt->negative_factor) { 00285 mt->positives = mt->hits = 0; 00286 } 00287 } 00288 00289 /* Reinitialise the detector for the next block */ 00290 for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) { 00291 goertzel_init (&mt->gs[x], &mt->tdd[x]); 00292 goertzel_init (&mt->gs2[x], &mt->tdd[x]); 00293 } 00294 00295 mt->energy = 0.0; 00296 mt->current_sample = 0; 00297 } 00298 00299 return see_hit; 00300 }
| void teletone_multi_tone_init | ( | teletone_multi_tone_t * | mt, | |
| teletone_tone_map_t * | map | |||
| ) |
Initilize a multi-frequency tone detector.
| mt | the multi-frequency tone descriptor | |
| map | a representation of the multi-frequency tone |
Definition at line 173 of file libteletone_detect.c.
References goertzel_init(), M_TWO_PI, and TELETONE_MAX_TONES.
00174 { 00175 float theta = 0; 00176 int x = 0; 00177 00178 if (!mt->sample_rate) { 00179 mt->sample_rate = 8000; 00180 } 00181 00182 if (!mt->min_samples) { 00183 mt->min_samples = 102; 00184 } 00185 00186 mt->min_samples *= (mt->sample_rate / 8000); 00187 00188 if (!mt->positive_factor) { 00189 mt->positive_factor = 2; 00190 } 00191 00192 if(!mt->negative_factor) { 00193 mt->negative_factor = 10; 00194 } 00195 00196 if (!mt->hit_factor) { 00197 mt->hit_factor = 2; 00198 } 00199 00200 for(x = 0; x < TELETONE_MAX_TONES; x++) { 00201 if ((int) map->freqs[x] == 0) { 00202 break; 00203 } 00204 mt->tone_count++; 00205 theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate)); 00206 mt->tdd[x].fac = (float)(2.0 * cos(theta)); 00207 goertzel_init (&mt->gs[x], &mt->tdd[x]); 00208 goertzel_init (&mt->gs2[x], &mt->tdd[x]); 00209 } 00210 00211 }
1.4.7