libteletone_detect.h File Reference

Tone Detection Routines. More...

#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.


Detailed Description

Tone Detection Routines.

This module is responsible for tone detection specifics

Definition in file libteletone_detect.h.


Define Documentation

#define BLOCK_LEN   102

Definition at line 134 of file libteletone_detect.h.

Referenced by teletone_dtmf_detect().

#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.


Enumeration Type Documentation

enum teletone_hit_type_t

Enumerator:
TT_HIT_NONE 
TT_HIT_BEGIN 
TT_HIT_MIDDLE 
TT_HIT_END 

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;


Function Documentation

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.

Parameters:
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
Returns:
true when DTMF was detected or false when it is not

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.

Parameters:
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

Parameters:
dtmf_detect_state the detection state object to check
buf the string buffer to write to
max the maximum length of buf
Returns:
the number of characters written to 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.

Parameters:
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.

Parameters:
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
Returns:
true when the tone was detected or false when it is not

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.

Parameters:
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 }


Generated on Wed May 16 04:00:07 2012 for FreeSWITCH API Documentation by  doxygen 1.4.7